Merge branch 'release/v1.20.0' into iand/issue-9849-filters
This commit is contained in:
commit
a08b557938
@ -740,6 +740,11 @@ workflows:
|
|||||||
suite: itest-eth_filter
|
suite: itest-eth_filter
|
||||||
target: "./itests/eth_filter_test.go"
|
target: "./itests/eth_filter_test.go"
|
||||||
|
|
||||||
|
- test:
|
||||||
|
name: test-itest-eth_hash_lookup
|
||||||
|
suite: itest-eth_hash_lookup
|
||||||
|
target: "./itests/eth_hash_lookup_test.go"
|
||||||
|
|
||||||
- test:
|
- test:
|
||||||
name: test-itest-eth_transactions
|
name: test-itest-eth_transactions
|
||||||
suite: itest-eth_transactions
|
suite: itest-eth_transactions
|
||||||
|
@ -778,6 +778,8 @@ type FullNode interface {
|
|||||||
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
|
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
|
||||||
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
|
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
|
||||||
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read
|
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read
|
||||||
|
EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) //perm:read
|
||||||
|
EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) //perm:read
|
||||||
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) //perm:read
|
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) //perm:read
|
||||||
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read
|
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read
|
||||||
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read
|
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read
|
||||||
|
@ -1177,6 +1177,21 @@ func (mr *MockFullNodeMockRecorder) EthGetLogs(arg0, arg1 interface{}) *gomock.C
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetLogs", reflect.TypeOf((*MockFullNode)(nil).EthGetLogs), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetLogs", reflect.TypeOf((*MockFullNode)(nil).EthGetLogs), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EthGetMessageCidByTransactionHash mocks base method.
|
||||||
|
func (m *MockFullNode) EthGetMessageCidByTransactionHash(arg0 context.Context, arg1 *ethtypes.EthHash) (*cid.Cid, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "EthGetMessageCidByTransactionHash", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(*cid.Cid)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// EthGetMessageCidByTransactionHash indicates an expected call of EthGetMessageCidByTransactionHash.
|
||||||
|
func (mr *MockFullNodeMockRecorder) EthGetMessageCidByTransactionHash(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetMessageCidByTransactionHash", reflect.TypeOf((*MockFullNode)(nil).EthGetMessageCidByTransactionHash), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// EthGetStorageAt mocks base method.
|
// EthGetStorageAt mocks base method.
|
||||||
func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 string) (ethtypes.EthBytes, error) {
|
func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 string) (ethtypes.EthBytes, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@ -1252,6 +1267,21 @@ func (mr *MockFullNodeMockRecorder) EthGetTransactionCount(arg0, arg1, arg2 inte
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionCount", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionCount), arg0, arg1, arg2)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionCount", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionCount), arg0, arg1, arg2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EthGetTransactionHashByCid mocks base method.
|
||||||
|
func (m *MockFullNode) EthGetTransactionHashByCid(arg0 context.Context, arg1 cid.Cid) (*ethtypes.EthHash, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "EthGetTransactionHashByCid", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(*ethtypes.EthHash)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// EthGetTransactionHashByCid indicates an expected call of EthGetTransactionHashByCid.
|
||||||
|
func (mr *MockFullNodeMockRecorder) EthGetTransactionHashByCid(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionHashByCid", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionHashByCid), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// EthGetTransactionReceipt mocks base method.
|
// EthGetTransactionReceipt mocks base method.
|
||||||
func (m *MockFullNode) EthGetTransactionReceipt(arg0 context.Context, arg1 ethtypes.EthHash) (*api.EthTxReceipt, error) {
|
func (m *MockFullNode) EthGetTransactionReceipt(arg0 context.Context, arg1 ethtypes.EthHash) (*api.EthTxReceipt, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -253,6 +253,8 @@ type FullNodeStruct struct {
|
|||||||
|
|
||||||
EthGetLogs func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) `perm:"read"`
|
EthGetLogs func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) `perm:"read"`
|
||||||
|
|
||||||
|
EthGetMessageCidByTransactionHash func(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) `perm:"read"`
|
||||||
|
|
||||||
EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) `perm:"read"`
|
EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) `perm:"read"`
|
||||||
|
|
||||||
EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `perm:"read"`
|
EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `perm:"read"`
|
||||||
@ -263,6 +265,8 @@ type FullNodeStruct struct {
|
|||||||
|
|
||||||
EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `perm:"read"`
|
EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `perm:"read"`
|
||||||
|
|
||||||
|
EthGetTransactionHashByCid func(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) `perm:"read"`
|
||||||
|
|
||||||
EthGetTransactionReceipt func(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) `perm:"read"`
|
EthGetTransactionReceipt func(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) `perm:"read"`
|
||||||
|
|
||||||
EthMaxPriorityFeePerGas func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"`
|
EthMaxPriorityFeePerGas func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"`
|
||||||
@ -2117,6 +2121,17 @@ func (s *FullNodeStub) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec
|
|||||||
return nil, ErrNotSupported
|
return nil, ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStruct) EthGetMessageCidByTransactionHash(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) {
|
||||||
|
if s.Internal.EthGetMessageCidByTransactionHash == nil {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
return s.Internal.EthGetMessageCidByTransactionHash(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStub) EthGetMessageCidByTransactionHash(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) {
|
func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) {
|
||||||
if s.Internal.EthGetStorageAt == nil {
|
if s.Internal.EthGetStorageAt == nil {
|
||||||
return *new(ethtypes.EthBytes), ErrNotSupported
|
return *new(ethtypes.EthBytes), ErrNotSupported
|
||||||
@ -2172,6 +2187,17 @@ func (s *FullNodeStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.Et
|
|||||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStruct) EthGetTransactionHashByCid(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) {
|
||||||
|
if s.Internal.EthGetTransactionHashByCid == nil {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
return s.Internal.EthGetTransactionHashByCid(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStub) EthGetTransactionHashByCid(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FullNodeStruct) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) {
|
func (s *FullNodeStruct) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) {
|
||||||
if s.Internal.EthGetTransactionReceipt == nil {
|
if s.Internal.EthGetTransactionReceipt == nil {
|
||||||
return nil, ErrNotSupported
|
return nil, ErrNotSupported
|
||||||
|
Binary file not shown.
@ -53,14 +53,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
|||||||
}, {
|
}, {
|
||||||
Network: "butterflynet",
|
Network: "butterflynet",
|
||||||
Version: 10,
|
Version: 10,
|
||||||
ManifestCid: MustParseCid("bafy2bzacecjs7xvhtejsh47b2tx2iwe7mbad4kxovbfs7a6wxfl47kcnl25bm"),
|
ManifestCid: MustParseCid("bafy2bzaced2wq4k4i2deknam6ehbynaoo37bhysud7eze7su3ftlaggwwjuje"),
|
||||||
Actors: map[string]cid.Cid{
|
Actors: map[string]cid.Cid{
|
||||||
"account": MustParseCid("bafk2bzacebd5zetyjtragjwrv2nqktct6u2pmsi4eifbanovxohx3a7lszjxi"),
|
"account": MustParseCid("bafk2bzacebd5zetyjtragjwrv2nqktct6u2pmsi4eifbanovxohx3a7lszjxi"),
|
||||||
"cron": MustParseCid("bafk2bzacecrszortqkc7har77ssgajglymv6ftrqvmdko5h2yqqh5k2qospl2"),
|
"cron": MustParseCid("bafk2bzacecrszortqkc7har77ssgajglymv6ftrqvmdko5h2yqqh5k2qospl2"),
|
||||||
"datacap": MustParseCid("bafk2bzacecapjnxnyw4talwqv5ajbtbkzmzqiosztj5cb3sortyp73ndjl76e"),
|
"datacap": MustParseCid("bafk2bzacecapjnxnyw4talwqv5ajbtbkzmzqiosztj5cb3sortyp73ndjl76e"),
|
||||||
"eam": MustParseCid("bafk2bzaceavdyeveel5iohjg7t6twc2cbdo7bt3m5xajwtibekudyhzv2xojy"),
|
"eam": MustParseCid("bafk2bzacebsvtqzp7g7vpufbyqrwwcpuo2yu3y7kenm7auidyiwzcv6jdw724"),
|
||||||
"ethaccount": MustParseCid("bafk2bzacedl4pmkfxkzoqajs6im3ranmopozsmxjcxsnk3kwvd3vv7mfwwrf4"),
|
"ethaccount": MustParseCid("bafk2bzacedl4pmkfxkzoqajs6im3ranmopozsmxjcxsnk3kwvd3vv7mfwwrf4"),
|
||||||
"evm": MustParseCid("bafk2bzacebgzvmvwv7rsnnhp3zhqbiqkumvyrc7pazfovpptgpgtqkalrli74"),
|
"evm": MustParseCid("bafk2bzacedx5wdyaihi22pwqqqtfxmuwh5acem46mzaep3znmhh5bsuqmxogq"),
|
||||||
"init": MustParseCid("bafk2bzacecbxp66q3ytjkg37nyv4rmzezbfaigvx4i5yhvqbm5gg4amjeaias"),
|
"init": MustParseCid("bafk2bzacecbxp66q3ytjkg37nyv4rmzezbfaigvx4i5yhvqbm5gg4amjeaias"),
|
||||||
"multisig": MustParseCid("bafk2bzacecjltag3mn75dsnmrmopjow27buxqhabissowayqlmavrcfetqswc"),
|
"multisig": MustParseCid("bafk2bzacecjltag3mn75dsnmrmopjow27buxqhabissowayqlmavrcfetqswc"),
|
||||||
"paymentchannel": MustParseCid("bafk2bzacednzxg263eqbl2imwz3uhujov63tjkffieyl4hl3dhrgxyhwep6hc"),
|
"paymentchannel": MustParseCid("bafk2bzacednzxg263eqbl2imwz3uhujov63tjkffieyl4hl3dhrgxyhwep6hc"),
|
||||||
@ -110,14 +110,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
|||||||
}, {
|
}, {
|
||||||
Network: "calibrationnet",
|
Network: "calibrationnet",
|
||||||
Version: 10,
|
Version: 10,
|
||||||
ManifestCid: MustParseCid("bafy2bzaceaklxgrzd34i53rm4eeq6477nlq2ckpex27evftbsmjd2yrdbj4ba"),
|
ManifestCid: MustParseCid("bafy2bzacearpwvmcqlailxyq2d2wtzmtudxqhvfot77tbdqotek5qiq5hyhzg"),
|
||||||
Actors: map[string]cid.Cid{
|
Actors: map[string]cid.Cid{
|
||||||
"account": MustParseCid("bafk2bzacea7zmrdz2rjbzlbmrmx3ko6pm3cbyqxxgogiqldsccbqffuok7m6s"),
|
"account": MustParseCid("bafk2bzacea7zmrdz2rjbzlbmrmx3ko6pm3cbyqxxgogiqldsccbqffuok7m6s"),
|
||||||
"cron": MustParseCid("bafk2bzacec7bxugi7ouh75nglycy7qwdq7e2hnku3w6yafq4fwdwvvq2mtrl2"),
|
"cron": MustParseCid("bafk2bzacec7bxugi7ouh75nglycy7qwdq7e2hnku3w6yafq4fwdwvvq2mtrl2"),
|
||||||
"datacap": MustParseCid("bafk2bzacedii4stmlo3ccdff7eevcolmgnuxy5ftkzbzwtkqa4iinlfzq4mei"),
|
"datacap": MustParseCid("bafk2bzacedii4stmlo3ccdff7eevcolmgnuxy5ftkzbzwtkqa4iinlfzq4mei"),
|
||||||
"eam": MustParseCid("bafk2bzacea6du2tjdewnfd2zofjp342d2lw7rdl6hx4ejawup744kpym2xsf4"),
|
"eam": MustParseCid("bafk2bzacedykxiyewqijj5nksr7qi6o4wu5yz4rezb747ntql4rpidyfdpes4"),
|
||||||
"ethaccount": MustParseCid("bafk2bzacecgbcbh3uk7olcfdqo44no5nxxayeqnycdznrlekqigbifor2revm"),
|
"ethaccount": MustParseCid("bafk2bzacecgbcbh3uk7olcfdqo44no5nxxayeqnycdznrlekqigbifor2revm"),
|
||||||
"evm": MustParseCid("bafk2bzaceanxhvz5czs6xfunhbysbttmim5e7poftibsu53uqn4by5nqmdaj6"),
|
"evm": MustParseCid("bafk2bzaceau5n66rabegik55kymni6uyk7n7jb5eymfywybs543yifpl7du2m"),
|
||||||
"init": MustParseCid("bafk2bzacea7lxnvgxupwwgoxlmwtrca75w73qabe324wnwx43qranbgf5zdqo"),
|
"init": MustParseCid("bafk2bzacea7lxnvgxupwwgoxlmwtrca75w73qabe324wnwx43qranbgf5zdqo"),
|
||||||
"multisig": MustParseCid("bafk2bzacear5eu5gpbjlroqkmsgpqerzc4aemp2uqcaeq7s2h4ur4ucgpzesg"),
|
"multisig": MustParseCid("bafk2bzacear5eu5gpbjlroqkmsgpqerzc4aemp2uqcaeq7s2h4ur4ucgpzesg"),
|
||||||
"paymentchannel": MustParseCid("bafk2bzacecwxuruxawcru7xfcx3rmt4hmhlfh4hi6jvfumerazz6jpvfmxxcw"),
|
"paymentchannel": MustParseCid("bafk2bzacecwxuruxawcru7xfcx3rmt4hmhlfh4hi6jvfumerazz6jpvfmxxcw"),
|
||||||
@ -176,14 +176,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
|||||||
}, {
|
}, {
|
||||||
Network: "caterpillarnet",
|
Network: "caterpillarnet",
|
||||||
Version: 10,
|
Version: 10,
|
||||||
ManifestCid: MustParseCid("bafy2bzaceawh5opc4uqctlzc6xnq3pb7ycchfqwprjysbfa5xlrmiicbbvkrm"),
|
ManifestCid: MustParseCid("bafy2bzacebxr4uvnf5g3373shjzbaca6pf4th6nnfubytjfbrlxcpvbjw4ane"),
|
||||||
Actors: map[string]cid.Cid{
|
Actors: map[string]cid.Cid{
|
||||||
"account": MustParseCid("bafk2bzacedfms6w3ghqtljpgsfuiqa6ztjx7kcuin6myjezj6rypj3zjbqms6"),
|
"account": MustParseCid("bafk2bzacedfms6w3ghqtljpgsfuiqa6ztjx7kcuin6myjezj6rypj3zjbqms6"),
|
||||||
"cron": MustParseCid("bafk2bzaceaganmlpozvy4jywigs46pfrtdmhjjey6uyhpurplqbasojsislba"),
|
"cron": MustParseCid("bafk2bzaceaganmlpozvy4jywigs46pfrtdmhjjey6uyhpurplqbasojsislba"),
|
||||||
"datacap": MustParseCid("bafk2bzacebafqqe3wv5ytkfwmqzbmchgem66pw6yq6rl7w6vlhqsbkxnisswq"),
|
"datacap": MustParseCid("bafk2bzacebafqqe3wv5ytkfwmqzbmchgem66pw6yq6rl7w6vlhqsbkxnisswq"),
|
||||||
"eam": MustParseCid("bafk2bzaceawl3twv7iontkiiwgezkub2vvgd7cprhv7wvgpqjpeh4o6ygshlg"),
|
"eam": MustParseCid("bafk2bzacedwk5eqczflcsuisqsyeomgkpg54olojjq2ieb2ozu5s45wfwluti"),
|
||||||
"ethaccount": MustParseCid("bafk2bzaceburkmtd63nmzxpux5rcxsbqr6x5didl2ce7al32g4tqrvo4pjz2i"),
|
"ethaccount": MustParseCid("bafk2bzaceburkmtd63nmzxpux5rcxsbqr6x5didl2ce7al32g4tqrvo4pjz2i"),
|
||||||
"evm": MustParseCid("bafk2bzacea7tp4lop7ivhay3ozitkmxxurk74v4zse42ant47rh2uw5z3tq5e"),
|
"evm": MustParseCid("bafk2bzacedbroioygjnbjtc7ykcjjs4wfbwnaa6gkzubi7c5enifoqqqu66s6"),
|
||||||
"init": MustParseCid("bafk2bzaced23r54kwuebl7t6mdantbby5qpfduxwxfryeliof2enyqzhokix6"),
|
"init": MustParseCid("bafk2bzaced23r54kwuebl7t6mdantbby5qpfduxwxfryeliof2enyqzhokix6"),
|
||||||
"multisig": MustParseCid("bafk2bzacebcn3rib6j6jvclys7dkf62hco45ssgamczkrtzt6xyewd6gt3mtu"),
|
"multisig": MustParseCid("bafk2bzacebcn3rib6j6jvclys7dkf62hco45ssgamczkrtzt6xyewd6gt3mtu"),
|
||||||
"paymentchannel": MustParseCid("bafk2bzacecvas4leo44pqdguj22nnwqoqdgwajzrpm5d6ltkehc37ni6p6doq"),
|
"paymentchannel": MustParseCid("bafk2bzacecvas4leo44pqdguj22nnwqoqdgwajzrpm5d6ltkehc37ni6p6doq"),
|
||||||
@ -233,14 +233,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
|||||||
}, {
|
}, {
|
||||||
Network: "devnet",
|
Network: "devnet",
|
||||||
Version: 10,
|
Version: 10,
|
||||||
ManifestCid: MustParseCid("bafy2bzacedfwwsn5weycwkqrnusc37m6ut2uf42z5qvbukl67wi76mqtgafw2"),
|
ManifestCid: MustParseCid("bafy2bzacebixrjysarwxdadewlllfp4rwfoejxstwdutghghei54uvuuxlsbq"),
|
||||||
Actors: map[string]cid.Cid{
|
Actors: map[string]cid.Cid{
|
||||||
"account": MustParseCid("bafk2bzacebb5txxkfexeaxa2th3rckxsxchzyss3ijgqbicf265h7rre2rvhm"),
|
"account": MustParseCid("bafk2bzacebb5txxkfexeaxa2th3rckxsxchzyss3ijgqbicf265h7rre2rvhm"),
|
||||||
"cron": MustParseCid("bafk2bzacecotn4gwluhamoqwnzgbg7ogehv26o5xnhjzltnzfv6utrlyanzek"),
|
"cron": MustParseCid("bafk2bzacecotn4gwluhamoqwnzgbg7ogehv26o5xnhjzltnzfv6utrlyanzek"),
|
||||||
"datacap": MustParseCid("bafk2bzacea4hket2srrtbewkf3tip6ellwpxdfbrzt5u47y57i2k6iojqqgba"),
|
"datacap": MustParseCid("bafk2bzacea4hket2srrtbewkf3tip6ellwpxdfbrzt5u47y57i2k6iojqqgba"),
|
||||||
"eam": MustParseCid("bafk2bzacecrg5sjpnmk3nu3vqyegkmjnvsjoumptseuu7zabeggu745bd2kwo"),
|
"eam": MustParseCid("bafk2bzacecxm2gr6tevzzan6oqp6aiqydjm5b7eo34mlzo5jdm7mnlbbueikq"),
|
||||||
"ethaccount": MustParseCid("bafk2bzacedh4y3zvtgft3i6ift4rpptgr2dx67pvenowvq7yaspuf25gqgcdc"),
|
"ethaccount": MustParseCid("bafk2bzacedh4y3zvtgft3i6ift4rpptgr2dx67pvenowvq7yaspuf25gqgcdc"),
|
||||||
"evm": MustParseCid("bafk2bzacecrjgqoozymyoplrmtpi7bmkmggiqgpbgwkzooy2a67fjivuedm6a"),
|
"evm": MustParseCid("bafk2bzacec26myls7vg6anr5yjbb2r75dryhdzwlwnrhjcyuhahlaoxdrua6i"),
|
||||||
"init": MustParseCid("bafk2bzacedof2ckc6w2qboxzxv4w67njcug4ut4cq3nnlrfybzsvlgnp4kt24"),
|
"init": MustParseCid("bafk2bzacedof2ckc6w2qboxzxv4w67njcug4ut4cq3nnlrfybzsvlgnp4kt24"),
|
||||||
"multisig": MustParseCid("bafk2bzacec4eqajjqhl53tnkbs7glu7njlbtlditi7lxhvw33ezmxk6jae46y"),
|
"multisig": MustParseCid("bafk2bzacec4eqajjqhl53tnkbs7glu7njlbtlditi7lxhvw33ezmxk6jae46y"),
|
||||||
"paymentchannel": MustParseCid("bafk2bzacec6nvdprqja7dy3qp5islebbbh2ifiyg2p7arbe6pocjhfe6xwkfy"),
|
"paymentchannel": MustParseCid("bafk2bzacec6nvdprqja7dy3qp5islebbbh2ifiyg2p7arbe6pocjhfe6xwkfy"),
|
||||||
@ -299,14 +299,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
|||||||
}, {
|
}, {
|
||||||
Network: "hyperspace",
|
Network: "hyperspace",
|
||||||
Version: 10,
|
Version: 10,
|
||||||
ManifestCid: MustParseCid("bafy2bzacedimb4dzty5tsyy3ucbcxai7crli452wn5cguhpmuelq74i4bffoo"),
|
ManifestCid: MustParseCid("bafy2bzaced6hc7ujjmypg6mkrxdmf32oh2udhmhpmwkqyxusdkxoi2uoodyxg"),
|
||||||
Actors: map[string]cid.Cid{
|
Actors: map[string]cid.Cid{
|
||||||
"account": MustParseCid("bafk2bzacecim7uybic2qprbkjhowg7qkniv4zywj5h5g4u4ss72urco2akzuo"),
|
"account": MustParseCid("bafk2bzacecim7uybic2qprbkjhowg7qkniv4zywj5h5g4u4ss72urco2akzuo"),
|
||||||
"cron": MustParseCid("bafk2bzaceahgq64awp4f7li3hdgimc4upqvdvltpmeywckvens33umcxt424a"),
|
"cron": MustParseCid("bafk2bzaceahgq64awp4f7li3hdgimc4upqvdvltpmeywckvens33umcxt424a"),
|
||||||
"datacap": MustParseCid("bafk2bzacebkxn52ttooaslkwncijk3bgd3tm2zw7vijdhwvg2cxnxbrzmmq5e"),
|
"datacap": MustParseCid("bafk2bzacebkxn52ttooaslkwncijk3bgd3tm2zw7vijdhwvg2cxnxbrzmmq5e"),
|
||||||
"eam": MustParseCid("bafk2bzacedg5bnw3ic2ub4mb2agrvdowpqd7xyjv6v2ndlkugnrtjgzzfxqlw"),
|
"eam": MustParseCid("bafk2bzaceaftiqwpx6dcjfqxyq7pazn2p55diukf32pz74755vj7pgg5joexw"),
|
||||||
"ethaccount": MustParseCid("bafk2bzacealn5enbxyxbfs7gbsjbyma2zk3bcr7okvflxhpr753d4eh6ixooa"),
|
"ethaccount": MustParseCid("bafk2bzacealn5enbxyxbfs7gbsjbyma2zk3bcr7okvflxhpr753d4eh6ixooa"),
|
||||||
"evm": MustParseCid("bafk2bzacedljkrmazyewawpnddrkzrt55556374dw2pm2hokgkompgzw4vx5y"),
|
"evm": MustParseCid("bafk2bzacea6etsvrqejjl7uej5dxlswja5gxzqyggsjjvg27timvtiedf7nsg"),
|
||||||
"init": MustParseCid("bafk2bzacec55gyyaqjrw7zughywocgwcjvv6k5fijjpjw4xgckuqz6pjtff5a"),
|
"init": MustParseCid("bafk2bzacec55gyyaqjrw7zughywocgwcjvv6k5fijjpjw4xgckuqz6pjtff5a"),
|
||||||
"multisig": MustParseCid("bafk2bzaceblozbdzybdivvjdiid4jwm2jc6x5a66sunh2vvwsqba6wzqmr7i6"),
|
"multisig": MustParseCid("bafk2bzaceblozbdzybdivvjdiid4jwm2jc6x5a66sunh2vvwsqba6wzqmr7i6"),
|
||||||
"paymentchannel": MustParseCid("bafk2bzacealcyke5a6n24efs6qe4iikynpk2twqssyugy7jcyf6p6shgw2iwa"),
|
"paymentchannel": MustParseCid("bafk2bzacealcyke5a6n24efs6qe4iikynpk2twqssyugy7jcyf6p6shgw2iwa"),
|
||||||
@ -356,14 +356,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
|||||||
}, {
|
}, {
|
||||||
Network: "mainnet",
|
Network: "mainnet",
|
||||||
Version: 10,
|
Version: 10,
|
||||||
ManifestCid: MustParseCid("bafy2bzaceat4ut5xv3qn4lvvkvwvdn6gtlbnqzvueh67fjqlemw6eled5oqnc"),
|
ManifestCid: MustParseCid("bafy2bzacea5vylkbby7rb42fknkk4g4byhj7hkqlxp4z4urydi3vlpwsgllik"),
|
||||||
Actors: map[string]cid.Cid{
|
Actors: map[string]cid.Cid{
|
||||||
"account": MustParseCid("bafk2bzacedsn6i2flkpk6sb4iuejo7gfl5n6fhsdawggtbsihlrrjtvs7oepu"),
|
"account": MustParseCid("bafk2bzacedsn6i2flkpk6sb4iuejo7gfl5n6fhsdawggtbsihlrrjtvs7oepu"),
|
||||||
"cron": MustParseCid("bafk2bzacecw4guere7ba2canyi2622lw52b5qbn7iubckcp5cwlmx2kw7qqwy"),
|
"cron": MustParseCid("bafk2bzacecw4guere7ba2canyi2622lw52b5qbn7iubckcp5cwlmx2kw7qqwy"),
|
||||||
"datacap": MustParseCid("bafk2bzaceat2ncckd2jjjqcovd3ib4sylwff7jk7rlk6gr5d2gmrrc7isrmu2"),
|
"datacap": MustParseCid("bafk2bzaceat2ncckd2jjjqcovd3ib4sylwff7jk7rlk6gr5d2gmrrc7isrmu2"),
|
||||||
"eam": MustParseCid("bafk2bzacebl7267zqf7aubpl7n6ligulayhz65dpgn3ii26b3wwjwytlsdc3i"),
|
"eam": MustParseCid("bafk2bzacebbpu5smjrjqpkrvvlhcpk23yvlovlndqmwzhfz5kuuph54tdw732"),
|
||||||
"ethaccount": MustParseCid("bafk2bzacedmwzkbytxfn7exmxxosomvix4mpyxrmupeqw45aofqmdq5q7mgqe"),
|
"ethaccount": MustParseCid("bafk2bzacedmwzkbytxfn7exmxxosomvix4mpyxrmupeqw45aofqmdq5q7mgqe"),
|
||||||
"evm": MustParseCid("bafk2bzacecrrwixyqwphxaybhy5zxuawkhncq5tgtuz2ind4bl22oivzjidoq"),
|
"evm": MustParseCid("bafk2bzacechkf43lmddynxmc35hvz5kwr3fdxrbg6fxbcvysfsihgiopbrb7o"),
|
||||||
"init": MustParseCid("bafk2bzacec6276d7ls3hhuqibqorn3yp45mv7hroczf3bgb6jkhmbb2zqt3bw"),
|
"init": MustParseCid("bafk2bzacec6276d7ls3hhuqibqorn3yp45mv7hroczf3bgb6jkhmbb2zqt3bw"),
|
||||||
"multisig": MustParseCid("bafk2bzaceahggxrnjj3w3cgtko54srssqyhcs4x6y55ytego6jf2owg5piw3y"),
|
"multisig": MustParseCid("bafk2bzaceahggxrnjj3w3cgtko54srssqyhcs4x6y55ytego6jf2owg5piw3y"),
|
||||||
"paymentchannel": MustParseCid("bafk2bzaceaobaqjamso57bkjv3n4ilv7lfropgrncnnej666w3tegmr4cfgve"),
|
"paymentchannel": MustParseCid("bafk2bzaceaobaqjamso57bkjv3n4ilv7lfropgrncnnej666w3tegmr4cfgve"),
|
||||||
@ -413,14 +413,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
|||||||
}, {
|
}, {
|
||||||
Network: "testing",
|
Network: "testing",
|
||||||
Version: 10,
|
Version: 10,
|
||||||
ManifestCid: MustParseCid("bafy2bzacearh2dy6uzcfvruckai5qbf7banklkg6uezaa7w6onsmdfxn2qxbs"),
|
ManifestCid: MustParseCid("bafy2bzacea7tbn4p232ecrjvlp2uvpci5pexqjqq2vpv4t5ihktpja2zsj3ek"),
|
||||||
Actors: map[string]cid.Cid{
|
Actors: map[string]cid.Cid{
|
||||||
"account": MustParseCid("bafk2bzaceds3iy5qjgr3stoywxt4uxvhybca23q7d2kxhitedgudrkhxaxa6o"),
|
"account": MustParseCid("bafk2bzaceds3iy5qjgr3stoywxt4uxvhybca23q7d2kxhitedgudrkhxaxa6o"),
|
||||||
"cron": MustParseCid("bafk2bzacebxp4whb4ocqxnbvqlz3kckarabtyvhjbhqvrdwhejuffwactyiss"),
|
"cron": MustParseCid("bafk2bzacebxp4whb4ocqxnbvqlz3kckarabtyvhjbhqvrdwhejuffwactyiss"),
|
||||||
"datacap": MustParseCid("bafk2bzacedepm3zas6vqryruwiz7d3axkneo7v66q65gf2dlpfd53pjlycrg4"),
|
"datacap": MustParseCid("bafk2bzacedepm3zas6vqryruwiz7d3axkneo7v66q65gf2dlpfd53pjlycrg4"),
|
||||||
"eam": MustParseCid("bafk2bzacedl4q6l3m5uvunuviwlxicyweszrahipxfpf3nt6wspvcdi4ryzyk"),
|
"eam": MustParseCid("bafk2bzacea2uascrtv6xnsqlxyf3tcf4onpgrs7frh55p6dnrdeum2uup7wx4"),
|
||||||
"ethaccount": MustParseCid("bafk2bzacecbhz4ipg773lsovgpjysm6fxl2i7y2wuxadqnt4s4vm3nd2qodb4"),
|
"ethaccount": MustParseCid("bafk2bzacecbhz4ipg773lsovgpjysm6fxl2i7y2wuxadqnt4s4vm3nd2qodb4"),
|
||||||
"evm": MustParseCid("bafk2bzaced5efc2bi7ulqsep4ej74hxwbjap2qi7lojiqzfsowxr4kylkwzk6"),
|
"evm": MustParseCid("bafk2bzaceabwn4i62od3i4qkuj5zx4vn5w5cbcl53tqnszk6kl43bfl55hl6c"),
|
||||||
"init": MustParseCid("bafk2bzacebqym5i5eciyyyzsimu73z6bkffpm5hzjpx3gwcm64pm2fh7okrja"),
|
"init": MustParseCid("bafk2bzacebqym5i5eciyyyzsimu73z6bkffpm5hzjpx3gwcm64pm2fh7okrja"),
|
||||||
"multisig": MustParseCid("bafk2bzacecmlyngek7qvj5ezaaitadrycapup3mbty4ijlzun6g23tcoysxle"),
|
"multisig": MustParseCid("bafk2bzacecmlyngek7qvj5ezaaitadrycapup3mbty4ijlzun6g23tcoysxle"),
|
||||||
"paymentchannel": MustParseCid("bafk2bzacedspin4hxpgnxkjen3hsxpcc52oc5q4ypukl4qq6vaytcgmmi7hl4"),
|
"paymentchannel": MustParseCid("bafk2bzacedspin4hxpgnxkjen3hsxpcc52oc5q4ypukl4qq6vaytcgmmi7hl4"),
|
||||||
@ -470,14 +470,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
|||||||
}, {
|
}, {
|
||||||
Network: "testing-fake-proofs",
|
Network: "testing-fake-proofs",
|
||||||
Version: 10,
|
Version: 10,
|
||||||
ManifestCid: MustParseCid("bafy2bzacedw6kk3u2vjexzqmm3vtvusd42lllk7wbnsrlxxmt35smsnmiatca"),
|
ManifestCid: MustParseCid("bafy2bzacecyqfyzmw72234rvbk6vzq2omnmt3cbfezkq2h3ewnn33w42b2s62"),
|
||||||
Actors: map[string]cid.Cid{
|
Actors: map[string]cid.Cid{
|
||||||
"account": MustParseCid("bafk2bzaceds3iy5qjgr3stoywxt4uxvhybca23q7d2kxhitedgudrkhxaxa6o"),
|
"account": MustParseCid("bafk2bzaceds3iy5qjgr3stoywxt4uxvhybca23q7d2kxhitedgudrkhxaxa6o"),
|
||||||
"cron": MustParseCid("bafk2bzacebxp4whb4ocqxnbvqlz3kckarabtyvhjbhqvrdwhejuffwactyiss"),
|
"cron": MustParseCid("bafk2bzacebxp4whb4ocqxnbvqlz3kckarabtyvhjbhqvrdwhejuffwactyiss"),
|
||||||
"datacap": MustParseCid("bafk2bzacedepm3zas6vqryruwiz7d3axkneo7v66q65gf2dlpfd53pjlycrg4"),
|
"datacap": MustParseCid("bafk2bzacedepm3zas6vqryruwiz7d3axkneo7v66q65gf2dlpfd53pjlycrg4"),
|
||||||
"eam": MustParseCid("bafk2bzacedl4q6l3m5uvunuviwlxicyweszrahipxfpf3nt6wspvcdi4ryzyk"),
|
"eam": MustParseCid("bafk2bzacea2uascrtv6xnsqlxyf3tcf4onpgrs7frh55p6dnrdeum2uup7wx4"),
|
||||||
"ethaccount": MustParseCid("bafk2bzacecbhz4ipg773lsovgpjysm6fxl2i7y2wuxadqnt4s4vm3nd2qodb4"),
|
"ethaccount": MustParseCid("bafk2bzacecbhz4ipg773lsovgpjysm6fxl2i7y2wuxadqnt4s4vm3nd2qodb4"),
|
||||||
"evm": MustParseCid("bafk2bzaced5efc2bi7ulqsep4ej74hxwbjap2qi7lojiqzfsowxr4kylkwzk6"),
|
"evm": MustParseCid("bafk2bzaceabwn4i62od3i4qkuj5zx4vn5w5cbcl53tqnszk6kl43bfl55hl6c"),
|
||||||
"init": MustParseCid("bafk2bzacebqym5i5eciyyyzsimu73z6bkffpm5hzjpx3gwcm64pm2fh7okrja"),
|
"init": MustParseCid("bafk2bzacebqym5i5eciyyyzsimu73z6bkffpm5hzjpx3gwcm64pm2fh7okrja"),
|
||||||
"multisig": MustParseCid("bafk2bzacecmlyngek7qvj5ezaaitadrycapup3mbty4ijlzun6g23tcoysxle"),
|
"multisig": MustParseCid("bafk2bzacecmlyngek7qvj5ezaaitadrycapup3mbty4ijlzun6g23tcoysxle"),
|
||||||
"paymentchannel": MustParseCid("bafk2bzacedspin4hxpgnxkjen3hsxpcc52oc5q4ypukl4qq6vaytcgmmi7hl4"),
|
"paymentchannel": MustParseCid("bafk2bzacedspin4hxpgnxkjen3hsxpcc52oc5q4ypukl4qq6vaytcgmmi7hl4"),
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
163
chain/ethhashlookup/eth_transaction_hash_lookup.go
Normal file
163
chain/ethhashlookup/eth_transaction_hash_lookup.go
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
package ethhashlookup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrNotFound = errors.New("not found")
|
||||||
|
|
||||||
|
var pragmas = []string{
|
||||||
|
"PRAGMA synchronous = normal",
|
||||||
|
"PRAGMA temp_store = memory",
|
||||||
|
"PRAGMA mmap_size = 30000000000",
|
||||||
|
"PRAGMA page_size = 32768",
|
||||||
|
"PRAGMA auto_vacuum = NONE",
|
||||||
|
"PRAGMA automatic_index = OFF",
|
||||||
|
"PRAGMA journal_mode = WAL",
|
||||||
|
"PRAGMA read_uncommitted = ON",
|
||||||
|
}
|
||||||
|
|
||||||
|
var ddls = []string{
|
||||||
|
`CREATE TABLE IF NOT EXISTS eth_tx_hashes (
|
||||||
|
hash TEXT PRIMARY KEY NOT NULL,
|
||||||
|
cid TEXT NOT NULL UNIQUE,
|
||||||
|
insertion_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||||
|
)`,
|
||||||
|
|
||||||
|
`CREATE INDEX IF NOT EXISTS insertion_time_index ON eth_tx_hashes (insertion_time)`,
|
||||||
|
|
||||||
|
// metadata containing version of schema
|
||||||
|
`CREATE TABLE IF NOT EXISTS _meta (
|
||||||
|
version UINT64 NOT NULL UNIQUE
|
||||||
|
)`,
|
||||||
|
|
||||||
|
// version 1.
|
||||||
|
`INSERT OR IGNORE INTO _meta (version) VALUES (1)`,
|
||||||
|
}
|
||||||
|
|
||||||
|
const schemaVersion = 1
|
||||||
|
|
||||||
|
const (
|
||||||
|
insertTxHash = `INSERT INTO eth_tx_hashes
|
||||||
|
(hash, cid)
|
||||||
|
VALUES(?, ?)
|
||||||
|
ON CONFLICT (hash) DO UPDATE SET insertion_time = CURRENT_TIMESTAMP`
|
||||||
|
)
|
||||||
|
|
||||||
|
type EthTxHashLookup struct {
|
||||||
|
db *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ei *EthTxHashLookup) UpsertHash(txHash ethtypes.EthHash, c cid.Cid) error {
|
||||||
|
hashEntry, err := ei.db.Prepare(insertTxHash)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("prepare insert event: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = hashEntry.Exec(txHash.String(), c.String())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ei *EthTxHashLookup) GetCidFromHash(txHash ethtypes.EthHash) (cid.Cid, error) {
|
||||||
|
q, err := ei.db.Query("SELECT cid FROM eth_tx_hashes WHERE hash = :hash;", sql.Named("hash", txHash.String()))
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var c string
|
||||||
|
if !q.Next() {
|
||||||
|
return cid.Undef, ErrNotFound
|
||||||
|
}
|
||||||
|
err = q.Scan(&c)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, err
|
||||||
|
}
|
||||||
|
return cid.Decode(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ei *EthTxHashLookup) GetHashFromCid(c cid.Cid) (ethtypes.EthHash, error) {
|
||||||
|
q, err := ei.db.Query("SELECT hash FROM eth_tx_hashes WHERE cid = :cid;", sql.Named("cid", c.String()))
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EmptyEthHash, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var hashString string
|
||||||
|
if !q.Next() {
|
||||||
|
return ethtypes.EmptyEthHash, ErrNotFound
|
||||||
|
}
|
||||||
|
err = q.Scan(&hashString)
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EmptyEthHash, err
|
||||||
|
}
|
||||||
|
return ethtypes.ParseEthHash(hashString)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ei *EthTxHashLookup) DeleteEntriesOlderThan(days int) (int64, error) {
|
||||||
|
res, err := ei.db.Exec("DELETE FROM eth_tx_hashes WHERE insertion_time < datetime('now', ?);", "-"+strconv.Itoa(days)+" day")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.RowsAffected()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTransactionHashLookup(path string) (*EthTxHashLookup, error) {
|
||||||
|
db, err := sql.Open("sqlite3", path+"?mode=rwc")
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("open sqlite3 database: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pragma := range pragmas {
|
||||||
|
if _, err := db.Exec(pragma); err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, xerrors.Errorf("exec pragma %q: %w", pragma, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
q, err := db.Query("SELECT name FROM sqlite_master WHERE type='table' AND name='_meta';")
|
||||||
|
if err == sql.ErrNoRows || !q.Next() {
|
||||||
|
// empty database, create the schema
|
||||||
|
for _, ddl := range ddls {
|
||||||
|
if _, err := db.Exec(ddl); err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, xerrors.Errorf("exec ddl %q: %w", ddl, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, xerrors.Errorf("looking for _meta table: %w", err)
|
||||||
|
} else {
|
||||||
|
// Ensure we don't open a database from a different schema version
|
||||||
|
|
||||||
|
row := db.QueryRow("SELECT max(version) FROM _meta")
|
||||||
|
var version int
|
||||||
|
err := row.Scan(&version)
|
||||||
|
if err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, xerrors.Errorf("invalid database version: no version found")
|
||||||
|
}
|
||||||
|
if version != schemaVersion {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, xerrors.Errorf("invalid database version: got %d, expected %d", version, schemaVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EthTxHashLookup{
|
||||||
|
db: db,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ei *EthTxHashLookup) Close() error {
|
||||||
|
if ei.db == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ei.db.Close()
|
||||||
|
}
|
@ -5,7 +5,6 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
@ -18,7 +17,7 @@ type MemPoolFilter struct {
|
|||||||
ch chan<- interface{}
|
ch chan<- interface{}
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
collected []cid.Cid
|
collected []*types.SignedMessage
|
||||||
lastTaken time.Time
|
lastTaken time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,10 +54,10 @@ func (f *MemPoolFilter) CollectMessage(ctx context.Context, msg *types.SignedMes
|
|||||||
copy(f.collected, f.collected[1:])
|
copy(f.collected, f.collected[1:])
|
||||||
f.collected = f.collected[:len(f.collected)-1]
|
f.collected = f.collected[:len(f.collected)-1]
|
||||||
}
|
}
|
||||||
f.collected = append(f.collected, msg.Cid())
|
f.collected = append(f.collected, msg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *MemPoolFilter) TakeCollectedMessages(context.Context) []cid.Cid {
|
func (f *MemPoolFilter) TakeCollectedMessages(context.Context) []*types.SignedMessage {
|
||||||
f.mu.Lock()
|
f.mu.Lock()
|
||||||
collected := f.collected
|
collected := f.collected
|
||||||
f.collected = nil
|
f.collected = nil
|
||||||
|
@ -22,6 +22,8 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const TIPSETKEY_BACKFILL_RANGE = 2 * build.Finality
|
||||||
|
|
||||||
func (cs *ChainStore) UnionStore() bstore.Blockstore {
|
func (cs *ChainStore) UnionStore() bstore.Blockstore {
|
||||||
return bstore.Union(cs.stateBlockstore, cs.chainBlockstore)
|
return bstore.Union(cs.stateBlockstore, cs.chainBlockstore)
|
||||||
}
|
}
|
||||||
@ -113,6 +115,20 @@ func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (*types.TipSet, e
|
|||||||
return nil, xerrors.Errorf("failed to load root tipset from chainfile: %w", err)
|
return nil, xerrors.Errorf("failed to load root tipset from chainfile: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ts := root
|
||||||
|
for i := 0; i < int(TIPSETKEY_BACKFILL_RANGE); i++ {
|
||||||
|
err = cs.PersistTipset(ctx, ts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
parentTsKey := ts.Parents()
|
||||||
|
ts, err = cs.LoadTipSet(ctx, parentTsKey)
|
||||||
|
if ts == nil || err != nil {
|
||||||
|
log.Warnf("Only able to load the last %d tipsets", i)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return root, nil
|
return root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1097,6 +1097,10 @@ func (cs *ChainStore) StateBlockstore() bstore.Blockstore {
|
|||||||
return cs.stateBlockstore
|
return cs.stateBlockstore
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cs *ChainStore) ChainLocalBlockstore() bstore.Blockstore {
|
||||||
|
return cs.chainLocalBlockstore
|
||||||
|
}
|
||||||
|
|
||||||
func ActorStore(ctx context.Context, bs bstore.Blockstore) adt.Store {
|
func ActorStore(ctx context.Context, bs bstore.Blockstore) adt.Store {
|
||||||
return adt.WrapStore(ctx, cbor.NewCborStore(bs))
|
return adt.WrapStore(ctx, cbor.NewCborStore(bs))
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/ipfs/go-datastore"
|
"github.com/ipfs/go-datastore"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/crypto"
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
@ -124,6 +125,51 @@ func TestChainExportImport(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test to check if tipset key cids are being stored on snapshot
|
||||||
|
func TestChainImportTipsetKeyCid(t *testing.T) {
|
||||||
|
|
||||||
|
ctx := context.Background()
|
||||||
|
cg, err := gen.NewGenerator()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
var last *types.TipSet
|
||||||
|
var tsKeys []types.TipSetKey
|
||||||
|
for i := 0; i < 10; i++ {
|
||||||
|
ts, err := cg.NextTipSet()
|
||||||
|
require.NoError(t, err)
|
||||||
|
last = ts.TipSet.TipSet()
|
||||||
|
tsKeys = append(tsKeys, last.Key())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := cg.ChainStore().Export(ctx, last, last.Height(), false, buf); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
nbs := blockstore.NewMemorySync()
|
||||||
|
cs := store.NewChainStore(nbs, nbs, datastore.NewMapDatastore(), filcns.Weight, nil)
|
||||||
|
defer cs.Close() //nolint:errcheck
|
||||||
|
|
||||||
|
root, err := cs.Import(ctx, buf)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Truef(t, root.Equals(last), "imported chain differed from exported chain")
|
||||||
|
|
||||||
|
err = cs.SetHead(ctx, last)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
for _, tsKey := range tsKeys {
|
||||||
|
_, err := cs.LoadTipSet(ctx, tsKey)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tsCid, err := tsKey.Cid()
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, err = cs.ChainLocalBlockstore().Get(ctx, tsCid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestChainExportImportFull(t *testing.T) {
|
func TestChainExportImportFull(t *testing.T) {
|
||||||
//stm: @CHAIN_GEN_NEXT_TIPSET_001
|
//stm: @CHAIN_GEN_NEXT_TIPSET_001
|
||||||
//stm: @CHAIN_STORE_IMPORT_001, @CHAIN_STORE_EXPORT_001, @CHAIN_STORE_SET_HEAD_001
|
//stm: @CHAIN_STORE_IMPORT_001, @CHAIN_STORE_EXPORT_001, @CHAIN_STORE_SET_HEAD_001
|
||||||
|
@ -231,6 +231,36 @@ func (tx *EthTxArgs) ToRlpUnsignedMsg() ([]byte, error) {
|
|||||||
return append([]byte{0x02}, encoded...), nil
|
return append([]byte{0x02}, encoded...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tx *EthTx) ToEthTxArgs() EthTxArgs {
|
||||||
|
return EthTxArgs{
|
||||||
|
ChainID: int(tx.ChainID),
|
||||||
|
Nonce: int(tx.Nonce),
|
||||||
|
To: tx.To,
|
||||||
|
Value: big.Int(tx.Value),
|
||||||
|
MaxFeePerGas: big.Int(tx.MaxFeePerGas),
|
||||||
|
MaxPriorityFeePerGas: big.Int(tx.MaxPriorityFeePerGas),
|
||||||
|
GasLimit: int(tx.Gas),
|
||||||
|
Input: tx.Input,
|
||||||
|
V: big.Int(tx.V),
|
||||||
|
R: big.Int(tx.R),
|
||||||
|
S: big.Int(tx.S),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *EthTx) TxHash() (EthHash, error) {
|
||||||
|
ethTxArgs := tx.ToEthTxArgs()
|
||||||
|
return (ðTxArgs).TxHash()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *EthTxArgs) TxHash() (EthHash, error) {
|
||||||
|
rlp, err := tx.ToRlpSignedMsg()
|
||||||
|
if err != nil {
|
||||||
|
return EmptyEthHash, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return EthHashFromTxBytes(rlp), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *EthTxArgs) ToRlpSignedMsg() ([]byte, error) {
|
func (tx *EthTxArgs) ToRlpSignedMsg() ([]byte, error) {
|
||||||
packed1, err := tx.packTxFields()
|
packed1, err := tx.packTxFields()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -396,10 +396,21 @@ func ParseEthHash(s string) (EthHash, error) {
|
|||||||
return h, nil
|
return h, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EthHashFromTxBytes(b []byte) EthHash {
|
||||||
|
hasher := sha3.NewLegacyKeccak256()
|
||||||
|
hasher.Write(b)
|
||||||
|
hash := hasher.Sum(nil)
|
||||||
|
|
||||||
|
var ethHash EthHash
|
||||||
|
copy(ethHash[:], hash)
|
||||||
|
return ethHash
|
||||||
|
}
|
||||||
|
|
||||||
func (h EthHash) String() string {
|
func (h EthHash) String() string {
|
||||||
return "0x" + hex.EncodeToString(h[:])
|
return "0x" + hex.EncodeToString(h[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Should ONLY be used for blocks and Filecoin messages. Eth transactions expect a different hashing scheme.
|
||||||
func (h EthHash) ToCid() cid.Cid {
|
func (h EthHash) ToCid() cid.Cid {
|
||||||
// err is always nil
|
// err is always nil
|
||||||
mh, _ := multihash.EncodeName(h[:], "blake2b-256")
|
mh, _ := multihash.EncodeName(h[:], "blake2b-256")
|
||||||
@ -560,7 +571,7 @@ type EthLog struct {
|
|||||||
// The index corresponds to the sequence of messages produced by ChainGetParentMessages
|
// The index corresponds to the sequence of messages produced by ChainGetParentMessages
|
||||||
TransactionIndex EthUint64 `json:"transactionIndex"`
|
TransactionIndex EthUint64 `json:"transactionIndex"`
|
||||||
|
|
||||||
// TransactionHash is the cid of the message that produced the event log.
|
// TransactionHash is the hash of the RLP message that produced the event log.
|
||||||
TransactionHash EthHash `json:"transactionHash"`
|
TransactionHash EthHash `json:"transactionHash"`
|
||||||
|
|
||||||
// BlockHash is the hash of the tipset containing the message that produced the log.
|
// BlockHash is the hash of the tipset containing the message that produced the log.
|
||||||
|
@ -83,11 +83,13 @@
|
|||||||
* [EthGetFilterChanges](#EthGetFilterChanges)
|
* [EthGetFilterChanges](#EthGetFilterChanges)
|
||||||
* [EthGetFilterLogs](#EthGetFilterLogs)
|
* [EthGetFilterLogs](#EthGetFilterLogs)
|
||||||
* [EthGetLogs](#EthGetLogs)
|
* [EthGetLogs](#EthGetLogs)
|
||||||
|
* [EthGetMessageCidByTransactionHash](#EthGetMessageCidByTransactionHash)
|
||||||
* [EthGetStorageAt](#EthGetStorageAt)
|
* [EthGetStorageAt](#EthGetStorageAt)
|
||||||
* [EthGetTransactionByBlockHashAndIndex](#EthGetTransactionByBlockHashAndIndex)
|
* [EthGetTransactionByBlockHashAndIndex](#EthGetTransactionByBlockHashAndIndex)
|
||||||
* [EthGetTransactionByBlockNumberAndIndex](#EthGetTransactionByBlockNumberAndIndex)
|
* [EthGetTransactionByBlockNumberAndIndex](#EthGetTransactionByBlockNumberAndIndex)
|
||||||
* [EthGetTransactionByHash](#EthGetTransactionByHash)
|
* [EthGetTransactionByHash](#EthGetTransactionByHash)
|
||||||
* [EthGetTransactionCount](#EthGetTransactionCount)
|
* [EthGetTransactionCount](#EthGetTransactionCount)
|
||||||
|
* [EthGetTransactionHashByCid](#EthGetTransactionHashByCid)
|
||||||
* [EthGetTransactionReceipt](#EthGetTransactionReceipt)
|
* [EthGetTransactionReceipt](#EthGetTransactionReceipt)
|
||||||
* [EthMaxPriorityFeePerGas](#EthMaxPriorityFeePerGas)
|
* [EthMaxPriorityFeePerGas](#EthMaxPriorityFeePerGas)
|
||||||
* [EthNewBlockFilter](#EthNewBlockFilter)
|
* [EthNewBlockFilter](#EthNewBlockFilter)
|
||||||
@ -2640,6 +2642,25 @@ Response:
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### EthGetMessageCidByTransactionHash
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### EthGetStorageAt
|
### EthGetStorageAt
|
||||||
|
|
||||||
|
|
||||||
@ -2778,6 +2799,22 @@ Inputs:
|
|||||||
|
|
||||||
Response: `"0x5"`
|
Response: `"0x5"`
|
||||||
|
|
||||||
|
### EthGetTransactionHashByCid
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response: `"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"`
|
||||||
|
|
||||||
### EthGetTransactionReceipt
|
### EthGetTransactionReceipt
|
||||||
|
|
||||||
|
|
||||||
|
@ -343,3 +343,19 @@
|
|||||||
#ActorEventDatabasePath = ""
|
#ActorEventDatabasePath = ""
|
||||||
|
|
||||||
|
|
||||||
|
[Fevm]
|
||||||
|
# EnableEthHashToFilecoinCidMapping enables storing a mapping of eth transaction hashes to filecoin message Cids
|
||||||
|
# You will not be able to look up ethereum transactions by their hash if this is disabled.
|
||||||
|
#
|
||||||
|
# type: bool
|
||||||
|
# env var: LOTUS_FEVM_ENABLEETHHASHTOFILECOINCIDMAPPING
|
||||||
|
#EnableEthHashToFilecoinCidMapping = false
|
||||||
|
|
||||||
|
# EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
|
||||||
|
# Set to 0 to keep all mappings
|
||||||
|
#
|
||||||
|
# type: int
|
||||||
|
# env var: LOTUS_FEVM_ETHTXHASHMAPPINGLIFETIMEDAYS
|
||||||
|
#EthTxHashMappingLifetimeDays = 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ func TestDeployment(t *testing.T) {
|
|||||||
cfg.ActorEvent.EnableRealTimeFilterAPI = true
|
cfg.ActorEvent.EnableRealTimeFilterAPI = true
|
||||||
return nil
|
return nil
|
||||||
}),
|
}),
|
||||||
|
kit.EthTxHashLookup(),
|
||||||
)
|
)
|
||||||
ens.InterconnectAll().BeginMining(blockTime)
|
ens.InterconnectAll().BeginMining(blockTime)
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ func TestEthNewFilterCatchAll(t *testing.T) {
|
|||||||
kit.QuietAllLogsExcept("events", "messagepool")
|
kit.QuietAllLogsExcept("events", "messagepool")
|
||||||
|
|
||||||
blockTime := 100 * time.Millisecond
|
blockTime := 100 * time.Millisecond
|
||||||
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.RealTimeFilterAPI())
|
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.RealTimeFilterAPI(), kit.EthTxHashLookup())
|
||||||
ens.InterconnectAll().BeginMining(blockTime)
|
ens.InterconnectAll().BeginMining(blockTime)
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
@ -1436,9 +1436,9 @@ func invokeAndWaitUntilAllOnChain(t *testing.T, client *kit.TestFullNode, invoca
|
|||||||
require.True(ok)
|
require.True(ok)
|
||||||
m.events = evs
|
m.events = evs
|
||||||
|
|
||||||
eh, err := ethtypes.EthHashFromCid(m.msg.Cid)
|
eh, err := client.EthGetTransactionHashByCid(ctx, m.msg.Cid)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
received[eh] = m
|
received[*eh] = m
|
||||||
}
|
}
|
||||||
require.Equal(len(invocations), len(received), "all messages on chain")
|
require.Equal(len(invocations), len(received), "all messages on chain")
|
||||||
|
|
||||||
|
598
itests/eth_hash_lookup_test.go
Normal file
598
itests/eth_hash_lookup_test.go
Normal file
@ -0,0 +1,598 @@
|
|||||||
|
package itests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/hex"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||||
|
"github.com/filecoin-project/lotus/itests/kit"
|
||||||
|
"github.com/filecoin-project/lotus/node/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestTransactionHashLookup tests to see if lotus correctly stores a mapping from ethereum transaction hash to
|
||||||
|
// Filecoin Message Cid
|
||||||
|
func TestTransactionHashLookup(t *testing.T) {
|
||||||
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
|
blocktime := 1 * time.Second
|
||||||
|
client, _, ens := kit.EnsembleMinimal(
|
||||||
|
t,
|
||||||
|
kit.MockProofs(),
|
||||||
|
kit.ThroughRPC(),
|
||||||
|
kit.EthTxHashLookup(),
|
||||||
|
)
|
||||||
|
ens.InterconnectAll().BeginMining(blocktime)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// install contract
|
||||||
|
contractHex, err := os.ReadFile("./contracts/SimpleCoin.hex")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
contract, err := hex.DecodeString(string(contractHex))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// create a new Ethereum account
|
||||||
|
key, ethAddr, deployer := client.EVM().NewAccount()
|
||||||
|
|
||||||
|
// send some funds to the f410 address
|
||||||
|
kit.SendFunds(ctx, t, client, deployer, types.FromFil(10))
|
||||||
|
|
||||||
|
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||||
|
From: ðAddr,
|
||||||
|
Data: contract,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// now deploy a contract from the embryo, and validate it went well
|
||||||
|
tx := ethtypes.EthTxArgs{
|
||||||
|
ChainID: build.Eip155ChainId,
|
||||||
|
Value: big.Zero(),
|
||||||
|
Nonce: 0,
|
||||||
|
MaxFeePerGas: types.NanoFil,
|
||||||
|
MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas),
|
||||||
|
GasLimit: int(gaslimit),
|
||||||
|
Input: contract,
|
||||||
|
V: big.Zero(),
|
||||||
|
R: big.Zero(),
|
||||||
|
S: big.Zero(),
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EVM().SignTransaction(&tx, key.PrivateKey)
|
||||||
|
|
||||||
|
rawTxHash, err := tx.TxHash()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
hash := client.EVM().SubmitTransaction(ctx, &tx)
|
||||||
|
require.Equal(t, rawTxHash, hash)
|
||||||
|
|
||||||
|
mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, hash, mpoolTx.Hash)
|
||||||
|
|
||||||
|
// Wait for message to land on chain
|
||||||
|
var receipt *api.EthTxReceipt
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
receipt, err = client.EthGetTransactionReceipt(ctx, hash)
|
||||||
|
if err != nil || receipt == nil {
|
||||||
|
time.Sleep(blocktime)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, receipt)
|
||||||
|
|
||||||
|
// Verify that the chain transaction now has new fields set.
|
||||||
|
chainTx, err := client.EthGetTransactionByHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, hash, chainTx.Hash)
|
||||||
|
|
||||||
|
// require that the hashes are identical
|
||||||
|
require.Equal(t, hash, chainTx.Hash)
|
||||||
|
require.NotNil(t, chainTx.BlockNumber)
|
||||||
|
require.Greater(t, uint64(*chainTx.BlockNumber), uint64(0))
|
||||||
|
require.NotNil(t, chainTx.BlockHash)
|
||||||
|
require.NotEmpty(t, *chainTx.BlockHash)
|
||||||
|
require.NotNil(t, chainTx.TransactionIndex)
|
||||||
|
require.Equal(t, uint64(*chainTx.TransactionIndex), uint64(0)) // only transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTransactionHashLookupNoDb tests to see if looking up eth transactions by hash breaks without the lookup table
|
||||||
|
func TestTransactionHashLookupNoDb(t *testing.T) {
|
||||||
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
|
blocktime := 1 * time.Second
|
||||||
|
client, _, ens := kit.EnsembleMinimal(
|
||||||
|
t,
|
||||||
|
kit.MockProofs(),
|
||||||
|
kit.ThroughRPC(),
|
||||||
|
kit.WithCfgOpt(func(cfg *config.FullNode) error {
|
||||||
|
cfg.Fevm.EnableEthHashToFilecoinCidMapping = false
|
||||||
|
return nil
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
ens.InterconnectAll().BeginMining(blocktime)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// install contract
|
||||||
|
contractHex, err := os.ReadFile("./contracts/SimpleCoin.hex")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
contract, err := hex.DecodeString(string(contractHex))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// create a new Ethereum account
|
||||||
|
key, ethAddr, deployer := client.EVM().NewAccount()
|
||||||
|
|
||||||
|
// send some funds to the f410 address
|
||||||
|
kit.SendFunds(ctx, t, client, deployer, types.FromFil(10))
|
||||||
|
|
||||||
|
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||||
|
From: ðAddr,
|
||||||
|
Data: contract,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// now deploy a contract from the embryo, and validate it went well
|
||||||
|
tx := ethtypes.EthTxArgs{
|
||||||
|
ChainID: build.Eip155ChainId,
|
||||||
|
Value: big.Zero(),
|
||||||
|
Nonce: 0,
|
||||||
|
MaxFeePerGas: types.NanoFil,
|
||||||
|
MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas),
|
||||||
|
GasLimit: int(gaslimit),
|
||||||
|
Input: contract,
|
||||||
|
V: big.Zero(),
|
||||||
|
R: big.Zero(),
|
||||||
|
S: big.Zero(),
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EVM().SignTransaction(&tx, key.PrivateKey)
|
||||||
|
|
||||||
|
rawTxHash, err := tx.TxHash()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
hash := client.EVM().SubmitTransaction(ctx, &tx)
|
||||||
|
require.Equal(t, rawTxHash, hash)
|
||||||
|
|
||||||
|
// We shouldn't be able to find the tx
|
||||||
|
mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, mpoolTx)
|
||||||
|
|
||||||
|
// Wait for message to land on chain, we can't know exactly when because we can't find it.
|
||||||
|
time.Sleep(20 * blocktime)
|
||||||
|
receipt, err := client.EthGetTransactionReceipt(ctx, hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, receipt)
|
||||||
|
|
||||||
|
// We still shouldn't be able to find the tx
|
||||||
|
chainTx, err := client.EthGetTransactionByHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, chainTx)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTransactionHashLookupBlsFilecoinMessage tests to see if lotus can find a BLS Filecoin Message using the transaction hash
|
||||||
|
func TestTransactionHashLookupBlsFilecoinMessage(t *testing.T) {
|
||||||
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
|
blocktime := 1 * time.Second
|
||||||
|
client, _, ens := kit.EnsembleMinimal(
|
||||||
|
t,
|
||||||
|
kit.MockProofs(),
|
||||||
|
kit.ThroughRPC(),
|
||||||
|
kit.EthTxHashLookup(),
|
||||||
|
)
|
||||||
|
ens.InterconnectAll().BeginMining(blocktime)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// get the existing balance from the default wallet to then split it.
|
||||||
|
bal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// create a new address where to send funds.
|
||||||
|
addr, err := client.WalletNew(ctx, types.KTBLS)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
toSend := big.Div(bal, big.NewInt(2))
|
||||||
|
msg := &types.Message{
|
||||||
|
From: client.DefaultKey.Address,
|
||||||
|
To: addr,
|
||||||
|
Value: toSend,
|
||||||
|
}
|
||||||
|
|
||||||
|
sm, err := client.MpoolPushMessage(ctx, msg, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
hash, err := ethtypes.EthHashFromCid(sm.Message.Cid())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, hash, mpoolTx.Hash)
|
||||||
|
|
||||||
|
// Wait for message to land on chain
|
||||||
|
var receipt *api.EthTxReceipt
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
receipt, err = client.EthGetTransactionReceipt(ctx, hash)
|
||||||
|
if err != nil || receipt == nil {
|
||||||
|
time.Sleep(blocktime)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, receipt)
|
||||||
|
require.Equal(t, hash, receipt.TransactionHash)
|
||||||
|
|
||||||
|
// Verify that the chain transaction now has new fields set.
|
||||||
|
chainTx, err := client.EthGetTransactionByHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, hash, chainTx.Hash)
|
||||||
|
|
||||||
|
// require that the hashes are identical
|
||||||
|
require.Equal(t, hash, chainTx.Hash)
|
||||||
|
require.NotNil(t, chainTx.BlockNumber)
|
||||||
|
require.Greater(t, uint64(*chainTx.BlockNumber), uint64(0))
|
||||||
|
require.NotNil(t, chainTx.BlockHash)
|
||||||
|
require.NotEmpty(t, *chainTx.BlockHash)
|
||||||
|
require.NotNil(t, chainTx.TransactionIndex)
|
||||||
|
require.Equal(t, uint64(*chainTx.TransactionIndex), uint64(0)) // only transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTransactionHashLookupSecpFilecoinMessage tests to see if lotus can find a Secp Filecoin Message using the transaction hash
|
||||||
|
func TestTransactionHashLookupSecpFilecoinMessage(t *testing.T) {
|
||||||
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
|
blocktime := 1 * time.Second
|
||||||
|
client, _, ens := kit.EnsembleMinimal(
|
||||||
|
t,
|
||||||
|
kit.MockProofs(),
|
||||||
|
kit.ThroughRPC(),
|
||||||
|
kit.EthTxHashLookup(),
|
||||||
|
)
|
||||||
|
ens.InterconnectAll().BeginMining(blocktime)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// get the existing balance from the default wallet to then split it.
|
||||||
|
bal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// create a new address where to send funds.
|
||||||
|
addr, err := client.WalletNew(ctx, types.KTSecp256k1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
toSend := big.Div(bal, big.NewInt(2))
|
||||||
|
setupMsg := &types.Message{
|
||||||
|
From: client.DefaultKey.Address,
|
||||||
|
To: addr,
|
||||||
|
Value: toSend,
|
||||||
|
}
|
||||||
|
|
||||||
|
setupSmsg, err := client.MpoolPushMessage(ctx, setupMsg, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = client.StateWaitMsg(ctx, setupSmsg.Cid(), 3, api.LookbackNoLimit, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Send message for secp account
|
||||||
|
secpMsg := &types.Message{
|
||||||
|
From: addr,
|
||||||
|
To: client.DefaultKey.Address,
|
||||||
|
Value: big.Div(toSend, big.NewInt(2)),
|
||||||
|
}
|
||||||
|
|
||||||
|
secpSmsg, err := client.MpoolPushMessage(ctx, secpMsg, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
hash, err := ethtypes.EthHashFromCid(secpSmsg.Cid())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, hash, mpoolTx.Hash)
|
||||||
|
|
||||||
|
_, err = client.StateWaitMsg(ctx, secpSmsg.Cid(), 3, api.LookbackNoLimit, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
receipt, err := client.EthGetTransactionReceipt(ctx, hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, receipt)
|
||||||
|
require.Equal(t, hash, receipt.TransactionHash)
|
||||||
|
|
||||||
|
// Verify that the chain transaction now has new fields set.
|
||||||
|
chainTx, err := client.EthGetTransactionByHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, hash, chainTx.Hash)
|
||||||
|
|
||||||
|
// require that the hashes are identical
|
||||||
|
require.Equal(t, hash, chainTx.Hash)
|
||||||
|
require.NotNil(t, chainTx.BlockNumber)
|
||||||
|
require.Greater(t, uint64(*chainTx.BlockNumber), uint64(0))
|
||||||
|
require.NotNil(t, chainTx.BlockHash)
|
||||||
|
require.NotEmpty(t, *chainTx.BlockHash)
|
||||||
|
require.NotNil(t, chainTx.TransactionIndex)
|
||||||
|
require.Equal(t, uint64(*chainTx.TransactionIndex), uint64(0)) // only transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestTransactionHashLookupSecpFilecoinMessage tests to see if lotus can find a Secp Filecoin Message using the transaction hash
|
||||||
|
func TestTransactionHashLookupNonexistentMessage(t *testing.T) {
|
||||||
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
|
blocktime := 1 * time.Second
|
||||||
|
client, _, ens := kit.EnsembleMinimal(
|
||||||
|
t,
|
||||||
|
kit.MockProofs(),
|
||||||
|
kit.ThroughRPC(),
|
||||||
|
kit.EthTxHashLookup(),
|
||||||
|
)
|
||||||
|
ens.InterconnectAll().BeginMining(blocktime)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
cid := build.MustParseCid("bafk2bzacecapjnxnyw4talwqv5ajbtbkzmzqiosztj5cb3sortyp73ndjl76e")
|
||||||
|
|
||||||
|
// We shouldn't be able to return a hash for this fake cid
|
||||||
|
chainHash, err := client.EthGetTransactionHashByCid(ctx, cid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, chainHash)
|
||||||
|
|
||||||
|
calculatedHash, err := ethtypes.EthHashFromCid(cid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// We shouldn't be able to return a cid for this fake hash
|
||||||
|
chainCid, err := client.EthGetMessageCidByTransactionHash(ctx, &calculatedHash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Nil(t, chainCid)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEthGetMessageCidByTransactionHashEthTx(t *testing.T) {
|
||||||
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
|
blocktime := 1 * time.Second
|
||||||
|
client, _, ens := kit.EnsembleMinimal(
|
||||||
|
t,
|
||||||
|
kit.MockProofs(),
|
||||||
|
kit.ThroughRPC(),
|
||||||
|
kit.EthTxHashLookup(),
|
||||||
|
)
|
||||||
|
ens.InterconnectAll().BeginMining(blocktime)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// install contract
|
||||||
|
contractHex, err := os.ReadFile("./contracts/SimpleCoin.hex")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
contract, err := hex.DecodeString(string(contractHex))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// create a new Ethereum account
|
||||||
|
key, ethAddr, deployer := client.EVM().NewAccount()
|
||||||
|
|
||||||
|
// send some funds to the f410 address
|
||||||
|
kit.SendFunds(ctx, t, client, deployer, types.FromFil(10))
|
||||||
|
|
||||||
|
gaslimit, err := client.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||||
|
From: ðAddr,
|
||||||
|
Data: contract,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// now deploy a contract from the embryo, and validate it went well
|
||||||
|
tx := ethtypes.EthTxArgs{
|
||||||
|
ChainID: build.Eip155ChainId,
|
||||||
|
Value: big.Zero(),
|
||||||
|
Nonce: 0,
|
||||||
|
MaxFeePerGas: types.NanoFil,
|
||||||
|
MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas),
|
||||||
|
GasLimit: int(gaslimit),
|
||||||
|
Input: contract,
|
||||||
|
V: big.Zero(),
|
||||||
|
R: big.Zero(),
|
||||||
|
S: big.Zero(),
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EVM().SignTransaction(&tx, key.PrivateKey)
|
||||||
|
|
||||||
|
sender, err := tx.Sender()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
unsignedMessage, err := tx.ToUnsignedMessage(sender)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
rawTxHash, err := tx.TxHash()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
hash := client.EVM().SubmitTransaction(ctx, &tx)
|
||||||
|
require.Equal(t, rawTxHash, hash)
|
||||||
|
|
||||||
|
mpoolCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, mpoolCid)
|
||||||
|
|
||||||
|
mpoolTx, err := client.ChainGetMessage(ctx, *mpoolCid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, mpoolTx)
|
||||||
|
require.Equal(t, *unsignedMessage, *mpoolTx)
|
||||||
|
|
||||||
|
// Wait for message to land on chain
|
||||||
|
var receipt *api.EthTxReceipt
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
receipt, err = client.EthGetTransactionReceipt(ctx, hash)
|
||||||
|
if err != nil || receipt == nil {
|
||||||
|
time.Sleep(blocktime)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, receipt)
|
||||||
|
|
||||||
|
chainCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, chainCid)
|
||||||
|
|
||||||
|
chainTx, err := client.ChainGetMessage(ctx, *mpoolCid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, chainTx)
|
||||||
|
require.Equal(t, *unsignedMessage, *chainTx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEthGetMessageCidByTransactionHashSecp(t *testing.T) {
|
||||||
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
|
blocktime := 1 * time.Second
|
||||||
|
client, _, ens := kit.EnsembleMinimal(
|
||||||
|
t,
|
||||||
|
kit.MockProofs(),
|
||||||
|
kit.ThroughRPC(),
|
||||||
|
kit.EthTxHashLookup(),
|
||||||
|
)
|
||||||
|
ens.InterconnectAll().BeginMining(blocktime)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// get the existing balance from the default wallet to then split it.
|
||||||
|
bal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// create a new address where to send funds.
|
||||||
|
addr, err := client.WalletNew(ctx, types.KTSecp256k1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
toSend := big.Div(bal, big.NewInt(2))
|
||||||
|
setupMsg := &types.Message{
|
||||||
|
From: client.DefaultKey.Address,
|
||||||
|
To: addr,
|
||||||
|
Value: toSend,
|
||||||
|
}
|
||||||
|
|
||||||
|
setupSmsg, err := client.MpoolPushMessage(ctx, setupMsg, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = client.StateWaitMsg(ctx, setupSmsg.Cid(), 3, api.LookbackNoLimit, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Send message for secp account
|
||||||
|
secpMsg := &types.Message{
|
||||||
|
From: addr,
|
||||||
|
To: client.DefaultKey.Address,
|
||||||
|
Value: big.Div(toSend, big.NewInt(2)),
|
||||||
|
}
|
||||||
|
|
||||||
|
secpSmsg, err := client.MpoolPushMessage(ctx, secpMsg, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
hash, err := ethtypes.EthHashFromCid(secpSmsg.Cid())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
mpoolCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, mpoolCid)
|
||||||
|
|
||||||
|
mpoolTx, err := client.ChainGetMessage(ctx, *mpoolCid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, mpoolTx)
|
||||||
|
require.Equal(t, secpSmsg.Message, *mpoolTx)
|
||||||
|
|
||||||
|
_, err = client.StateWaitMsg(ctx, secpSmsg.Cid(), 3, api.LookbackNoLimit, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
chainCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, chainCid)
|
||||||
|
|
||||||
|
chainTx, err := client.ChainGetMessage(ctx, *mpoolCid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, chainTx)
|
||||||
|
require.Equal(t, secpSmsg.Message, *chainTx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEthGetMessageCidByTransactionHashBLS(t *testing.T) {
|
||||||
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
|
blocktime := 1 * time.Second
|
||||||
|
client, _, ens := kit.EnsembleMinimal(
|
||||||
|
t,
|
||||||
|
kit.MockProofs(),
|
||||||
|
kit.ThroughRPC(),
|
||||||
|
kit.EthTxHashLookup(),
|
||||||
|
)
|
||||||
|
ens.InterconnectAll().BeginMining(blocktime)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
// get the existing balance from the default wallet to then split it.
|
||||||
|
bal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// create a new address where to send funds.
|
||||||
|
addr, err := client.WalletNew(ctx, types.KTBLS)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
toSend := big.Div(bal, big.NewInt(2))
|
||||||
|
msg := &types.Message{
|
||||||
|
From: client.DefaultKey.Address,
|
||||||
|
To: addr,
|
||||||
|
Value: toSend,
|
||||||
|
}
|
||||||
|
|
||||||
|
sm, err := client.MpoolPushMessage(ctx, msg, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
hash, err := ethtypes.EthHashFromCid(sm.Cid())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
mpoolCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, mpoolCid)
|
||||||
|
|
||||||
|
mpoolTx, err := client.ChainGetMessage(ctx, *mpoolCid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, mpoolTx)
|
||||||
|
require.Equal(t, sm.Message, *mpoolTx)
|
||||||
|
|
||||||
|
_, err = client.StateWaitMsg(ctx, sm.Cid(), 3, api.LookbackNoLimit, true)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
chainCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, chainCid)
|
||||||
|
|
||||||
|
chainTx, err := client.ChainGetMessage(ctx, *mpoolCid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, chainTx)
|
||||||
|
require.Equal(t, sm.Message, *chainTx)
|
||||||
|
}
|
@ -21,7 +21,7 @@ import (
|
|||||||
|
|
||||||
func TestValueTransferValidSignature(t *testing.T) {
|
func TestValueTransferValidSignature(t *testing.T) {
|
||||||
blockTime := 100 * time.Millisecond
|
blockTime := 100 * time.Millisecond
|
||||||
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
|
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthTxHashLookup())
|
||||||
|
|
||||||
ens.InterconnectAll().BeginMining(blockTime)
|
ens.InterconnectAll().BeginMining(blockTime)
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ func TestLegacyTransaction(t *testing.T) {
|
|||||||
func TestContractDeploymentValidSignature(t *testing.T) {
|
func TestContractDeploymentValidSignature(t *testing.T) {
|
||||||
|
|
||||||
blockTime := 100 * time.Millisecond
|
blockTime := 100 * time.Millisecond
|
||||||
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
|
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthTxHashLookup())
|
||||||
|
|
||||||
ens.InterconnectAll().BeginMining(blockTime)
|
ens.InterconnectAll().BeginMining(blockTime)
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ func TestContractDeploymentValidSignature(t *testing.T) {
|
|||||||
|
|
||||||
func TestContractInvocation(t *testing.T) {
|
func TestContractInvocation(t *testing.T) {
|
||||||
blockTime := 100 * time.Millisecond
|
blockTime := 100 * time.Millisecond
|
||||||
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
|
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.EthTxHashLookup())
|
||||||
|
|
||||||
ens.InterconnectAll().BeginMining(blockTime)
|
ens.InterconnectAll().BeginMining(blockTime)
|
||||||
|
|
||||||
|
@ -296,3 +296,10 @@ func HistoricFilterAPI(dbpath string) NodeOpt {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EthTxHashLookup() NodeOpt {
|
||||||
|
return WithCfgOpt(func(cfg *config.FullNode) error {
|
||||||
|
cfg.Fevm.EnableEthHashToFilecoinCidMapping = true
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -161,7 +161,6 @@ var ChainNode = Options(
|
|||||||
Override(new(messagepool.Provider), messagepool.NewProvider),
|
Override(new(messagepool.Provider), messagepool.NewProvider),
|
||||||
Override(new(messagepool.MpoolNonceAPI), From(new(*messagepool.MessagePool))),
|
Override(new(messagepool.MpoolNonceAPI), From(new(*messagepool.MessagePool))),
|
||||||
Override(new(full.ChainModuleAPI), From(new(full.ChainModule))),
|
Override(new(full.ChainModuleAPI), From(new(full.ChainModule))),
|
||||||
Override(new(full.EthModuleAPI), From(new(full.EthModule))),
|
|
||||||
Override(new(full.GasModuleAPI), From(new(full.GasModule))),
|
Override(new(full.GasModuleAPI), From(new(full.GasModule))),
|
||||||
Override(new(full.MpoolModuleAPI), From(new(full.MpoolModule))),
|
Override(new(full.MpoolModuleAPI), From(new(full.MpoolModule))),
|
||||||
Override(new(full.StateModuleAPI), From(new(full.StateModule))),
|
Override(new(full.StateModuleAPI), From(new(full.StateModule))),
|
||||||
@ -261,6 +260,8 @@ func ConfigFullNode(c interface{}) Option {
|
|||||||
Override(new(events.EventAPI), From(new(modules.EventAPI))),
|
Override(new(events.EventAPI), From(new(modules.EventAPI))),
|
||||||
// in lite-mode Eth event api is provided by gateway
|
// in lite-mode Eth event api is provided by gateway
|
||||||
ApplyIf(isFullNode, Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.ActorEvent))),
|
ApplyIf(isFullNode, Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.ActorEvent))),
|
||||||
|
|
||||||
|
Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +107,10 @@ func DefaultFullNode() *FullNode {
|
|||||||
MaxFilterResults: 10000,
|
MaxFilterResults: 10000,
|
||||||
MaxFilterHeightRange: 2880, // conservative limit of one day
|
MaxFilterHeightRange: 2880, // conservative limit of one day
|
||||||
},
|
},
|
||||||
|
Fevm: FevmConfig{
|
||||||
|
EnableEthHashToFilecoinCidMapping: false,
|
||||||
|
EthTxHashMappingLifetimeDays: 0,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,6 +399,22 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
|
|||||||
Comment: ``,
|
Comment: ``,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"FevmConfig": []DocField{
|
||||||
|
{
|
||||||
|
Name: "EnableEthHashToFilecoinCidMapping",
|
||||||
|
Type: "bool",
|
||||||
|
|
||||||
|
Comment: `EnableEthHashToFilecoinCidMapping enables storing a mapping of eth transaction hashes to filecoin message Cids
|
||||||
|
You will not be able to look up ethereum transactions by their hash if this is disabled.`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "EthTxHashMappingLifetimeDays",
|
||||||
|
Type: "int",
|
||||||
|
|
||||||
|
Comment: `EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
|
||||||
|
Set to 0 to keep all mappings`,
|
||||||
|
},
|
||||||
|
},
|
||||||
"FullNode": []DocField{
|
"FullNode": []DocField{
|
||||||
{
|
{
|
||||||
Name: "Client",
|
Name: "Client",
|
||||||
@ -434,6 +450,12 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
|
|||||||
Name: "ActorEvent",
|
Name: "ActorEvent",
|
||||||
Type: "ActorEventConfig",
|
Type: "ActorEventConfig",
|
||||||
|
|
||||||
|
Comment: ``,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Fevm",
|
||||||
|
Type: "FevmConfig",
|
||||||
|
|
||||||
Comment: ``,
|
Comment: ``,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -28,6 +28,7 @@ type FullNode struct {
|
|||||||
Chainstore Chainstore
|
Chainstore Chainstore
|
||||||
Cluster UserRaftConfig
|
Cluster UserRaftConfig
|
||||||
ActorEvent ActorEventConfig
|
ActorEvent ActorEventConfig
|
||||||
|
Fevm FevmConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// // Common
|
// // Common
|
||||||
@ -692,3 +693,12 @@ type ActorEventConfig struct {
|
|||||||
// Set a timeout for subscription clients
|
// Set a timeout for subscription clients
|
||||||
// Set upper bound on index size
|
// Set upper bound on index size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FevmConfig struct {
|
||||||
|
// EnableEthHashToFilecoinCidMapping enables storing a mapping of eth transaction hashes to filecoin message Cids
|
||||||
|
// You will not be able to look up ethereum transactions by their hash if this is disabled.
|
||||||
|
EnableEthHashToFilecoinCidMapping bool
|
||||||
|
// EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
|
||||||
|
// Set to 0 to keep all mappings
|
||||||
|
EthTxHashMappingLifetimeDays int
|
||||||
|
}
|
||||||
|
@ -21,11 +21,13 @@ import (
|
|||||||
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||||
"github.com/filecoin-project/go-state-types/builtin/v10/eam"
|
"github.com/filecoin-project/go-state-types/builtin/v10/eam"
|
||||||
"github.com/filecoin-project/go-state-types/builtin/v10/evm"
|
"github.com/filecoin-project/go-state-types/builtin/v10/evm"
|
||||||
|
"github.com/filecoin-project/go-state-types/crypto"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin"
|
builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
"github.com/filecoin-project/lotus/chain/ethhashlookup"
|
||||||
"github.com/filecoin-project/lotus/chain/events/filter"
|
"github.com/filecoin-project/lotus/chain/events/filter"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
@ -43,6 +45,8 @@ type EthModuleAPI interface {
|
|||||||
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error)
|
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error)
|
||||||
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error)
|
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error)
|
||||||
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error)
|
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error)
|
||||||
|
EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error)
|
||||||
|
EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error)
|
||||||
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error)
|
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error)
|
||||||
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error)
|
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error)
|
||||||
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error)
|
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error)
|
||||||
@ -107,11 +111,10 @@ var (
|
|||||||
// accepts as the best parent tipset, based on the blocks it is accumulating
|
// accepts as the best parent tipset, based on the blocks it is accumulating
|
||||||
// within the HEAD tipset.
|
// within the HEAD tipset.
|
||||||
type EthModule struct {
|
type EthModule struct {
|
||||||
fx.In
|
Chain *store.ChainStore
|
||||||
|
Mpool *messagepool.MessagePool
|
||||||
Chain *store.ChainStore
|
StateManager *stmgr.StateManager
|
||||||
Mpool *messagepool.MessagePool
|
EthTxHashManager *EthTxHashManager
|
||||||
StateManager *stmgr.StateManager
|
|
||||||
|
|
||||||
ChainAPI
|
ChainAPI
|
||||||
MpoolAPI
|
MpoolAPI
|
||||||
@ -254,10 +257,21 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
cid := txHash.ToCid()
|
c := cid.Undef
|
||||||
|
if a.EthTxHashManager != nil {
|
||||||
|
var err error
|
||||||
|
c, err = a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("could not find transaction hash %s in lookup table", txHash.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This isn't an eth transaction we have the mapping for, so let's look it up as a filecoin message
|
||||||
|
if c == cid.Undef {
|
||||||
|
c = txHash.ToCid()
|
||||||
|
}
|
||||||
|
|
||||||
// first, try to get the cid from mined transactions
|
// first, try to get the cid from mined transactions
|
||||||
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, cid, api.LookbackNoLimit, true)
|
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, c, api.LookbackNoLimit, true)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI)
|
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -274,8 +288,8 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range pending {
|
for _, p := range pending {
|
||||||
if p.Cid() == cid {
|
if p.Cid() == c {
|
||||||
tx, err := newEthTxFromFilecoinMessage(ctx, p, a.StateAPI)
|
tx, err := NewEthTxFromFilecoinMessage(ctx, p, a.StateAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not convert Filecoin message into tx: %s", err)
|
return nil, fmt.Errorf("could not convert Filecoin message into tx: %s", err)
|
||||||
}
|
}
|
||||||
@ -286,6 +300,56 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *EthModule) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) {
|
||||||
|
// Ethereum's behavior is to return null when the txHash is invalid, so we use nil to check if txHash is valid
|
||||||
|
if txHash == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
c := cid.Undef
|
||||||
|
if a.EthTxHashManager != nil {
|
||||||
|
var err error
|
||||||
|
c, err = a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash)
|
||||||
|
// We fall out of the first condition and continue
|
||||||
|
if errors.Is(err, ethhashlookup.ErrNotFound) {
|
||||||
|
log.Debug("could not find transaction hash %s in lookup table", txHash.String())
|
||||||
|
} else if err != nil {
|
||||||
|
return nil, xerrors.Errorf("database error: %w", err)
|
||||||
|
} else {
|
||||||
|
return &c, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This isn't an eth transaction we have the mapping for, so let's try looking it up as a filecoin message
|
||||||
|
if c == cid.Undef {
|
||||||
|
c = txHash.ToCid()
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := a.StateAPI.Chain.GetSignedMessage(ctx, c)
|
||||||
|
if err == nil {
|
||||||
|
// This is an Eth Tx, Secp message, Or BLS message in the mpool
|
||||||
|
return &c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = a.StateAPI.Chain.GetMessage(ctx, c)
|
||||||
|
if err == nil {
|
||||||
|
// This is a BLS message
|
||||||
|
return &c, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ethereum clients expect an empty response when the message was not found
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *EthModule) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) {
|
||||||
|
hash, err := EthTxHashFromFilecoinMessageCid(ctx, cid, a.StateAPI)
|
||||||
|
if hash == ethtypes.EmptyEthHash {
|
||||||
|
// not found
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &hash, err
|
||||||
|
}
|
||||||
|
|
||||||
func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam string) (ethtypes.EthUint64, error) {
|
func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam string) (ethtypes.EthUint64, error) {
|
||||||
addr, err := sender.ToFilecoinAddress()
|
addr, err := sender.ToFilecoinAddress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -305,10 +369,21 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) {
|
func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) {
|
||||||
cid := txHash.ToCid()
|
c := cid.Undef
|
||||||
|
if a.EthTxHashManager != nil {
|
||||||
|
var err error
|
||||||
|
c, err = a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(txHash)
|
||||||
|
if err != nil {
|
||||||
|
log.Debug("could not find transaction hash %s in lookup table", txHash.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This isn't an eth transaction we have the mapping for, so let's look it up as a filecoin message
|
||||||
|
if c == cid.Undef {
|
||||||
|
c = txHash.ToCid()
|
||||||
|
}
|
||||||
|
|
||||||
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, cid, api.LookbackNoLimit, true)
|
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, c, api.LookbackNoLimit, true)
|
||||||
if err != nil {
|
if err != nil || msgLookup == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -317,7 +392,7 @@ func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtype
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
replay, err := a.StateAPI.StateReplay(ctx, types.EmptyTSK, cid)
|
replay, err := a.StateAPI.StateReplay(ctx, types.EmptyTSK, c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -640,11 +715,12 @@ func (a *EthModule) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.Et
|
|||||||
smsg.Message.Method = builtinactors.MethodSend
|
smsg.Message.Method = builtinactors.MethodSend
|
||||||
}
|
}
|
||||||
|
|
||||||
cid, err := a.MpoolAPI.MpoolPush(ctx, smsg)
|
_, err = a.MpoolAPI.MpoolPush(ctx, smsg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EmptyEthHash, err
|
return ethtypes.EmptyEthHash, err
|
||||||
}
|
}
|
||||||
return ethtypes.EthHashFromCid(cid)
|
|
||||||
|
return ethtypes.EthHashFromTxBytes(rawTx), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.EthCall) (*types.Message, error) {
|
func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.EthCall) (*types.Message, error) {
|
||||||
@ -791,7 +867,7 @@ func (e *EthEvent) EthGetLogs(ctx context.Context, filterSpec *ethtypes.EthFilte
|
|||||||
|
|
||||||
_ = e.uninstallFilter(ctx, f)
|
_ = e.uninstallFilter(ctx, f)
|
||||||
|
|
||||||
return ethFilterResultFromEvents(ces)
|
return ethFilterResultFromEvents(ces, e.SubManager.StateAPI)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EthEvent) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {
|
func (e *EthEvent) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {
|
||||||
@ -806,11 +882,11 @@ func (e *EthEvent) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilte
|
|||||||
|
|
||||||
switch fc := f.(type) {
|
switch fc := f.(type) {
|
||||||
case filterEventCollector:
|
case filterEventCollector:
|
||||||
return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx))
|
return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx), e.SubManager.StateAPI)
|
||||||
case filterTipSetCollector:
|
case filterTipSetCollector:
|
||||||
return ethFilterResultFromTipSets(fc.TakeCollectedTipSets(ctx))
|
return ethFilterResultFromTipSets(fc.TakeCollectedTipSets(ctx))
|
||||||
case filterMessageCollector:
|
case filterMessageCollector:
|
||||||
return ethFilterResultFromMessages(fc.TakeCollectedMessages(ctx))
|
return ethFilterResultFromMessages(fc.TakeCollectedMessages(ctx), e.SubManager.StateAPI)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, xerrors.Errorf("unknown filter type")
|
return nil, xerrors.Errorf("unknown filter type")
|
||||||
@ -828,7 +904,7 @@ func (e *EthEvent) EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID
|
|||||||
|
|
||||||
switch fc := f.(type) {
|
switch fc := f.(type) {
|
||||||
case filterEventCollector:
|
case filterEventCollector:
|
||||||
return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx))
|
return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx), e.SubManager.StateAPI)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, xerrors.Errorf("wrong filter type")
|
return nil, xerrors.Errorf("wrong filter type")
|
||||||
@ -1146,14 +1222,14 @@ type filterEventCollector interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type filterMessageCollector interface {
|
type filterMessageCollector interface {
|
||||||
TakeCollectedMessages(context.Context) []cid.Cid
|
TakeCollectedMessages(context.Context) []*types.SignedMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
type filterTipSetCollector interface {
|
type filterTipSetCollector interface {
|
||||||
TakeCollectedTipSets(context.Context) []types.TipSetKey
|
TakeCollectedTipSets(context.Context) []types.TipSetKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func ethFilterResultFromEvents(evs []*filter.CollectedEvent) (*ethtypes.EthFilterResult, error) {
|
func ethFilterResultFromEvents(evs []*filter.CollectedEvent, sa StateAPI) (*ethtypes.EthFilterResult, error) {
|
||||||
res := ðtypes.EthFilterResult{}
|
res := ðtypes.EthFilterResult{}
|
||||||
for _, ev := range evs {
|
for _, ev := range evs {
|
||||||
log := ethtypes.EthLog{
|
log := ethtypes.EthLog{
|
||||||
@ -1179,11 +1255,10 @@ func ethFilterResultFromEvents(evs []*filter.CollectedEvent) (*ethtypes.EthFilte
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.TransactionHash, err = ethtypes.EthHashFromCid(ev.MsgCid)
|
log.TransactionHash, err = EthTxHashFromFilecoinMessageCid(context.TODO(), ev.MsgCid, sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
c, err := ev.TipSetKey.Cid()
|
c, err := ev.TipSetKey.Cid()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -1218,11 +1293,11 @@ func ethFilterResultFromTipSets(tsks []types.TipSetKey) (*ethtypes.EthFilterResu
|
|||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ethFilterResultFromMessages(cs []cid.Cid) (*ethtypes.EthFilterResult, error) {
|
func ethFilterResultFromMessages(cs []*types.SignedMessage, sa StateAPI) (*ethtypes.EthFilterResult, error) {
|
||||||
res := ðtypes.EthFilterResult{}
|
res := ðtypes.EthFilterResult{}
|
||||||
|
|
||||||
for _, c := range cs {
|
for _, c := range cs {
|
||||||
hash, err := ethtypes.EthHashFromCid(c)
|
hash, err := EthTxHashFromSignedFilecoinMessage(context.TODO(), c, sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1321,7 +1396,7 @@ func (e *ethSubscription) start(ctx context.Context) {
|
|||||||
var err error
|
var err error
|
||||||
switch vt := v.(type) {
|
switch vt := v.(type) {
|
||||||
case *filter.CollectedEvent:
|
case *filter.CollectedEvent:
|
||||||
resp.Result, err = ethFilterResultFromEvents([]*filter.CollectedEvent{vt})
|
resp.Result, err = ethFilterResultFromEvents([]*filter.CollectedEvent{vt}, e.StateAPI)
|
||||||
case *types.TipSet:
|
case *types.TipSet:
|
||||||
eb, err := newEthBlockFromFilecoinTipSet(ctx, vt, true, e.Chain, e.ChainAPI, e.StateAPI)
|
eb, err := newEthBlockFromFilecoinTipSet(ctx, vt, true, e.Chain, e.ChainAPI, e.StateAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1396,18 +1471,15 @@ func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTx
|
|||||||
}
|
}
|
||||||
gasUsed += msgLookup.Receipt.GasUsed
|
gasUsed += msgLookup.Receipt.GasUsed
|
||||||
|
|
||||||
|
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, txIdx, cs, sa)
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EthBlock{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
if fullTxInfo {
|
if fullTxInfo {
|
||||||
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, txIdx, cs, sa)
|
|
||||||
if err != nil {
|
|
||||||
return ethtypes.EthBlock{}, nil
|
|
||||||
}
|
|
||||||
block.Transactions = append(block.Transactions, tx)
|
block.Transactions = append(block.Transactions, tx)
|
||||||
} else {
|
} else {
|
||||||
hash, err := ethtypes.EthHashFromCid(msg.Cid())
|
block.Transactions = append(block.Transactions, tx.Hash.String())
|
||||||
if err != nil {
|
|
||||||
return ethtypes.EthBlock{}, err
|
|
||||||
}
|
|
||||||
block.Transactions = append(block.Transactions, hash.String())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1459,19 +1531,42 @@ func lookupEthAddress(ctx context.Context, addr address.Address, sa StateAPI) (e
|
|||||||
return ethtypes.EthAddressFromFilecoinAddress(idAddr)
|
return ethtypes.EthAddressFromFilecoinAddress(idAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEthTxFromFilecoinMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthTx, error) {
|
func EthTxHashFromFilecoinMessageCid(ctx context.Context, c cid.Cid, sa StateAPI) (ethtypes.EthHash, error) {
|
||||||
fromEthAddr, err := lookupEthAddress(ctx, smsg.Message.From, sa)
|
smsg, err := sa.Chain.GetSignedMessage(ctx, c)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return ethtypes.EthTx{}, err
|
// This is an Eth Tx, Secp message, Or BLS message in the mpool
|
||||||
|
return EthTxHashFromSignedFilecoinMessage(ctx, smsg, sa)
|
||||||
}
|
}
|
||||||
|
|
||||||
toEthAddr, err := lookupEthAddress(ctx, smsg.Message.To, sa)
|
_, err = sa.Chain.GetMessage(ctx, c)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
return ethtypes.EthTx{}, err
|
// This is a BLS message
|
||||||
|
return ethtypes.EthHashFromCid(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ethtypes.EmptyEthHash, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func EthTxHashFromSignedFilecoinMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthHash, error) {
|
||||||
|
if smsg.Signature.Type == crypto.SigTypeDelegated {
|
||||||
|
ethTx, err := NewEthTxFromFilecoinMessage(ctx, smsg, sa)
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EmptyEthHash, err
|
||||||
|
}
|
||||||
|
return ethTx.Hash, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return ethtypes.EthHashFromCid(smsg.Cid())
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEthTxFromFilecoinMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthTx, error) {
|
||||||
|
// Ignore errors here so we can still parse non-eth messages
|
||||||
|
fromEthAddr, _ := lookupEthAddress(ctx, smsg.Message.From, sa)
|
||||||
|
toEthAddr, _ := lookupEthAddress(ctx, smsg.Message.To, sa)
|
||||||
|
|
||||||
toAddr := &toEthAddr
|
toAddr := &toEthAddr
|
||||||
input := smsg.Message.Params
|
input := smsg.Message.Params
|
||||||
|
var err error
|
||||||
// Check to see if we need to decode as contract deployment.
|
// Check to see if we need to decode as contract deployment.
|
||||||
// We don't need to resolve the to address, because there's only one form (an ID).
|
// We don't need to resolve the to address, because there's only one form (an ID).
|
||||||
if smsg.Message.To == builtintypes.EthereumAddressManagerActorAddr {
|
if smsg.Message.To == builtintypes.EthereumAddressManagerActorAddr {
|
||||||
@ -1510,26 +1605,38 @@ func newEthTxFromFilecoinMessage(ctx context.Context, smsg *types.SignedMessage,
|
|||||||
r, s, v = ethtypes.EthBigIntZero, ethtypes.EthBigIntZero, ethtypes.EthBigIntZero
|
r, s, v = ethtypes.EthBigIntZero, ethtypes.EthBigIntZero, ethtypes.EthBigIntZero
|
||||||
}
|
}
|
||||||
|
|
||||||
hash, err := ethtypes.EthHashFromCid(smsg.Cid())
|
|
||||||
if err != nil {
|
|
||||||
return ethtypes.EthTx{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tx := ethtypes.EthTx{
|
tx := ethtypes.EthTx{
|
||||||
Hash: hash,
|
|
||||||
Nonce: ethtypes.EthUint64(smsg.Message.Nonce),
|
Nonce: ethtypes.EthUint64(smsg.Message.Nonce),
|
||||||
ChainID: ethtypes.EthUint64(build.Eip155ChainId),
|
ChainID: ethtypes.EthUint64(build.Eip155ChainId),
|
||||||
From: fromEthAddr,
|
From: fromEthAddr,
|
||||||
To: toAddr,
|
To: toAddr,
|
||||||
Value: ethtypes.EthBigInt(smsg.Message.Value),
|
Value: ethtypes.EthBigInt(smsg.Message.Value),
|
||||||
Type: ethtypes.EthUint64(2),
|
Type: ethtypes.EthUint64(2),
|
||||||
|
Input: input,
|
||||||
Gas: ethtypes.EthUint64(smsg.Message.GasLimit),
|
Gas: ethtypes.EthUint64(smsg.Message.GasLimit),
|
||||||
MaxFeePerGas: ethtypes.EthBigInt(smsg.Message.GasFeeCap),
|
MaxFeePerGas: ethtypes.EthBigInt(smsg.Message.GasFeeCap),
|
||||||
MaxPriorityFeePerGas: ethtypes.EthBigInt(smsg.Message.GasPremium),
|
MaxPriorityFeePerGas: ethtypes.EthBigInt(smsg.Message.GasPremium),
|
||||||
V: v,
|
V: v,
|
||||||
R: r,
|
R: r,
|
||||||
S: s,
|
S: s,
|
||||||
Input: input,
|
}
|
||||||
|
|
||||||
|
// This is an eth tx
|
||||||
|
if smsg.Signature.Type == crypto.SigTypeDelegated {
|
||||||
|
tx.Hash, err = tx.TxHash()
|
||||||
|
if err != nil {
|
||||||
|
return tx, err
|
||||||
|
}
|
||||||
|
} else if smsg.Signature.Type == crypto.SigTypeUnknown { // BLS Filecoin message
|
||||||
|
tx.Hash, err = ethtypes.EthHashFromCid(smsg.Message.Cid())
|
||||||
|
if err != nil {
|
||||||
|
return tx, err
|
||||||
|
}
|
||||||
|
} else { // Secp Filecoin Message
|
||||||
|
tx.Hash, err = ethtypes.EthHashFromCid(smsg.Cid())
|
||||||
|
if err != nil {
|
||||||
|
return tx, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return tx, nil
|
return tx, nil
|
||||||
@ -1542,11 +1649,6 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
|
|||||||
if msgLookup == nil {
|
if msgLookup == nil {
|
||||||
return ethtypes.EthTx{}, fmt.Errorf("msg does not exist")
|
return ethtypes.EthTx{}, fmt.Errorf("msg does not exist")
|
||||||
}
|
}
|
||||||
cid := msgLookup.Message
|
|
||||||
txHash, err := ethtypes.EthHashFromCid(cid)
|
|
||||||
if err != nil {
|
|
||||||
return ethtypes.EthTx{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
ts, err := cs.LoadTipSet(ctx, msgLookup.TipSet)
|
ts, err := cs.LoadTipSet(ctx, msgLookup.TipSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1588,10 +1690,21 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
|
|||||||
|
|
||||||
smsg, err := cs.GetSignedMessage(ctx, msgLookup.Message)
|
smsg, err := cs.GetSignedMessage(ctx, msgLookup.Message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EthTx{}, err
|
// We couldn't find the signed message, it might be a BLS message, so search for a regular message.
|
||||||
|
msg, err := cs.GetMessage(ctx, msgLookup.Message)
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EthTx{}, err
|
||||||
|
}
|
||||||
|
smsg = &types.SignedMessage{
|
||||||
|
Message: *msg,
|
||||||
|
Signature: crypto.Signature{
|
||||||
|
Type: crypto.SigTypeUnknown,
|
||||||
|
Data: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, err := newEthTxFromFilecoinMessage(ctx, smsg, sa)
|
tx, err := NewEthTxFromFilecoinMessage(ctx, smsg, sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EthTx{}, err
|
return ethtypes.EthTx{}, err
|
||||||
}
|
}
|
||||||
@ -1602,7 +1715,6 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
|
|||||||
)
|
)
|
||||||
|
|
||||||
tx.ChainID = ethtypes.EthUint64(build.Eip155ChainId)
|
tx.ChainID = ethtypes.EthUint64(build.Eip155ChainId)
|
||||||
tx.Hash = txHash
|
|
||||||
tx.BlockHash = &blkHash
|
tx.BlockHash = &blkHash
|
||||||
tx.BlockNumber = &bn
|
tx.BlockNumber = &bn
|
||||||
tx.TransactionIndex = &ti
|
tx.TransactionIndex = &ti
|
||||||
@ -1706,6 +1818,84 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook
|
|||||||
return receipt, nil
|
return receipt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *EthTxHashManager) Apply(ctx context.Context, from, to *types.TipSet) error {
|
||||||
|
for _, blk := range to.Blocks() {
|
||||||
|
_, smsgs, err := m.StateAPI.Chain.MessagesForBlock(ctx, blk)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, smsg := range smsgs {
|
||||||
|
if smsg.Signature.Type != crypto.SigTypeDelegated {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
hash, err := EthTxHashFromSignedFilecoinMessage(ctx, smsg, m.StateAPI)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = m.TransactionHashLookup.UpsertHash(hash, smsg.Cid())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type EthTxHashManager struct {
|
||||||
|
StateAPI StateAPI
|
||||||
|
TransactionHashLookup *ethhashlookup.EthTxHashLookup
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *EthTxHashManager) Revert(ctx context.Context, from, to *types.TipSet) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WaitForMpoolUpdates(ctx context.Context, ch <-chan api.MpoolUpdate, manager *EthTxHashManager) {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case u := <-ch:
|
||||||
|
if u.Type != api.MpoolAdd {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if u.Message.Signature.Type != crypto.SigTypeDelegated {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
ethTx, err := NewEthTxFromFilecoinMessage(ctx, u.Message, manager.StateAPI)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("error converting filecoin message to eth tx: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = manager.TransactionHashLookup.UpsertHash(ethTx.Hash, u.Message.Cid())
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("error inserting tx mapping to db: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func EthTxHashGC(ctx context.Context, retentionDays int, manager *EthTxHashManager) {
|
||||||
|
if retentionDays == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
gcPeriod := 1 * time.Hour
|
||||||
|
for {
|
||||||
|
entriesDeleted, err := manager.TransactionHashLookup.DeleteEntriesOlderThan(retentionDays)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("error garbage collecting eth transaction hash database: %s", err)
|
||||||
|
}
|
||||||
|
log.Info("garbage collection run on eth transaction hash lookup database. %d entries deleted", entriesDeleted)
|
||||||
|
time.Sleep(gcPeriod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// decodeLogBytes decodes a CBOR-serialized array into its original form.
|
// decodeLogBytes decodes a CBOR-serialized array into its original form.
|
||||||
//
|
//
|
||||||
// This function swallows errors and returns the original array if it failed
|
// This function swallows errors and returns the original array if it failed
|
||||||
|
85
node/modules/ethmodule.go
Normal file
85
node/modules/ethmodule.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
package modules
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"go.uber.org/fx"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/ethhashlookup"
|
||||||
|
"github.com/filecoin-project/lotus/chain/events"
|
||||||
|
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||||
|
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||||
|
"github.com/filecoin-project/lotus/chain/store"
|
||||||
|
"github.com/filecoin-project/lotus/node/config"
|
||||||
|
"github.com/filecoin-project/lotus/node/impl/full"
|
||||||
|
"github.com/filecoin-project/lotus/node/modules/helpers"
|
||||||
|
"github.com/filecoin-project/lotus/node/repo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func EthModuleAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI, full.MpoolAPI) (*full.EthModule, error) {
|
||||||
|
return func(mctx helpers.MetricsCtx, r repo.LockedRepo, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi full.ChainAPI, mpoolapi full.MpoolAPI) (*full.EthModule, error) {
|
||||||
|
em := &full.EthModule{
|
||||||
|
Chain: cs,
|
||||||
|
Mpool: mp,
|
||||||
|
StateManager: sm,
|
||||||
|
ChainAPI: chainapi,
|
||||||
|
MpoolAPI: mpoolapi,
|
||||||
|
StateAPI: stateapi,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cfg.EnableEthHashToFilecoinCidMapping {
|
||||||
|
// mapping functionality disabled. Nothing to do here
|
||||||
|
return em, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
dbPath, err := r.SqlitePath()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
transactionHashLookup, err := ethhashlookup.NewTransactionHashLookup(filepath.Join(dbPath, "txhash.db"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
lc.Append(fx.Hook{
|
||||||
|
OnStop: func(ctx context.Context) error {
|
||||||
|
return transactionHashLookup.Close()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
ethTxHashManager := full.EthTxHashManager{
|
||||||
|
StateAPI: stateapi,
|
||||||
|
TransactionHashLookup: transactionHashLookup,
|
||||||
|
}
|
||||||
|
|
||||||
|
em.EthTxHashManager = ðTxHashManager
|
||||||
|
|
||||||
|
const ChainHeadConfidence = 1
|
||||||
|
|
||||||
|
ctx := helpers.LifecycleCtx(mctx, lc)
|
||||||
|
lc.Append(fx.Hook{
|
||||||
|
OnStart: func(context.Context) error {
|
||||||
|
ev, err := events.NewEventsWithConfidence(ctx, &evapi, ChainHeadConfidence)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tipset listener
|
||||||
|
_ = ev.Observe(ðTxHashManager)
|
||||||
|
|
||||||
|
ch, err := mp.Updates(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go full.WaitForMpoolUpdates(ctx, ch, ðTxHashManager)
|
||||||
|
go full.EthTxHashGC(ctx, cfg.EthTxHashMappingLifetimeDays, ðTxHashManager)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return em, nil
|
||||||
|
}
|
||||||
|
}
|
@ -37,6 +37,7 @@ const (
|
|||||||
fsDatastore = "datastore"
|
fsDatastore = "datastore"
|
||||||
fsLock = "repo.lock"
|
fsLock = "repo.lock"
|
||||||
fsKeystore = "keystore"
|
fsKeystore = "keystore"
|
||||||
|
fsSqlite = "sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewRepoTypeFromString(t string) RepoType {
|
func NewRepoTypeFromString(t string) RepoType {
|
||||||
@ -411,6 +412,10 @@ type fsLockedRepo struct {
|
|||||||
ssErr error
|
ssErr error
|
||||||
ssOnce sync.Once
|
ssOnce sync.Once
|
||||||
|
|
||||||
|
sqlPath string
|
||||||
|
sqlErr error
|
||||||
|
sqlOnce sync.Once
|
||||||
|
|
||||||
storageLk sync.Mutex
|
storageLk sync.Mutex
|
||||||
configLk sync.Mutex
|
configLk sync.Mutex
|
||||||
}
|
}
|
||||||
@ -515,6 +520,21 @@ func (fsr *fsLockedRepo) SplitstorePath() (string, error) {
|
|||||||
return fsr.ssPath, fsr.ssErr
|
return fsr.ssPath, fsr.ssErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fsr *fsLockedRepo) SqlitePath() (string, error) {
|
||||||
|
fsr.sqlOnce.Do(func() {
|
||||||
|
path := fsr.join(fsSqlite)
|
||||||
|
|
||||||
|
if err := os.MkdirAll(path, 0755); err != nil {
|
||||||
|
fsr.sqlErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fsr.sqlPath = path
|
||||||
|
})
|
||||||
|
|
||||||
|
return fsr.sqlPath, fsr.sqlErr
|
||||||
|
}
|
||||||
|
|
||||||
// join joins path elements with fsr.path
|
// join joins path elements with fsr.path
|
||||||
func (fsr *fsLockedRepo) join(paths ...string) string {
|
func (fsr *fsLockedRepo) join(paths ...string) string {
|
||||||
return filepath.Join(append([]string{fsr.path}, paths...)...)
|
return filepath.Join(append([]string{fsr.path}, paths...)...)
|
||||||
|
@ -69,6 +69,9 @@ type LockedRepo interface {
|
|||||||
// SplitstorePath returns the path for the SplitStore
|
// SplitstorePath returns the path for the SplitStore
|
||||||
SplitstorePath() (string, error)
|
SplitstorePath() (string, error)
|
||||||
|
|
||||||
|
// SqlitePath returns the path for the Sqlite database
|
||||||
|
SqlitePath() (string, error)
|
||||||
|
|
||||||
// Returns config in this repo
|
// Returns config in this repo
|
||||||
Config() (interface{}, error)
|
Config() (interface{}, error)
|
||||||
SetConfig(func(interface{})) error
|
SetConfig(func(interface{})) error
|
||||||
|
@ -277,6 +277,14 @@ func (lmem *lockedMemRepo) SplitstorePath() (string, error) {
|
|||||||
return splitstorePath, nil
|
return splitstorePath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lmem *lockedMemRepo) SqlitePath() (string, error) {
|
||||||
|
sqlitePath := filepath.Join(lmem.Path(), "sqlite")
|
||||||
|
if err := os.MkdirAll(sqlitePath, 0755); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return sqlitePath, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (lmem *lockedMemRepo) ListDatastores(ns string) ([]int64, error) {
|
func (lmem *lockedMemRepo) ListDatastores(ns string) ([]int64, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user