最新

以太坊黑暗森林-抢跑(front running)

以太坊黑暗森林-抢跑(front running)

前言 鸽了很久之后的今天突然心血来潮,准备写一个系列:以太坊黑暗森林,它介绍以太坊生态上的各种奇思妙想和逆天的攻击方式,会从简单的、常见的攻击方式开始介绍。取这个名字是因为我接触以太坊不久后看的一篇文章 Ethereum is a Dark Forest ,让我想起了《三体》小说中刘慈欣描述的黑暗森林,以太坊是一个弱肉强食的、没有规则的世界,猎人们总是躲在背后监听所有的交易,一旦发现猎物,它们会把它的血给吸干。 开盘抢币 相信进入以太坊生态的韭菜们,一定有过在 uniswap 上买刚开盘新币的经历,新开盘的币,一般会上涨几倍甚至十几倍,越早买入则越能低价买入。你守着时间,等着项目方添加流动性后第一时间买入代币,但是你发现,无论你的手速多块,总是看到一开盘,价格已经飚了几倍,你骂骂咧咧,开始不断拉高 gas 费用,尝试继续买入,但是你眼睁睁的看着代币涨到十倍,自己的交易却一直失败,你开始怀疑项目方自己抢跑,怀疑项目方捣鬼:肯定是项目方吃相难看,用老鼠仓提前买了。另一些聪明人,研究了以太坊的基本技术,他们在 ethscan

By FatTiger
C#:IDisposable 和 析构函数

C#:IDisposable 和 析构函数

C# 中有两种释放资源的方式:实现 IDisposable 或使用析构函数。通常,必须在特定时间释放资源的场景中,我们实现 IDisposable,像这样: public class ExampleDispose : IDisposable { // 非托管资源 private IntPtr _handle; // 使用的其它托管资源 private readonly Stream _stream; private bool disposed = false; public ExampleDispose(Stream stream, IntPtr handle) { this._stream = stream; this._handle = handle; } public void Dispose() { if (disposed) { return; } disposed = t

By FatTiger
ThreadLocal引发的灾难

ThreadLocal引发的灾难

在 Java 里有个称之为线程本地变量的类型叫做 ThreadLocal,它与 ThreadLocal 之于 C# 中是一样的作用,可以在线程范围内设置变量,这个变量只会在当前线程可被访问,但是它们有一点不同的是,在 Java 中,当你设置好变量后,在线程使用完毕回到线程池之前,需要手动调用 ThreadLocal.remove() 方法去清除线程本地变量,否则变量随着线程回到线程池,并且在下次使用此线程时此变量继续存在,而在 C# 中,线程回到线程池时会自动清除本地变量,因此无需手动去清除。 我们的业务有这样一个场景:某个业务 UserService 类中,具有多个方法会频繁(甚至循环)调用一个获取用户标签的接口,具体原因是因为某些方法会进行递归,数据结构有个树状结构,因此,为了优化接口响应时间以及看起来不那么蠢,我使用 ThreadLocal 将用户标签接口的返回数据存储到当前线程,因为在单个请求中,多次调用此接口获取数据是不必要的,它看起来像这样: /** * 此静态变量ThreadLocal会为每个线程创建本地副本, 因此USER_TAGS_THREAD_

By FatTiger
我在币安智能链的日子-区块链基础

我在币安智能链的日子-区块链基础

