我们知道以太坊是目前最大的公链,它是一个去中心化的数据库,与传统数据库有一个很大的区别是,以太坊的数据并没有一个主动写入的过程。
我们知道以太坊是目前最大的公链,它是一个去中心化的数据库,与传统数据库有一个很大的区别是,以太坊的数据并没有一个主动写入的过程。所谓数据上链,其实是用户发起一笔交易,并携带相关信息。这些相关信息可以是调用智能合约某些函数和相关参数。然后这笔交易会广播到全网节点,其他节点收到之后会将他保存到自己的内存池中(mempool,其实翻译成交易池更合适)。如果节点开启了挖矿功能,我们把它叫做矿工节点。矿工节点会根据内存池中所有交易的gasPrice从大到小排序,打包进区块。当然每一笔交易只能被一个矿工打包,这个通过共识决定。一旦发现某一笔交易已经上链,就将其从内存池中删除。
玩过DeFi的小伙伴可能遇到过这样的情况,当你要买入一个商品的时候,有人在你之前抢先成交了。其实这些都是机器人发起的交易。我们把这类机器人叫抢跑机器人,开发这些机器人的人叫 “科学家”。抢跑机器的基本原理就是通过监听内存池中的交易,分析交易内容,然后发起一笔gasPrice更高的交易,强行插队。上面我们说过矿工是根据gasPrice的大小来决定哪笔交易先打包的。
监听内存池需要一个全节点,可以自己部署,也可以使用第三方的节点。比如我们这里用 infura.io, 先去上面申请一个key,拿到接口地址。以太坊官方代码已经实现了go的客户端,直接使用即可。代码如下
package main
import (
"context"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/ethclient/gethclient"
"github.com/ethereum/go-ethereum/rpc"
"log"
"os"
"os/signal"
"syscall"
)
const (
url = "https://mainnet.infura.io/v3/b4c05366e4c14e8a8304f0690aeae0e8"
wss = "wss://mainnet.infura.io/ws/v3/b4c05366e4c14e8a8304f0690aeae0e8"
)
func watch() {
backend, err := ethclient.Dial(url)
if err != nil {
log.Printf("failed to dial: %v", err)
return
}
rpcCli, err := rpc.Dial(wss)
if err != nil {
log.Printf("failed to dial: %v", err)
return
}
gcli := gethclient.New(rpcCli)
txch := make(chan common.Hash, 100)
_, err = gcli.SubscribePendingTransactions(context.Background(), txch)
if err != nil {
log.Printf("failed to SubscribePendingTransactions: %v", err)
return
}
for {
select {
case txhash := <-txch:
tx, _, err := backend.TransactionByHash(context.Background(), txhash)
if err != nil {
continue
}
data, _ := tx.MarshalJSON()
log.Printf("tx: %v", string(data))
}
}
}
func main() {
go watch()
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
<-signalChan
}
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!