FatTiger Blog

Thoughts, stories and ideas.

最新

以太坊黑暗森林-抢跑(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