区块和链 无论是比特币还是以太坊,都是具有一个个区块(称之为Block)的链式结构,学过<数据结构>的肯定明白链表,区块链就像一个链表,每个区块都存储上一个区块哈希。 链(称之为Chain),有非常多的链,他们的协议不同,技术也不尽相同,比特币网络是一个链,以太坊网络是另一个链,每个链都有自己的目标(甚至目标只是为了圈钱),每个链也都有自己的代币,比特币网络的代币是比特币,每次交易都需要比特币作为手续费,以太坊网络代币是以太币,每次在以太坊网络的交易都需要以太币作为手续费。所以,链实际上作为基础设施,非常多的团队喜欢创建新的链,但是一个链光有网络光有代币不行,没有生态,很难成功。 币安智能链(Binance Smart Chain:BSC) 我的主要操作都是在BSC上,没有其它原因,只因为一个穷字。在BTC网络交易,需要BTC用作手续费,这个我可用不起,在以太坊(Ethereum)网络交易,需要以太币(ETH)作为用作手续费,按照以太币目前(

By FatTiger
All about ExecutionContext and SynchronizationContext

All about ExecutionContext and SynchronizationContext

前言 这篇文章深入探讨了ExecutionContext和SynchronizationContext, 这是大部分开发人员都不需要了解的 .NET 高级领域. SynchronizationContext 我最早关于 SynchronizationContext 了解可能是在 WindowsForm 程序, 当我错误的在其它线程去更新 UI 控件时, 总会出现一个异常 Cross-thread operation not valid: Control accessed from a thread other than the thread it was created on 翻译过来即 跨线程操作无效:控件从创建它的线程以外的线程访问, 例如这个代码片段: private void button_Click(object sender, EventArgs e) { Task.Run(() => { //异常: 跨线程操作无效:控件从创建它的线程以外的线程访问

By FatTiger
Create React App(CRA)本地开发配置代理

Create React App(CRA)本地开发配置代理

前言 现代的前端开发,通常使用前后端分离的形式,前端专注页面,数据来源于后端接口。这种开发方式使得职责更加明确且项目文件也更加的清晰起来,但是在本地开发过程中则有一点小问题:我如何调用后端接口?如果直接调用服务器上的接口,或者本地启动后端项目,由于端口不同,都会出现跨域问题,而服务端配置允许跨域也不太合适,那么,能否通过设置代理来绕过浏览器限制呢? 声明 * Create React App以下简称CRA。 根据CRA文档,本地配置代理有两种方式: * 在package.json中新增属性proxy来设置目标地址。 * 通过http-proxy-middleware模块手动配置灵活的代理。 两种方式各有好处,通过在package.json文件增加proxy属性的方式非常简单,一行代码即可解决代理问题,但是这个proxy地址没法根据配置进行动态切换,且package.json文件是需要提交到代码仓库的,如果每个人都有不同的目标地址,则package.json一定被大家改来改去且发生合并冲突。另外一种方式则是通过手动配置http-proxy-middleware的方式,根

By FatTiger
使用VS Code进行Java开发

使用VS Code进行Java开发

前言 目前有很多小伙伴在用IntelliJ IDEA,这东西啥都好,就是贵,再一个就是占用内存很高,打开它也觉得非常的重。如果跟我一样有上面几个问题困扰,可以尝试使用VS Code。它插件众多,能DIY的地方也很多,特别是对于喜欢折腾的人来说,更是福音。当然如果不喜欢折腾想上手即用也可,全家桶插件非常方便。 支持的Java版本范围 为什么要单开一段说这件事,原因在于目前不少人认为VS Code只能支持Java 11及以上版本,这对于很多使用Java 1.8开发的同学来说简直劝退。但这其实是个误解,目前VS Code是能支持Java 1.5 - Java 15(截止本文发布时的最新版本),基本能满足目前90%以上的Java使用者了(太老的Java版本这边移步Eclipse),至于说只能支持Java 11这件事,是指插件的运行环境需要安装最低Java 11的SDK,也就是说你如果想用VS Code开发Java程序必须要在本地安装Java 11 SDK才能够使用此插件。具体情况移步: * Language Support for Java(TM)

By FatTiger
real mode protected mode and segmentation

real mode protected mode and segmentation

前言 在操作系统启动时,会先进入实模式(Real Mode),然后再转换为保护模式(Protected Mode),为什么需要这么做?两种模式的寻址方式有何不同?本文通过Intel 8086和Intel 80286分段寻址的不同来解释这两种模式的区别。 Intel 8086 8086被设计为完全的16位处理器,所有的内部寄存器、内部及外部数据总线都是16位宽,不过它具有20位宽的外部地址总线,这意味着它能够寻址2^20=1,048,576个地址,也就是最大能够支持1MB的寻址空间。这里可能会有疑问,刚才不是说8086是16位处理器吗?怎么能够进行20位地址总线寻址呢?这是由于8086处理器支持分段机制(Segmentation),它能够通过16 * Segment + Offset的方式进行寻址,例如Segment为0xf000,Offset为0xfff0,则进行如下转换: 16 * 0xf000 + 0xfff0 = 0xf0000 + 0xfff0 = 0xffff0 Segment为16位的基地址被存储在段寄存器(Segment Registers),O

By FatTiger

MIT CS6.828-Lab 1: Booting a PC

Lab 1: Booting a PC 基础概念 处理器架构 * i386 i686 x86是同一套指令集,86指这一系列CPU,x则表示i3/i6是不同的处理器型号,x86即泛指i386 i686等,都是32位处理器 * x86_64则为x86的衍生,为x86的64位版本,另外amd64也是一样的东西 * aarch32指armv7处理器架构下的指令集 * aarch64指armv8处理器架构下的指令集 AT&T格式汇编指令介绍 * 基本格式command source, destination,AT&T将源操作数放在第一位,目标操作数放在第二位,这与Intel格式的汇编语法是相反的 * 在寄存器操作数前用%标记,立即操作数前用$标记 * testb/testw/testl s d * test表示对两个操作数进行AND操作,其结果如果为0则将CPU中的ZF标志寄存器设置为1否则清除ZF寄存器的值,即设置为0 * b/w/l为助记符,b用于8位字节值,w用于16位字值,

By FatTiger
C# Async/Await 最佳实践

C# Async/Await 最佳实践

异步不是魔法,也不需要另一个线程等待 很多不理解异步的人总觉得异步是一种魔法操作,认为使用了异步能够增加程序的处理速度。这是一个常见的误解,异步不是魔法,无法加速你程序的运行速度,如果你的方法以前需要一秒钟返回结果使用异步后一样需要一秒钟返回结果,这些人会觉得奇怪,说好的异步会使程序性能提升呢?另一种常见的误解则是,异步也需要线程来执行,只不过使用了线程池线程,会有一个后台线程继续等待异步结果,但事实总是出乎意料:没有额外线程在等待。 让我们一步步解剖异步的线程无需等待到底是什么,假设我们现在需要对文件进行读取: async Task MyMethodAsync() { //异步读取文件 var text = await System.IO.File.ReadAllTextAsync(@"file.text"); //输出文件内容到控制台 System.Console.WriteLine(text); } 当线程执行到 await System.IO.File.ReadAllTextAsync(@"file.text")时,线程会调用操作系统一

By FatTiger
SSH添加了公钥总是需要询问密码

SSH添加了公钥总是需要询问密码

针对此类问题首先可以在客户端使用ssh -vT [email protected]来展示更详细的ssh过程,但是这通常无法得到更多有用的信息,此时可以尝试在目标机器上tail -f /var/log/secure来查看ssh的日志信息。 # ssh -vT [email protected] OpenSSH_for_Windows_7.7p1, LibreSSL 2.6.5 debug1: Reading configuration data C:\\Users\\Fat Tiger/.ssh/config debug1: Connecting to git.jackyzhong.com [47.102.116.218] port 22. debug1: Connection established.

By FatTiger
Gitlab 无法使用HTTPS进行克隆:The requested URL returned error: 502

Gitlab

Gitlab 无法使用HTTPS进行克隆:The requested URL returned error: 502

问题 使用Gitlab-Runner进行Clone存储库时提示: fatal: unable to access 'http://gitlab-ci-token:xxxxxx@gitlab_domain/project/repo.git/': The requested URL returned error: 502 并且无法使用git clone https://domain/project.git,也返回相同错误。 TL;DR 将Nginx下Gitlab站点配置中passenger_user和passenger_group的用户和用户组设置为具有/var/opt/gitlab/gitlab-workhorse/socket权限的用户和用户组,或者将 /var/opt/gitlab/gitlab-workhorse/socket赋予正确的所有者和访问权限。 原因 我是通过外置Nginx对Gitlab进行反向代理时才出现的问题。查看Gitlab访问日志: unix://var/

By FatTiger
ASP.NET Core 中Session的分布式存储

.NET

ASP.NET Core 中Session的分布式存储

前言 在ASP.NET Core中的Session该如何存储?本文介绍了Session信息在单个应用实例和多个应用实例中的不同存储方式,以及ASP.NET Core在Session数据安全方面做的一些努力。 TL;DR 在ASP.NET Core中使用分布式缓存存储会话时,仅仅将Session进行分布式存储还不够,由于ASP.NET Core的数据安全保护机制,还需要将Data Protection所使用的加密密钥也进行分布式存储,这样才能正确解密Cookies: public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } public void ConfigureServices(IServiceCollection services) { //将数据保护的秘

By FatTiger
ASP.NET Core 3.0 Razor 修改页面刷新无效

.NET

ASP.NET Core 3.0 Razor 修改页面刷新无效

问题 在ASP.NET Core 3.0中,对Razor页面修改刷新无法展示修改后的内容。 原因 这是由于在ASP.NET Core 3.0中,对Razor视图和Razor页面的运行时编译的支持被移到了单独的程序包中,没有默认启用Razor运行时编译。 解决方案 * 安装Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation 在Startup中启用Razor运行时编译: public class Startup { public Startup(IConfiguration configuration, IWebHostEnvironment env) { Configuration = configuration; Env = env; } public IWebHostEnvironment Env { get; set; } public IConfiguration Configuration { get; } public voi

By FatTiger
单精度浮点数(Float)与双精度浮点数(Double)

单精度浮点数(Float)与双精度浮点数(Double)

前言 对于十进制的整数使用二进制表示很简单,但是对于十进制小数如何使用二进制进行存储?十进制的小数又何如使用二进制小数表示?此文章描述了如何将十进制小数转换为二进制小数以及浮点数再内存中时如何进行存储。 二进制小数 在计算机中,无论什么数据,最终存储都为二进制,对于整数部分很容易表示,但是对于非整数则比较困难。例如,十进制数0.125可表示为二进制0.001,怎么得来的?简单的计算可以用0.125不断乘2,结果小于1将二进制位记为0,结果大于1时将二进制位记为1: 0.125 * 2 = 0.25 二进制位记作 0 0.25 * 2 = 0.5 二进制位记作 0 0.5 * 2 = 1 二进制位记作 1 所以得出结果为0.001 另外可以把可以把十进制数0.125看做1/2/2/2 = 1*2^-3,

By FatTiger
char vs varchar vs nvarchar

MSSQL Server

char vs varchar vs nvarchar

MSSQL Server char(n) vs varchar(n) * n为字节单位而非字符单位,这是有区别的,在单字节编码字符集存储时,n的大小即为字符长度,当所存储的字符无法使用单字节编码字符集表示时则会采用双字节字符集存储,n的大小则是字符的2倍 * char会存储固定字节长度的字符,如果定义char(4)则插入'ab'会被存储为'ab ',超出字节长度的字符串会被截断。实际存储大小总是4 bytes,另外插入'ab '后查询出的结果是会去除末尾空格为'ab' * varchar存储可变字节长度的字符,如果定义varchar(4)则插入'ab'即存储为'ab'而不会向char一样使用空格填充,在检索时也不会去除末尾空格。然而使用varchar(n)

By FatTiger

.NET

ThreadStaticAttribute vs ThreadLocal vs AsyncLocal

前言 在.NET程序里,使用static关键字修饰的变量存在于整个程序的生命周期,这使得它可以被多个线程同时访问,这种方式在某些情况下很好用,但是可能需要加锁来处理线程安全问题,在另一些情况下可能只想在线程内共享变量,多个线程之间的变量互相隔离,这就需要使用ThreadStaticAttribute丶ThreadLocal<T>和AsyncLocal<T> TL;DR 实现方式 跨线程 流向辅助线程 static ✔️ ✔️ AsyncLocal ❌ ✔️ ThreadLocal ❌ ❌ ThreadStaticAttribute ❌ ❌ 流向辅助线程 发生线程上下文切换时,能够保存数据并流向到下一个线程,注意,这是单向数据流,辅助线程上更改数据,并不会影响主线程数据(但是你可以通过引用类型来实现主线程数据的同时更改)。 * 线程上下文切换 * new Thread() * new Task() * Task.Run() * ThreadPool.QueueUserWorkItem() * await

By FatTiger
ASP.NET Core中I/O阻塞与线程池爬山

.NET

ASP.NET Core中I/O阻塞与线程池爬山

线程池爬山算法 * CLR的线程池具有最小线程数和最大线程数的限制,默认最小线程数为CPU的逻辑处理器数量,当同时使用的线程数超过最小线程数后,它以适中的速率(例如每秒1或2个)创建新的线程。这意味着当你的线程数超过最小线程数后,超出部分的线程创建请求则需要进行排队,且越后面的线程等待时间越长。 * CLR设计默认线程池数量与CPU逻辑处理器数量相同是有原因的,两个好处: * 线程数过多的情况下,CPU需要在多个线程间进行切换,这会导致额外的线程切换开销,线程数越多则CPU大部分时间都花在了切换线程上下文上。 * 如果某个方法是阻塞的,那么大量的请求进来会导致线程无限制的被创建,会瞬间消耗大量的内存。 Practice * 我们可以简单的创建一个NET Core Console程序进行验证 static void Main(string[] args) { var processThreads = 0; while (true) { Task.Factory.StartNew(() => {

By FatTiger
在CentOS 8 中使用 Docker 无法访问网络

Linux

在CentOS 8 中使用 Docker 无法访问网络

在CentOS 8上使用Docker时,Docker Build无法还原依赖,错误提示failure resolving xxxxxx,看起来像DNS失效无法还原出域名映射的地址。联想到在CentOS 8上安装Docker时也因为网络问题无法安装,怀疑是firewalld的原因,于是systemctl start firewalld.service停止firewalld,再service docker restart重启Docker服务后,果然就可以还原依赖了。但是机器没有防火墙简直就是裸奔,搜索后发现用firewall-cmd --zone=public --add-masquerade --permanent命令使masquerade允许通过firewall,再firewall-cmd --reload && service docker restart后,一切恢复正常. Quote * How to Install Docker on CentOS 8 * No network connectivity to/from Docker CE container on

By FatTiger

.NET Framework

Globalization and localization in ASP.NET Framework

Globalization and Localization Globalization指将应用程序设计为支持多个语言和文化的过程,Localization则意为将已经Globalization的应用程序设置为特定区域输出的过程。例如将应用程序的输出字符和UI都使用资源文件进行配置,可输出多个不同语言则应用程序已经准备好全球化过程,而根据浏览器语言或者Cookie设置获取特定的区域语言则称之为本地化过程。 Best Practices 新建ASP.NET Framework应用程序后,新建App_GlobalResources文件夹并在下面新建三个资源文件: 其中,Resource.resx为基准资源文件,Resource.en-US则为en-US区域对应的资源文件,Resource.zh-CN则为zh-CN区域对应的资源文件,应当说明的是,所有资源文件的字符串Key应当与Resource.resx资源文件中的Key相一致,Value则为对应区域的本地化字符串。 接下来在Resource.resx中新增一个SYSTEM_NAME用来表示当前系统信息,相应的Resource.e

By FatTiger