Ether.js+Web3modal基础使用
1.说明现在网站会提供很多种钱包,web3modal可以提供统一的provider,不需要你操心太多东西用ether.js而不是web3.js的原因是简单,爽2.安装npm i web3modal npm i ethers //另外还需要安装对应wallet的包,自行搜索就行 3.连接钱包// MM默认就有,无需显式加入 const providerOptions = { walletconnect: { package: walletconnectProvider, options: { infuraId: "", }, }, }; //构建Web3Modal对象 const web3Modal = new Web3Modal({ //缓存provider cacheProvider: true, providerOptions, }); //连接wallet async function connect() { try { const web3ModalProvider = await web3Modal.connect(); provider = new ethers.pr...
ETH源码学习(1)创建私有链
下载geth,创建genesis.json{ "config": { "chainId": 8888, //自行修改 "homesteadBlock": 0, "daoForkBlock": 0, "daoForkSupport": true, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, "ethash": {} }, "nonce": "0x42", "timestamp": "0x0", "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", "gasLimit": "0xffffffff", "difficulty": "0x700000",//难度,越大挖矿越慢 "alloc": { "093f59f1d91017d30d8c2caa78feb5beb0d2cfaf...
Go获取合约事件日志
func main() { client, err := ethclient.Dial("https://rinkeby-light.eth.linkpool.io/") if err != nil { log.Fatal(err) } //获取当前的最新区块 header, err := client.HeaderByNumber(context.Background(), nil) if err != nil { log.Fatal(err) } fmt.Println("最新区块", header.Number.String()) // 5671744 //开始查询日志,可以添加过滤条件,查询符合你想要的日志 query := ethereum.FilterQuery{ FromBlock: big.NewInt( 10570948), ToBlock: header.Number, Addresses: []common.Address{ common.HexToAddress("0x40490DF1cc631817D24BA324147c59821C8970BF"), ...
Ether.js+Web3modal基础使用
1.说明现在网站会提供很多种钱包,web3modal可以提供统一的provider,不需要你操心太多东西用ether.js而不是web3.js的原因是简单,爽2.安装npm i web3modal npm i ethers //另外还需要安装对应wallet的包,自行搜索就行 3.连接钱包// MM默认就有,无需显式加入 const providerOptions = { walletconnect: { package: walletconnectProvider, options: { infuraId: "", }, }, }; //构建Web3Modal对象 const web3Modal = new Web3Modal({ //缓存provider cacheProvider: true, providerOptions, }); //连接wallet async function connect() { try { const web3ModalProvider = await web3Modal.connect(); provider = new ethers.pr...
ETH源码学习(1)创建私有链
下载geth,创建genesis.json{ "config": { "chainId": 8888, //自行修改 "homesteadBlock": 0, "daoForkBlock": 0, "daoForkSupport": true, "eip150Block": 0, "eip155Block": 0, "eip158Block": 0, "byzantiumBlock": 0, "constantinopleBlock": 0, "petersburgBlock": 0, "ethash": {} }, "nonce": "0x42", "timestamp": "0x0", "extraData": "0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa", "gasLimit": "0xffffffff", "difficulty": "0x700000",//难度,越大挖矿越慢 "alloc": { "093f59f1d91017d30d8c2caa78feb5beb0d2cfaf...
Go获取合约事件日志
func main() { client, err := ethclient.Dial("https://rinkeby-light.eth.linkpool.io/") if err != nil { log.Fatal(err) } //获取当前的最新区块 header, err := client.HeaderByNumber(context.Background(), nil) if err != nil { log.Fatal(err) } fmt.Println("最新区块", header.Number.String()) // 5671744 //开始查询日志,可以添加过滤条件,查询符合你想要的日志 query := ethereum.FilterQuery{ FromBlock: big.NewInt( 10570948), ToBlock: header.Number, Addresses: []common.Address{ common.HexToAddress("0x40490DF1cc631817D24BA324147c59821C8970BF"), ...
Share Dialog
Share Dialog
Subscribe to point
Subscribe to point
<100 subscribers
<100 subscribers
从这开始读,因为最简单。还能对重要的东西有所理解。如果是单节点debug,重启链之后余额会归零,所以最少要两个节点,同步区块就没这个问题了,具体原因还未知。
声明:eth版本:Geth/v1.10.7-unstable/darwin-arm64/go1.17.5,我对比了网上的一些文章,这块代码有改动,主要以下改变
从BlockChain的snap中读account
几乎放弃从trie中获取account,判断极为严苛,我想不到有什么情况能进入,应该是放弃了这层
//命令
eth.getBalance('0x0d7dd6dbabee2ec9b325aa7aa8b42d75068e8597')
//入口
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
//获取statedb
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if state == nil || err != nil {
return nil, err
}
//获取余额
return (*hexutil.Big)(state.GetBalance(address)), state.Error()
}
创建statedb
func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
//根据最新的hader state root创建statedb
if blockNr, ok := blockNrOrHash.Number(); ok {
return b.StateAndHeaderByNumber(ctx, blockNr)
}
if hash, ok := blockNrOrHash.Hash(); ok {
header, err := b.HeaderByHash(ctx, hash)
if err != nil {
return nil, nil, err
}
if header == nil {
return nil, nil, errors.New("header for hash not found")
}
if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
return nil, nil, errors.New("hash is not currently canonical")
}
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
return stateDb, header, err
}
return nil, nil, errors.New("invalid arguments; neither block nor hash specified")
}
func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
// Pending state is only known by the miner
//有Pending的区块,从这里面获取statedb
if number == rpc.PendingBlockNumber {
block, state := b.eth.miner.Pending()
return state, block.Header(), nil
}
// Otherwise resolve the block number and return its state
header, err := b.HeaderByNumber(ctx, number)
if err != nil {
return nil, nil, err
}
if header == nil {
return nil, nil, errors.New("header not found")
}
//创建新的statedb
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
return stateDb, header, err
}
//主要做了两件事,创建trie和snap
func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) {
fmt.Println("root=====", root.String())
tr, err := db.OpenTrie(root)
if err != nil {
return nil, err
}
sdb := &StateDB{
db: db,
trie: tr,
originalRoot: root,
snaps: snaps,
stateObjects: make(map[common.Address]*stateObject),
stateObjectsPending: make(map[common.Address]struct{}),
stateObjectsDirty: make(map[common.Address]struct{}),
logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
accessList: newAccessList(),
hasher: crypto.NewKeccakState(),
}
if sdb.snaps != nil {
if sdb.snap = sdb.snaps.Snapshot(root); sdb.snap != nil {
sdb.snapDestructs = make(map[common.Hash]struct{})
sdb.snapAccounts = make(map[common.Hash][]byte)
sdb.snapStorage = make(map[common.Hash]map[common.Hash][]byte)
}
}
return sdb, nil
}
回到最开始从GetBalance进入
func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
fmt.Println("addr=====", addr.String())
// Prefer live objects if any is available
//从stateobject中获取
if obj := s.stateObjects[addr]; obj != nil {
return obj
}
// If no live objects are available, attempt to use snapshots
var (
data *Account
err error
)
//从缓存中获取
if s.snap != nil {
if metrics.EnabledExpensive {
defer func(start time.Time) { s.SnapshotAccountReads += time.Since(start) }(time.Now())
}
var acc *snapshot.Account
if acc, err = s.snap.Account(crypto.HashData(s.hasher, addr.Bytes())); err == nil {
if acc == nil {
return nil
}
data = &Account{
Nonce: acc.Nonce,
Balance: acc.Balance,
CodeHash: acc.CodeHash,
Root: common.BytesToHash(acc.Root),
}
if len(data.CodeHash) == 0 {
data.CodeHash = emptyCodeHash
}
if data.Root == (common.Hash{}) {
data.Root = emptyRoot
}
}
}
// If snapshot unavailable or reading from it failed, load from the database
//从trie中获取
if s.snap == nil || err != nil {
if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountReads += time.Since(start) }(time.Now())
}
enc, err := s.trie.TryGet(addr.Bytes())
if err != nil {
s.setError(fmt.Errorf("getDeleteStateObject (%x) error: %v", addr.Bytes(), err))
return nil
}
if len(enc) == 0 {
return nil
}
data = new(Account)
if err := rlp.DecodeBytes(enc, data); err != nil {
log.Error("Failed to decode state object", "addr", addr, "err", err)
return nil
}
}
// Insert into the live set
obj := newObject(s, addr, *data)
s.setStateObject(obj)
return obj
}
func (dl *diskLayer) AccountRLP(hash common.Hash) ([]byte, error) {
dl.lock.RLock()
defer dl.lock.RUnlock()
// If the layer was flattened into, consider it invalid (any live reference to
// the original should be marked as unusable).
if dl.stale {
return nil, ErrSnapshotStale
}
// If the layer is being generated, ensure the requested hash has already been
// covered by the generator.
if dl.genMarker != nil && bytes.Compare(hash[:], dl.genMarker) > 0 {
return nil, ErrNotCoveredYet
}
// If we're in the disk layer, all diff layers missed
snapshotDirtyAccountMissMeter.Mark(1)
// Try to retrieve the account from the memory cache
//从缓存中读
if blob, found := dl.cache.HasGet(nil, hash[:]); found {
snapshotCleanAccountHitMeter.Mark(1)
snapshotCleanAccountReadMeter.Mark(int64(len(blob)))
return blob, nil
}
// Cache doesn't contain account, pull from disk and cache for later
//从硬盘中读
blob := rawdb.ReadAccountSnapshot(dl.diskdb, hash)
dl.cache.Set(hash[:], blob)
snapshotCleanAccountMissMeter.Mark(1)
if n := len(blob); n > 0 {
snapshotCleanAccountWriteMeter.Mark(int64(n))
} else {
snapshotCleanAccountInexMeter.Mark(1)
}
return blob, nil
}
get balance和传统项目的思路差不多,一层层读缓存,最终读数据库,然后再保存缓存,返回前端
getBalance要先获取最新区块的root(stateRoot)来换stateDB
然后从stateDB的stateObject中获取
没有的话好像从snap中获取
先读缓存
再读levelDB
命中的话缓存至快照
没有的话再从trie中获取
命中则缓存至stateObject
返回前端
从上面了解到stateDB这个东西很重要,所有的操作都是围绕他来完成的。stateDB又是靠BlockChain里的数据来创建的
最新区块的state root
snaps
stateCache
这样就有了个大致的影响,然后通过后面的内容,更加深入的了解eth的架构
从这开始读,因为最简单。还能对重要的东西有所理解。如果是单节点debug,重启链之后余额会归零,所以最少要两个节点,同步区块就没这个问题了,具体原因还未知。
声明:eth版本:Geth/v1.10.7-unstable/darwin-arm64/go1.17.5,我对比了网上的一些文章,这块代码有改动,主要以下改变
从BlockChain的snap中读account
几乎放弃从trie中获取account,判断极为严苛,我想不到有什么情况能进入,应该是放弃了这层
//命令
eth.getBalance('0x0d7dd6dbabee2ec9b325aa7aa8b42d75068e8597')
//入口
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNrOrHash rpc.BlockNumberOrHash) (*hexutil.Big, error) {
//获取statedb
state, _, err := s.b.StateAndHeaderByNumberOrHash(ctx, blockNrOrHash)
if state == nil || err != nil {
return nil, err
}
//获取余额
return (*hexutil.Big)(state.GetBalance(address)), state.Error()
}
创建statedb
func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
//根据最新的hader state root创建statedb
if blockNr, ok := blockNrOrHash.Number(); ok {
return b.StateAndHeaderByNumber(ctx, blockNr)
}
if hash, ok := blockNrOrHash.Hash(); ok {
header, err := b.HeaderByHash(ctx, hash)
if err != nil {
return nil, nil, err
}
if header == nil {
return nil, nil, errors.New("header for hash not found")
}
if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
return nil, nil, errors.New("hash is not currently canonical")
}
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
return stateDb, header, err
}
return nil, nil, errors.New("invalid arguments; neither block nor hash specified")
}
func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
// Pending state is only known by the miner
//有Pending的区块,从这里面获取statedb
if number == rpc.PendingBlockNumber {
block, state := b.eth.miner.Pending()
return state, block.Header(), nil
}
// Otherwise resolve the block number and return its state
header, err := b.HeaderByNumber(ctx, number)
if err != nil {
return nil, nil, err
}
if header == nil {
return nil, nil, errors.New("header not found")
}
//创建新的statedb
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
return stateDb, header, err
}
//主要做了两件事,创建trie和snap
func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) {
fmt.Println("root=====", root.String())
tr, err := db.OpenTrie(root)
if err != nil {
return nil, err
}
sdb := &StateDB{
db: db,
trie: tr,
originalRoot: root,
snaps: snaps,
stateObjects: make(map[common.Address]*stateObject),
stateObjectsPending: make(map[common.Address]struct{}),
stateObjectsDirty: make(map[common.Address]struct{}),
logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte),
journal: newJournal(),
accessList: newAccessList(),
hasher: crypto.NewKeccakState(),
}
if sdb.snaps != nil {
if sdb.snap = sdb.snaps.Snapshot(root); sdb.snap != nil {
sdb.snapDestructs = make(map[common.Hash]struct{})
sdb.snapAccounts = make(map[common.Hash][]byte)
sdb.snapStorage = make(map[common.Hash]map[common.Hash][]byte)
}
}
return sdb, nil
}
回到最开始从GetBalance进入
func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
fmt.Println("addr=====", addr.String())
// Prefer live objects if any is available
//从stateobject中获取
if obj := s.stateObjects[addr]; obj != nil {
return obj
}
// If no live objects are available, attempt to use snapshots
var (
data *Account
err error
)
//从缓存中获取
if s.snap != nil {
if metrics.EnabledExpensive {
defer func(start time.Time) { s.SnapshotAccountReads += time.Since(start) }(time.Now())
}
var acc *snapshot.Account
if acc, err = s.snap.Account(crypto.HashData(s.hasher, addr.Bytes())); err == nil {
if acc == nil {
return nil
}
data = &Account{
Nonce: acc.Nonce,
Balance: acc.Balance,
CodeHash: acc.CodeHash,
Root: common.BytesToHash(acc.Root),
}
if len(data.CodeHash) == 0 {
data.CodeHash = emptyCodeHash
}
if data.Root == (common.Hash{}) {
data.Root = emptyRoot
}
}
}
// If snapshot unavailable or reading from it failed, load from the database
//从trie中获取
if s.snap == nil || err != nil {
if metrics.EnabledExpensive {
defer func(start time.Time) { s.AccountReads += time.Since(start) }(time.Now())
}
enc, err := s.trie.TryGet(addr.Bytes())
if err != nil {
s.setError(fmt.Errorf("getDeleteStateObject (%x) error: %v", addr.Bytes(), err))
return nil
}
if len(enc) == 0 {
return nil
}
data = new(Account)
if err := rlp.DecodeBytes(enc, data); err != nil {
log.Error("Failed to decode state object", "addr", addr, "err", err)
return nil
}
}
// Insert into the live set
obj := newObject(s, addr, *data)
s.setStateObject(obj)
return obj
}
func (dl *diskLayer) AccountRLP(hash common.Hash) ([]byte, error) {
dl.lock.RLock()
defer dl.lock.RUnlock()
// If the layer was flattened into, consider it invalid (any live reference to
// the original should be marked as unusable).
if dl.stale {
return nil, ErrSnapshotStale
}
// If the layer is being generated, ensure the requested hash has already been
// covered by the generator.
if dl.genMarker != nil && bytes.Compare(hash[:], dl.genMarker) > 0 {
return nil, ErrNotCoveredYet
}
// If we're in the disk layer, all diff layers missed
snapshotDirtyAccountMissMeter.Mark(1)
// Try to retrieve the account from the memory cache
//从缓存中读
if blob, found := dl.cache.HasGet(nil, hash[:]); found {
snapshotCleanAccountHitMeter.Mark(1)
snapshotCleanAccountReadMeter.Mark(int64(len(blob)))
return blob, nil
}
// Cache doesn't contain account, pull from disk and cache for later
//从硬盘中读
blob := rawdb.ReadAccountSnapshot(dl.diskdb, hash)
dl.cache.Set(hash[:], blob)
snapshotCleanAccountMissMeter.Mark(1)
if n := len(blob); n > 0 {
snapshotCleanAccountWriteMeter.Mark(int64(n))
} else {
snapshotCleanAccountInexMeter.Mark(1)
}
return blob, nil
}
get balance和传统项目的思路差不多,一层层读缓存,最终读数据库,然后再保存缓存,返回前端
getBalance要先获取最新区块的root(stateRoot)来换stateDB
然后从stateDB的stateObject中获取
没有的话好像从snap中获取
先读缓存
再读levelDB
命中的话缓存至快照
没有的话再从trie中获取
命中则缓存至stateObject
返回前端
从上面了解到stateDB这个东西很重要,所有的操作都是围绕他来完成的。stateDB又是靠BlockChain里的数据来创建的
最新区块的state root
snaps
stateCache
这样就有了个大致的影响,然后通过后面的内容,更加深入的了解eth的架构
No activity yet