Merge branch 'release/v1.20.0' into asr/merge-release-into-master

This commit is contained in:
Aayush 2023-01-20 17:32:29 -05:00
commit 4f199ada40
74 changed files with 3718 additions and 1485 deletions

View File

@ -355,56 +355,6 @@ jobs:
- run: ./scripts/generate-checksums.sh
- run: ./scripts/publish-checksums.sh
build-appimage:
machine:
image: ubuntu-2004:202111-02
steps:
- checkout
- attach_workspace:
at: /tmp/workspace
- run:
name: Update Go
command: |
sudo rm -rf /usr/local/go && \
curl -L https://golang.org/dl/go`cat GO_VERSION_MIN`.linux-amd64.tar.gz -o /tmp/go.tar.gz && \
sudo tar -C /usr/local -xvf /tmp/go.tar.gz
- run: go version
- run:
name: install appimage-builder
command: |
# appimage-builder requires /dev/snd to exist. It creates containers during the testing phase
# that pass sound devices from the host to the testing container. (hard coded!)
# https://github.com/AppImageCrafters/appimage-builder/blob/master/appimagebuilder/modules/test/execution_test.py#L54
# Circleci doesn't provide a working sound device; this is enough to fake it.
if [ ! -e /dev/snd ]
then
sudo mkdir /dev/snd
sudo mknod /dev/snd/ControlC0 c 1 2
fi
# docs: https://appimage-builder.readthedocs.io/en/latest/intro/install.html
sudo apt update
sudo apt install -y python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace
sudo curl -Lo /usr/local/bin/appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
sudo chmod +x /usr/local/bin/appimagetool
sudo pip3 install appimage-builder
- run:
name: install lotus dependencies
command: sudo apt install ocl-icd-opencl-dev libhwloc-dev
- run:
name: build appimage
command: |
sed -i "s/version: latest/version: ${CIRCLE_TAG:-latest}/" AppImageBuilder.yml
make appimage
- run: |
mkdir -p /tmp/workspace/appimage && \
mv Lotus-*.AppImage /tmp/workspace/appimage/
- persist_to_workspace:
root: /tmp/workspace
paths:
- appimage
gofmt:
executor: golang
working_directory: ~/lotus
@ -572,7 +522,7 @@ jobs:
equal: [ mainnet, <<parameters.network>> ]
steps:
- when:
condition: <parameters.push>>
condition: <<parameters.push>>
steps:
- docker/build:
image: filecoin/<<parameters.image>>
@ -583,7 +533,7 @@ jobs:
command: |
docker push filecoin/<<parameters.image>>:<<parameters.channel>>
if [[ ! -z $CIRCLE_SHA ]]; then
docker image tag filecoin/<<parameters.image>>:<<parameters.channel>>> filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"
docker image tag filecoin/<<parameters.image>>:<<parameters.channel>> filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"
docker push filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"
fi
if [[ ! -z $CIRCLE_TAG ]]; then
@ -611,7 +561,7 @@ jobs:
- run:
name: Docker push
command: |
docker push filecoin/<<parameters.image>>:<<parameters.channel>>-<<parameters.network>>
docker push filecoin/<<parameters.image>>:<<parameters.channel>>
if [[ ! -z $CIRCLE_SHA ]]; then
docker image tag filecoin/<<parameters.image>>:<<parameters.channel>>-<<parameters.network>> filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"-<<parameters.network>>
docker push filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"-<<parameters.network>>
@ -785,6 +735,11 @@ workflows:
- build
suite: itest-eth_balance
target: "./itests/eth_balance_test.go"
- test:
name: test-itest-eth_block_hash
suite: itest-eth_block_hash
target: "./itests/eth_block_hash_test.go"
- test:
name: test-itest-eth_deploy
requires:
@ -797,6 +752,11 @@ workflows:
- build
suite: itest-eth_filter
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:
name: test-itest-eth_transactions
requires:
@ -1182,71 +1142,6 @@ workflows:
branches:
only:
- /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/
- build-appimage:
name: "Build AppImage"
filters:
branches:
only:
- /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/
tags:
only:
- /^v\d+\.\d+\.\d+(-rc\d+)?$/
- publish:
name: "Publish AppImage"
appimage: true
requires:
- "Build AppImage"
filters:
branches:
ignore:
- /.*/
tags:
only:
- /^v\d+\.\d+\.\d+(-rc\d+)?$/
- publish-snapcraft:
name: "Publish Snapcraft (lotus / stable)"
channel: stable
snap-name: lotus
filters:
branches:
ignore:
- /.*/
tags:
only:
- /^v\d+\.\d+\.\d+$/
- publish-snapcraft:
name: "Publish Snapcraft (lotus / candidate)"
channel: candidate
snap-name: lotus
filters:
branches:
ignore:
- /.*/
tags:
only:
- /^v\d+\.\d+\.\d+-rc\d+$/
- publish-snapcraft:
name: "Publish Snapcraft (lotus-filecoin / stable)"
channel: stable
snap-name: lotus-filecoin
filters:
branches:
ignore:
- /.*/
tags:
only:
- /^v\d+\.\d+\.\d+$/
- publish-snapcraft:
name: "Publish Snapcraft (lotus-filecoin / candidate)"
channel: candidate
snap-name: lotus-filecoin
filters:
branches:
ignore:
- /.*/
tags:
only:
- /^v\d+\.\d+\.\d+-rc\d+$/
- build-docker:
name: "Docker push (lotus-all-in-one / stable / mainnet)"
image: lotus-all-in-one
@ -1482,14 +1377,6 @@ workflows:
only:
- master
jobs:
- publish-snapcraft:
name: "Publish Snapcraft (lotus / edge)"
channel: edge
snap-name: lotus
- publish-snapcraft:
name: "Publish Snapcraft (lotus-filecoin / edge)"
channel: edge
snap-name: lotus-filecoin
- build-docker:
name: "Docker (lotus-all-in-one / nightly / mainnet)"
image: lotus-all-in-one

View File

@ -107,13 +107,11 @@ func main() {
// form the input data.
type data struct {
Networks []string
SnapNames []string
ItestFiles []string
UnitSuites map[string]string
}
in := data{
Networks: []string{"mainnet", "butterflynet", "calibnet", "debug"},
SnapNames: []string{"lotus", "lotus-filecoin"},
ItestFiles: itests,
UnitSuites: func() map[string]string {
ret := make(map[string]string)

View File

@ -355,56 +355,6 @@ jobs:
- run: ./scripts/generate-checksums.sh
- run: ./scripts/publish-checksums.sh
build-appimage:
machine:
image: ubuntu-2004:202111-02
steps:
- checkout
- attach_workspace:
at: /tmp/workspace
- run:
name: Update Go
command: |
sudo rm -rf /usr/local/go && \
curl -L https://golang.org/dl/go`cat GO_VERSION_MIN`.linux-amd64.tar.gz -o /tmp/go.tar.gz && \
sudo tar -C /usr/local -xvf /tmp/go.tar.gz
- run: go version
- run:
name: install appimage-builder
command: |
# appimage-builder requires /dev/snd to exist. It creates containers during the testing phase
# that pass sound devices from the host to the testing container. (hard coded!)
# https://github.com/AppImageCrafters/appimage-builder/blob/master/appimagebuilder/modules/test/execution_test.py#L54
# Circleci doesn't provide a working sound device; this is enough to fake it.
if [ ! -e /dev/snd ]
then
sudo mkdir /dev/snd
sudo mknod /dev/snd/ControlC0 c 1 2
fi
# docs: https://appimage-builder.readthedocs.io/en/latest/intro/install.html
sudo apt update
sudo apt install -y python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace
sudo curl -Lo /usr/local/bin/appimagetool https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
sudo chmod +x /usr/local/bin/appimagetool
sudo pip3 install appimage-builder
- run:
name: install lotus dependencies
command: sudo apt install ocl-icd-opencl-dev libhwloc-dev
- run:
name: build appimage
command: |
sed -i "s/version: latest/version: ${CIRCLE_TAG:-latest}/" AppImageBuilder.yml
make appimage
- run: |
mkdir -p /tmp/workspace/appimage && \
mv Lotus-*.AppImage /tmp/workspace/appimage/
- persist_to_workspace:
root: /tmp/workspace
paths:
- appimage
gofmt:
executor: golang
working_directory: ~/lotus
@ -572,7 +522,7 @@ jobs:
equal: [ mainnet, <<parameters.network>> ]
steps:
- when:
condition: <parameters.push>>
condition: <<parameters.push>>
steps:
- docker/build:
image: filecoin/<<parameters.image>>
@ -583,7 +533,7 @@ jobs:
command: |
docker push filecoin/<<parameters.image>>:<<parameters.channel>>
if [["[[ ! -z $CIRCLE_SHA ]]"]]; then
docker image tag filecoin/<<parameters.image>>:<<parameters.channel>>> filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"
docker image tag filecoin/<<parameters.image>>:<<parameters.channel>> filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"
docker push filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"
fi
if [["[[ ! -z $CIRCLE_TAG ]]"]]; then
@ -611,7 +561,7 @@ jobs:
- run:
name: Docker push
command: |
docker push filecoin/<<parameters.image>>:<<parameters.channel>>-<<parameters.network>>
docker push filecoin/<<parameters.image>>:<<parameters.channel>>
if [["[[ ! -z $CIRCLE_SHA ]]"]]; then
docker image tag filecoin/<<parameters.image>>:<<parameters.channel>>-<<parameters.network>> filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"-<<parameters.network>>
docker push filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"-<<parameters.network>>
@ -743,51 +693,6 @@ workflows:
branches:
only:
- /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/
- build-appimage:
name: "Build AppImage"
filters:
branches:
only:
- /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/
tags:
only:
- /^v\d+\.\d+\.\d+(-rc\d+)?$/
- publish:
name: "Publish AppImage"
appimage: true
requires:
- "Build AppImage"
filters:
branches:
ignore:
- /.*/
tags:
only:
- /^v\d+\.\d+\.\d+(-rc\d+)?$/
[[- range .SnapNames]]
- publish-snapcraft:
name: "Publish Snapcraft ([[.]] / stable)"
channel: stable
snap-name: [[.]]
filters:
branches:
ignore:
- /.*/
tags:
only:
- /^v\d+\.\d+\.\d+$/
- publish-snapcraft:
name: "Publish Snapcraft ([[.]] / candidate)"
channel: candidate
snap-name: [[.]]
filters:
branches:
ignore:
- /.*/
tags:
only:
- /^v\d+\.\d+\.\d+-rc\d+$/
[[- end]]
[[- range .Networks]]
- build-docker:
name: "Docker push (lotus-all-in-one / stable / [[.]])"
@ -890,12 +795,6 @@ workflows:
only:
- master
jobs:
[[- range .SnapNames]]
- publish-snapcraft:
name: "Publish Snapcraft ([[.]] / edge)"
channel: edge
snap-name: [[.]]
[[- end]]
[[- range .Networks]]
- build-docker:
name: "Docker (lotus-all-in-one / nightly / [[.]])"

View File

@ -84,12 +84,6 @@ butterflynet: build-devnets
interopnet: GOFLAGS+=-tags=interopnet
interopnet: build-devnets
wallabynet: GOFLAGS+=-tags=wallabynet
wallabynet: build-devnets
hyperspacenet: GOFLAGS+=-tags=hyperspacenet
hyperspacenet: build-devnets
lotus: $(BUILD_DEPS)
rm -f lotus
$(GOCC) build $(GOFLAGS) -o lotus ./cmd/lotus

View File

@ -778,6 +778,8 @@ type FullNode interface {
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
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
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

View File

@ -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)
}
// 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.
func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 string) (ethtypes.EthBytes, error) {
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)
}
// 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.
func (m *MockFullNode) EthGetTransactionReceipt(arg0 context.Context, arg1 ethtypes.EthHash) (*api.EthTxReceipt, error) {
m.ctrl.T.Helper()

View File

@ -253,6 +253,8 @@ type FullNodeStruct struct {
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"`
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"`
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"`
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
}
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) {
if s.Internal.EthGetStorageAt == nil {
return *new(ethtypes.EthBytes), ErrNotSupported
@ -2172,6 +2187,17 @@ func (s *FullNodeStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.Et
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) {
if s.Internal.EthGetTransactionReceipt == nil {
return nil, ErrNotSupported

View File

@ -1,6 +1,6 @@
#!/bin/bash
NETWORKS=(devnet mainnet caterpillarnet butterflynet testing testing-fake-proofs calibrationnet hyperspace)
NETWORKS=(devnet mainnet caterpillarnet butterflynet testing testing-fake-proofs calibrationnet)
set -e

Binary file not shown.

View File

@ -1,4 +0,0 @@
/dns4/de0.bootstrap.wallaby.network/tcp/1337/p2p/12D3KooWHAvUVk5XuxSwi2dNLWbTDDRSGeHxMuWdQ3SQpRuNHbLz
/dns4/de1.bootstrap.wallaby.network/tcp/1337/p2p/12D3KooWBRqtxhJCtiLmCwKgAQozJtdGinEDdJGoS5oHw7vCjMGc
/dns4/ca0.bootstrap.wallaby.network/tcp/1337/p2p/12D3KooWCApBpUk7EX9pmEfyky1gKC6N2KJ74S1AwFfvnkDqw3pK
/dns4/sg0.bootstrap.wallaby.network/tcp/1337/p2p/12D3KooWLnYqr4hRoNHBJQVXsFGkDoKuoVfw5R2ASw1bHzrWU5Px

View File

@ -53,14 +53,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, {
Network: "butterflynet",
Version: 10,
ManifestCid: MustParseCid("bafy2bzacecjs7xvhtejsh47b2tx2iwe7mbad4kxovbfs7a6wxfl47kcnl25bm"),
ManifestCid: MustParseCid("bafy2bzaced2wq4k4i2deknam6ehbynaoo37bhysud7eze7su3ftlaggwwjuje"),
Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzacebd5zetyjtragjwrv2nqktct6u2pmsi4eifbanovxohx3a7lszjxi"),
"cron": MustParseCid("bafk2bzacecrszortqkc7har77ssgajglymv6ftrqvmdko5h2yqqh5k2qospl2"),
"datacap": MustParseCid("bafk2bzacecapjnxnyw4talwqv5ajbtbkzmzqiosztj5cb3sortyp73ndjl76e"),
"eam": MustParseCid("bafk2bzaceavdyeveel5iohjg7t6twc2cbdo7bt3m5xajwtibekudyhzv2xojy"),
"eam": MustParseCid("bafk2bzacebsvtqzp7g7vpufbyqrwwcpuo2yu3y7kenm7auidyiwzcv6jdw724"),
"ethaccount": MustParseCid("bafk2bzacedl4pmkfxkzoqajs6im3ranmopozsmxjcxsnk3kwvd3vv7mfwwrf4"),
"evm": MustParseCid("bafk2bzacebgzvmvwv7rsnnhp3zhqbiqkumvyrc7pazfovpptgpgtqkalrli74"),
"evm": MustParseCid("bafk2bzacedx5wdyaihi22pwqqqtfxmuwh5acem46mzaep3znmhh5bsuqmxogq"),
"init": MustParseCid("bafk2bzacecbxp66q3ytjkg37nyv4rmzezbfaigvx4i5yhvqbm5gg4amjeaias"),
"multisig": MustParseCid("bafk2bzacecjltag3mn75dsnmrmopjow27buxqhabissowayqlmavrcfetqswc"),
"paymentchannel": MustParseCid("bafk2bzacednzxg263eqbl2imwz3uhujov63tjkffieyl4hl3dhrgxyhwep6hc"),
@ -110,14 +110,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, {
Network: "calibrationnet",
Version: 10,
ManifestCid: MustParseCid("bafy2bzaceaklxgrzd34i53rm4eeq6477nlq2ckpex27evftbsmjd2yrdbj4ba"),
ManifestCid: MustParseCid("bafy2bzacearpwvmcqlailxyq2d2wtzmtudxqhvfot77tbdqotek5qiq5hyhzg"),
Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzacea7zmrdz2rjbzlbmrmx3ko6pm3cbyqxxgogiqldsccbqffuok7m6s"),
"cron": MustParseCid("bafk2bzacec7bxugi7ouh75nglycy7qwdq7e2hnku3w6yafq4fwdwvvq2mtrl2"),
"datacap": MustParseCid("bafk2bzacedii4stmlo3ccdff7eevcolmgnuxy5ftkzbzwtkqa4iinlfzq4mei"),
"eam": MustParseCid("bafk2bzacea6du2tjdewnfd2zofjp342d2lw7rdl6hx4ejawup744kpym2xsf4"),
"eam": MustParseCid("bafk2bzacedykxiyewqijj5nksr7qi6o4wu5yz4rezb747ntql4rpidyfdpes4"),
"ethaccount": MustParseCid("bafk2bzacecgbcbh3uk7olcfdqo44no5nxxayeqnycdznrlekqigbifor2revm"),
"evm": MustParseCid("bafk2bzaceanxhvz5czs6xfunhbysbttmim5e7poftibsu53uqn4by5nqmdaj6"),
"evm": MustParseCid("bafk2bzaceau5n66rabegik55kymni6uyk7n7jb5eymfywybs543yifpl7du2m"),
"init": MustParseCid("bafk2bzacea7lxnvgxupwwgoxlmwtrca75w73qabe324wnwx43qranbgf5zdqo"),
"multisig": MustParseCid("bafk2bzacear5eu5gpbjlroqkmsgpqerzc4aemp2uqcaeq7s2h4ur4ucgpzesg"),
"paymentchannel": MustParseCid("bafk2bzacecwxuruxawcru7xfcx3rmt4hmhlfh4hi6jvfumerazz6jpvfmxxcw"),
@ -176,14 +176,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, {
Network: "caterpillarnet",
Version: 10,
ManifestCid: MustParseCid("bafy2bzaceawh5opc4uqctlzc6xnq3pb7ycchfqwprjysbfa5xlrmiicbbvkrm"),
ManifestCid: MustParseCid("bafy2bzacebxr4uvnf5g3373shjzbaca6pf4th6nnfubytjfbrlxcpvbjw4ane"),
Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzacedfms6w3ghqtljpgsfuiqa6ztjx7kcuin6myjezj6rypj3zjbqms6"),
"cron": MustParseCid("bafk2bzaceaganmlpozvy4jywigs46pfrtdmhjjey6uyhpurplqbasojsislba"),
"datacap": MustParseCid("bafk2bzacebafqqe3wv5ytkfwmqzbmchgem66pw6yq6rl7w6vlhqsbkxnisswq"),
"eam": MustParseCid("bafk2bzaceawl3twv7iontkiiwgezkub2vvgd7cprhv7wvgpqjpeh4o6ygshlg"),
"eam": MustParseCid("bafk2bzacedwk5eqczflcsuisqsyeomgkpg54olojjq2ieb2ozu5s45wfwluti"),
"ethaccount": MustParseCid("bafk2bzaceburkmtd63nmzxpux5rcxsbqr6x5didl2ce7al32g4tqrvo4pjz2i"),
"evm": MustParseCid("bafk2bzacea7tp4lop7ivhay3ozitkmxxurk74v4zse42ant47rh2uw5z3tq5e"),
"evm": MustParseCid("bafk2bzacedbroioygjnbjtc7ykcjjs4wfbwnaa6gkzubi7c5enifoqqqu66s6"),
"init": MustParseCid("bafk2bzaced23r54kwuebl7t6mdantbby5qpfduxwxfryeliof2enyqzhokix6"),
"multisig": MustParseCid("bafk2bzacebcn3rib6j6jvclys7dkf62hco45ssgamczkrtzt6xyewd6gt3mtu"),
"paymentchannel": MustParseCid("bafk2bzacecvas4leo44pqdguj22nnwqoqdgwajzrpm5d6ltkehc37ni6p6doq"),
@ -233,14 +233,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, {
Network: "devnet",
Version: 10,
ManifestCid: MustParseCid("bafy2bzacedfwwsn5weycwkqrnusc37m6ut2uf42z5qvbukl67wi76mqtgafw2"),
ManifestCid: MustParseCid("bafy2bzacebixrjysarwxdadewlllfp4rwfoejxstwdutghghei54uvuuxlsbq"),
Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzacebb5txxkfexeaxa2th3rckxsxchzyss3ijgqbicf265h7rre2rvhm"),
"cron": MustParseCid("bafk2bzacecotn4gwluhamoqwnzgbg7ogehv26o5xnhjzltnzfv6utrlyanzek"),
"datacap": MustParseCid("bafk2bzacea4hket2srrtbewkf3tip6ellwpxdfbrzt5u47y57i2k6iojqqgba"),
"eam": MustParseCid("bafk2bzacecrg5sjpnmk3nu3vqyegkmjnvsjoumptseuu7zabeggu745bd2kwo"),
"eam": MustParseCid("bafk2bzacecxm2gr6tevzzan6oqp6aiqydjm5b7eo34mlzo5jdm7mnlbbueikq"),
"ethaccount": MustParseCid("bafk2bzacedh4y3zvtgft3i6ift4rpptgr2dx67pvenowvq7yaspuf25gqgcdc"),
"evm": MustParseCid("bafk2bzacecrjgqoozymyoplrmtpi7bmkmggiqgpbgwkzooy2a67fjivuedm6a"),
"evm": MustParseCid("bafk2bzacec26myls7vg6anr5yjbb2r75dryhdzwlwnrhjcyuhahlaoxdrua6i"),
"init": MustParseCid("bafk2bzacedof2ckc6w2qboxzxv4w67njcug4ut4cq3nnlrfybzsvlgnp4kt24"),
"multisig": MustParseCid("bafk2bzacec4eqajjqhl53tnkbs7glu7njlbtlditi7lxhvw33ezmxk6jae46y"),
"paymentchannel": MustParseCid("bafk2bzacec6nvdprqja7dy3qp5islebbbh2ifiyg2p7arbe6pocjhfe6xwkfy"),
@ -299,14 +299,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, {
Network: "hyperspace",
Version: 10,
ManifestCid: MustParseCid("bafy2bzacedimb4dzty5tsyy3ucbcxai7crli452wn5cguhpmuelq74i4bffoo"),
ManifestCid: MustParseCid("bafy2bzaced6hc7ujjmypg6mkrxdmf32oh2udhmhpmwkqyxusdkxoi2uoodyxg"),
Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzacecim7uybic2qprbkjhowg7qkniv4zywj5h5g4u4ss72urco2akzuo"),
"cron": MustParseCid("bafk2bzaceahgq64awp4f7li3hdgimc4upqvdvltpmeywckvens33umcxt424a"),
"datacap": MustParseCid("bafk2bzacebkxn52ttooaslkwncijk3bgd3tm2zw7vijdhwvg2cxnxbrzmmq5e"),
"eam": MustParseCid("bafk2bzacedg5bnw3ic2ub4mb2agrvdowpqd7xyjv6v2ndlkugnrtjgzzfxqlw"),
"eam": MustParseCid("bafk2bzaceaftiqwpx6dcjfqxyq7pazn2p55diukf32pz74755vj7pgg5joexw"),
"ethaccount": MustParseCid("bafk2bzacealn5enbxyxbfs7gbsjbyma2zk3bcr7okvflxhpr753d4eh6ixooa"),
"evm": MustParseCid("bafk2bzacedljkrmazyewawpnddrkzrt55556374dw2pm2hokgkompgzw4vx5y"),
"evm": MustParseCid("bafk2bzacea6etsvrqejjl7uej5dxlswja5gxzqyggsjjvg27timvtiedf7nsg"),
"init": MustParseCid("bafk2bzacec55gyyaqjrw7zughywocgwcjvv6k5fijjpjw4xgckuqz6pjtff5a"),
"multisig": MustParseCid("bafk2bzaceblozbdzybdivvjdiid4jwm2jc6x5a66sunh2vvwsqba6wzqmr7i6"),
"paymentchannel": MustParseCid("bafk2bzacealcyke5a6n24efs6qe4iikynpk2twqssyugy7jcyf6p6shgw2iwa"),
@ -356,14 +356,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, {
Network: "mainnet",
Version: 10,
ManifestCid: MustParseCid("bafy2bzaceat4ut5xv3qn4lvvkvwvdn6gtlbnqzvueh67fjqlemw6eled5oqnc"),
ManifestCid: MustParseCid("bafy2bzacea5vylkbby7rb42fknkk4g4byhj7hkqlxp4z4urydi3vlpwsgllik"),
Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzacedsn6i2flkpk6sb4iuejo7gfl5n6fhsdawggtbsihlrrjtvs7oepu"),
"cron": MustParseCid("bafk2bzacecw4guere7ba2canyi2622lw52b5qbn7iubckcp5cwlmx2kw7qqwy"),
"datacap": MustParseCid("bafk2bzaceat2ncckd2jjjqcovd3ib4sylwff7jk7rlk6gr5d2gmrrc7isrmu2"),
"eam": MustParseCid("bafk2bzacebl7267zqf7aubpl7n6ligulayhz65dpgn3ii26b3wwjwytlsdc3i"),
"eam": MustParseCid("bafk2bzacebbpu5smjrjqpkrvvlhcpk23yvlovlndqmwzhfz5kuuph54tdw732"),
"ethaccount": MustParseCid("bafk2bzacedmwzkbytxfn7exmxxosomvix4mpyxrmupeqw45aofqmdq5q7mgqe"),
"evm": MustParseCid("bafk2bzacecrrwixyqwphxaybhy5zxuawkhncq5tgtuz2ind4bl22oivzjidoq"),
"evm": MustParseCid("bafk2bzacechkf43lmddynxmc35hvz5kwr3fdxrbg6fxbcvysfsihgiopbrb7o"),
"init": MustParseCid("bafk2bzacec6276d7ls3hhuqibqorn3yp45mv7hroczf3bgb6jkhmbb2zqt3bw"),
"multisig": MustParseCid("bafk2bzaceahggxrnjj3w3cgtko54srssqyhcs4x6y55ytego6jf2owg5piw3y"),
"paymentchannel": MustParseCid("bafk2bzaceaobaqjamso57bkjv3n4ilv7lfropgrncnnej666w3tegmr4cfgve"),
@ -413,14 +413,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, {
Network: "testing",
Version: 10,
ManifestCid: MustParseCid("bafy2bzacearh2dy6uzcfvruckai5qbf7banklkg6uezaa7w6onsmdfxn2qxbs"),
ManifestCid: MustParseCid("bafy2bzacea7tbn4p232ecrjvlp2uvpci5pexqjqq2vpv4t5ihktpja2zsj3ek"),
Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzaceds3iy5qjgr3stoywxt4uxvhybca23q7d2kxhitedgudrkhxaxa6o"),
"cron": MustParseCid("bafk2bzacebxp4whb4ocqxnbvqlz3kckarabtyvhjbhqvrdwhejuffwactyiss"),
"datacap": MustParseCid("bafk2bzacedepm3zas6vqryruwiz7d3axkneo7v66q65gf2dlpfd53pjlycrg4"),
"eam": MustParseCid("bafk2bzacedl4q6l3m5uvunuviwlxicyweszrahipxfpf3nt6wspvcdi4ryzyk"),
"eam": MustParseCid("bafk2bzacea2uascrtv6xnsqlxyf3tcf4onpgrs7frh55p6dnrdeum2uup7wx4"),
"ethaccount": MustParseCid("bafk2bzacecbhz4ipg773lsovgpjysm6fxl2i7y2wuxadqnt4s4vm3nd2qodb4"),
"evm": MustParseCid("bafk2bzaced5efc2bi7ulqsep4ej74hxwbjap2qi7lojiqzfsowxr4kylkwzk6"),
"evm": MustParseCid("bafk2bzaceabwn4i62od3i4qkuj5zx4vn5w5cbcl53tqnszk6kl43bfl55hl6c"),
"init": MustParseCid("bafk2bzacebqym5i5eciyyyzsimu73z6bkffpm5hzjpx3gwcm64pm2fh7okrja"),
"multisig": MustParseCid("bafk2bzacecmlyngek7qvj5ezaaitadrycapup3mbty4ijlzun6g23tcoysxle"),
"paymentchannel": MustParseCid("bafk2bzacedspin4hxpgnxkjen3hsxpcc52oc5q4ypukl4qq6vaytcgmmi7hl4"),
@ -470,14 +470,14 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, {
Network: "testing-fake-proofs",
Version: 10,
ManifestCid: MustParseCid("bafy2bzacedw6kk3u2vjexzqmm3vtvusd42lllk7wbnsrlxxmt35smsnmiatca"),
ManifestCid: MustParseCid("bafy2bzacecyqfyzmw72234rvbk6vzq2omnmt3cbfezkq2h3ewnn33w42b2s62"),
Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzaceds3iy5qjgr3stoywxt4uxvhybca23q7d2kxhitedgudrkhxaxa6o"),
"cron": MustParseCid("bafk2bzacebxp4whb4ocqxnbvqlz3kckarabtyvhjbhqvrdwhejuffwactyiss"),
"datacap": MustParseCid("bafk2bzacedepm3zas6vqryruwiz7d3axkneo7v66q65gf2dlpfd53pjlycrg4"),
"eam": MustParseCid("bafk2bzacedl4q6l3m5uvunuviwlxicyweszrahipxfpf3nt6wspvcdi4ryzyk"),
"eam": MustParseCid("bafk2bzacea2uascrtv6xnsqlxyf3tcf4onpgrs7frh55p6dnrdeum2uup7wx4"),
"ethaccount": MustParseCid("bafk2bzacecbhz4ipg773lsovgpjysm6fxl2i7y2wuxadqnt4s4vm3nd2qodb4"),
"evm": MustParseCid("bafk2bzaced5efc2bi7ulqsep4ej74hxwbjap2qi7lojiqzfsowxr4kylkwzk6"),
"evm": MustParseCid("bafk2bzaceabwn4i62od3i4qkuj5zx4vn5w5cbcl53tqnszk6kl43bfl55hl6c"),
"init": MustParseCid("bafk2bzacebqym5i5eciyyyzsimu73z6bkffpm5hzjpx3gwcm64pm2fh7okrja"),
"multisig": MustParseCid("bafk2bzacecmlyngek7qvj5ezaaitadrycapup3mbty4ijlzun6g23tcoysxle"),
"paymentchannel": MustParseCid("bafk2bzacedspin4hxpgnxkjen3hsxpcc52oc5q4ypukl4qq6vaytcgmmi7hl4"),

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,94 +0,0 @@
//go:build hyperspacenet
// +build hyperspacenet
package build
import (
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/go-state-types/network"
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/policy"
)
var NetworkBundle = "hyperspace"
var BundleOverrides map[actorstypes.Version]string
var ActorDebugging = false
const BootstrappersFile = "hyperspacenet.pi"
const GenesisFile = "hyperspacenet.car"
const GenesisNetworkVersion = network.Version18
var UpgradeBreezeHeight = abi.ChainEpoch(-1)
const BreezeGasTampingDuration = 120
var UpgradeSmokeHeight = abi.ChainEpoch(-1)
var UpgradeIgnitionHeight = abi.ChainEpoch(-2)
var UpgradeRefuelHeight = abi.ChainEpoch(-3)
var UpgradeTapeHeight = abi.ChainEpoch(-4)
var UpgradeAssemblyHeight = abi.ChainEpoch(-5)
var UpgradeLiftoffHeight = abi.ChainEpoch(-6)
var UpgradeKumquatHeight = abi.ChainEpoch(-7)
var UpgradeCalicoHeight = abi.ChainEpoch(-9)
var UpgradePersianHeight = abi.ChainEpoch(-10)
var UpgradeOrangeHeight = abi.ChainEpoch(-11)
var UpgradeClausHeight = abi.ChainEpoch(-12)
var UpgradeTrustHeight = abi.ChainEpoch(-13)
var UpgradeNorwegianHeight = abi.ChainEpoch(-14)
var UpgradeTurboHeight = abi.ChainEpoch(-15)
var UpgradeHyperdriveHeight = abi.ChainEpoch(-16)
var UpgradeChocolateHeight = abi.ChainEpoch(-17)
var UpgradeOhSnapHeight = abi.ChainEpoch(-18)
var UpgradeSkyrHeight = abi.ChainEpoch(-19)
var UpgradeSharkHeight = abi.ChainEpoch(-20)
var UpgradeHyggeHeight = abi.ChainEpoch(-21)
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
}
var SupportedProofTypes = []abi.RegisteredSealProof{
abi.RegisteredSealProof_StackedDrg512MiBV1,
abi.RegisteredSealProof_StackedDrg32GiBV1,
abi.RegisteredSealProof_StackedDrg64GiBV1,
}
var ConsensusMinerMinPower = abi.NewStoragePower(16 << 30)
var MinVerifiedDealSize = abi.NewStoragePower(1 << 20)
var PreCommitChallengeDelay = abi.ChainEpoch(10)
func init() {
policy.SetSupportedProofTypes(SupportedProofTypes...)
policy.SetConsensusMinerMinPower(ConsensusMinerMinPower)
policy.SetMinVerifiedDealSize(MinVerifiedDealSize)
policy.SetPreCommitChallengeDelay(PreCommitChallengeDelay)
BuildType = BuildHyperspacenet
SetAddressNetwork(address.Testnet)
Devnet = true
}
const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds)
const PropagationDelaySecs = uint64(6)
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
const BootstrapPeerThreshold = 2
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
// As per https://github.com/ethereum-lists/chains
const Eip155ChainId = 3141
var WhitelistedBlock = cid.Undef

View File

@ -1,5 +1,5 @@
//go:build !debug && !2k && !testground && !calibnet && !butterflynet && !interopnet && !wallabynet && !hyperspacenet
// +build !debug,!2k,!testground,!calibnet,!butterflynet,!interopnet,!wallabynet,!hyperspacenet
//go:build !debug && !2k && !testground && !calibnet && !butterflynet && !interopnet
// +build !debug,!2k,!testground,!calibnet,!butterflynet,!interopnet
package build

View File

@ -42,9 +42,6 @@ var (
AllowableClockDriftSecs = uint64(1)
Finality = policy.ChainFinality
ForkLengthThreshold = Finality
SlashablePowerDelay = 20
InteractivePoRepConfidence = 6
@ -130,6 +127,9 @@ var (
GenesisFile = ""
)
const Finality = policy.ChainFinality
const ForkLengthThreshold = Finality
const BootstrapPeerThreshold = 1
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.

View File

@ -1,94 +0,0 @@
//go:build wallabynet
// +build wallabynet
package build
import (
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi"
actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/go-state-types/network"
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
"github.com/filecoin-project/lotus/chain/actors/policy"
)
var NetworkBundle = "wallaby"
var BundleOverrides map[actorstypes.Version]string
var ActorDebugging = false
const BootstrappersFile = "wallabynet.pi"
const GenesisFile = "wallabynet.car"
const GenesisNetworkVersion = network.Version18
var UpgradeBreezeHeight = abi.ChainEpoch(-1)
const BreezeGasTampingDuration = 120
var UpgradeSmokeHeight = abi.ChainEpoch(-1)
var UpgradeIgnitionHeight = abi.ChainEpoch(-2)
var UpgradeRefuelHeight = abi.ChainEpoch(-3)
var UpgradeTapeHeight = abi.ChainEpoch(-4)
var UpgradeAssemblyHeight = abi.ChainEpoch(-5)
var UpgradeLiftoffHeight = abi.ChainEpoch(-6)
var UpgradeKumquatHeight = abi.ChainEpoch(-7)
var UpgradeCalicoHeight = abi.ChainEpoch(-9)
var UpgradePersianHeight = abi.ChainEpoch(-10)
var UpgradeOrangeHeight = abi.ChainEpoch(-11)
var UpgradeClausHeight = abi.ChainEpoch(-12)
var UpgradeTrustHeight = abi.ChainEpoch(-13)
var UpgradeNorwegianHeight = abi.ChainEpoch(-14)
var UpgradeTurboHeight = abi.ChainEpoch(-15)
var UpgradeHyperdriveHeight = abi.ChainEpoch(-16)
var UpgradeChocolateHeight = abi.ChainEpoch(-17)
var UpgradeOhSnapHeight = abi.ChainEpoch(-18)
var UpgradeSkyrHeight = abi.ChainEpoch(-19)
var UpgradeSharkHeight = abi.ChainEpoch(-20)
var UpgradeHyggeHeight = abi.ChainEpoch(-21)
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet,
}
var SupportedProofTypes = []abi.RegisteredSealProof{
abi.RegisteredSealProof_StackedDrg512MiBV1,
abi.RegisteredSealProof_StackedDrg32GiBV1,
abi.RegisteredSealProof_StackedDrg64GiBV1,
}
var ConsensusMinerMinPower = abi.NewStoragePower(16 << 30)
var MinVerifiedDealSize = abi.NewStoragePower(1 << 20)
var PreCommitChallengeDelay = abi.ChainEpoch(10)
func init() {
policy.SetSupportedProofTypes(SupportedProofTypes...)
policy.SetConsensusMinerMinPower(ConsensusMinerMinPower)
policy.SetMinVerifiedDealSize(MinVerifiedDealSize)
policy.SetPreCommitChallengeDelay(PreCommitChallengeDelay)
BuildType = BuildWallabynet
SetAddressNetwork(address.Testnet)
Devnet = true
}
const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds)
const PropagationDelaySecs = uint64(6)
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
const BootstrapPeerThreshold = 2
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
// As per https://github.com/ethereum-lists/chains
const Eip155ChainId = 31415
var WhitelistedBlock = cid.Undef

View File

@ -6,15 +6,13 @@ var CurrentCommit string
var BuildType int
const (
BuildDefault = 0
BuildMainnet = 0x1
Build2k = 0x2
BuildDebug = 0x3
BuildCalibnet = 0x4
BuildInteropnet = 0x5
BuildButterflynet = 0x7
BuildWallabynet = 0x8
BuildHyperspacenet = 0x9
BuildDefault = 0
BuildMainnet = 0x1
Build2k = 0x2
BuildDebug = 0x3
BuildCalibnet = 0x4
BuildInteropnet = 0x5
BuildButterflynet = 0x7
)
func BuildTypeString() string {
@ -33,10 +31,6 @@ func BuildTypeString() string {
return "+interopnet"
case BuildButterflynet:
return "+butterflynet"
case BuildWallabynet:
return "+wallabynet"
case BuildHyperspacenet:
return "+hyperspacenet"
default:
return "+huh?"
}

View 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()
}

View File

@ -100,9 +100,18 @@ func (f *EventFilter) CollectEvents(ctx context.Context, te *TipSetEvents, rever
continue
}
decodedEntries := make([]types.EventEntry, len(ev.Entries))
for i, entry := range ev.Entries {
decodedEntries[i] = types.EventEntry{
Flags: entry.Flags,
Key: entry.Key,
Value: decodeLogBytes(entry.Value),
}
}
// event matches filter, so record it
cev := &CollectedEvent{
Entries: ev.Entries,
Entries: decodedEntries,
EmitterAddr: addr,
EventIdx: evIdx,
Reverted: revert,
@ -266,13 +275,13 @@ func (te *TipSetEvents) messages(ctx context.Context) ([]executedMessage, error)
}
type executedMessage struct {
msg *types.Message
msg types.ChainMsg
rct *types.MessageReceipt
// events extracted from receipt
evs []*types.Event
}
func (e *executedMessage) Message() *types.Message {
func (e *executedMessage) Message() types.ChainMsg {
return e.msg
}
@ -428,7 +437,7 @@ func (m *EventFilterManager) loadExecutedMessages(ctx context.Context, msgTs, rc
ems := make([]executedMessage, len(msgs))
for i := 0; i < len(msgs); i++ {
ems[i].msg = msgs[i].VMMessage()
ems[i].msg = msgs[i]
var rct types.MessageReceipt
found, err := arr.Get(uint64(i), &rct)

View File

@ -225,7 +225,7 @@ func (ei *EventIndex) CollectEvents(ctx context.Context, te *TipSetEvents, rever
// This function swallows errors and returns the original array if it failed
// to decode.
func decodeLogBytes(orig []byte) []byte {
if orig == nil {
if len(orig) == 0 {
return orig
}
decoded, err := cbg.ReadByteArray(bytes.NewReader(orig), uint64(len(orig)))

View File

@ -5,7 +5,6 @@ import (
"sync"
"time"
"github.com/ipfs/go-cid"
"golang.org/x/xerrors"
"github.com/filecoin-project/lotus/api"
@ -18,7 +17,7 @@ type MemPoolFilter struct {
ch chan<- interface{}
mu sync.Mutex
collected []cid.Cid
collected []*types.SignedMessage
lastTaken time.Time
}
@ -55,10 +54,10 @@ func (f *MemPoolFilter) CollectMessage(ctx context.Context, msg *types.SignedMes
copy(f.collected, 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()
collected := f.collected
f.collected = nil

View File

@ -13,10 +13,13 @@ import (
"golang.org/x/xerrors"
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/messagepool"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/chain/wallet/key"
"github.com/filecoin-project/lotus/node/modules/dtypes"
)
@ -66,15 +69,24 @@ func (ms *MessageSigner) SignMessage(ctx context.Context, msg *types.Message, sp
// Sign the message with the nonce
msg.Nonce = nonce
keyInfo, err := ms.wallet.WalletExport(ctx, msg.From)
if err != nil {
return nil, err
}
sb, err := SigningBytes(msg, key.ActSigType(keyInfo.Type))
if err != nil {
return nil, err
}
mb, err := msg.ToStorageBlock()
if err != nil {
return nil, xerrors.Errorf("serializing message: %w", err)
}
sig, err := ms.wallet.WalletSign(ctx, msg.From, mb.Cid().Bytes(), api.MsgMeta{
sig, err := ms.wallet.WalletSign(ctx, msg.From, sb, api.MsgMeta{
Type: api.MTChainMsg,
Extra: mb.RawData(),
})
if err != nil {
return nil, xerrors.Errorf("failed to sign message: %w, addr=%s", err, msg.From)
}
@ -187,3 +199,19 @@ func (ms *MessageSigner) SaveNonce(ctx context.Context, addr address.Address, no
func (ms *MessageSigner) dstoreKey(addr address.Address) datastore.Key {
return datastore.KeyWithNamespaces([]string{dsKeyActorNonce, addr.String()})
}
func SigningBytes(msg *types.Message, sigType crypto.SigType) ([]byte, error) {
if sigType == crypto.SigTypeDelegated {
txArgs, err := ethtypes.EthTxArgsFromMessage(msg)
if err != nil {
return nil, xerrors.Errorf("failed to reconstruct eth transaction: %w", err)
}
rlpEncodedMsg, err := txArgs.ToRlpUnsignedMsg()
if err != nil {
return nil, xerrors.Errorf("failed to repack eth rlp message: %w", err)
}
return rlpEncodedMsg, nil
}
return msg.Cid().Bytes(), nil
}

View File

@ -22,6 +22,8 @@ import (
"github.com/filecoin-project/lotus/chain/types"
)
const TipsetkeyBackfillRange = 2 * build.Finality
func (cs *ChainStore) UnionStore() bstore.Blockstore {
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)
}
ts := root
for i := 0; i < int(TipsetkeyBackfillRange); 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
}

View File

@ -384,7 +384,19 @@ func (cs *ChainStore) PutTipSet(ctx context.Context, ts *types.TipSet) error {
if err != nil {
return xerrors.Errorf("errored while expanding tipset: %w", err)
}
log.Debugf("expanded %s into %s\n", ts.Cids(), expanded.Cids())
if expanded.Key() != ts.Key() {
log.Debugf("expanded %s into %s\n", ts.Cids(), expanded.Cids())
tsBlk, err := expanded.Key().ToStorageBlock()
if err != nil {
return xerrors.Errorf("failed to get tipset key block: %w", err)
}
if err = cs.chainLocalBlockstore.Put(ctx, tsBlk); err != nil {
return xerrors.Errorf("failed to put tipset key block: %w", err)
}
}
if err := cs.MaybeTakeHeavierTipSet(ctx, expanded); err != nil {
return xerrors.Errorf("MaybeTakeHeavierTipSet failed in PutTipSet: %w", err)
@ -1097,6 +1109,10 @@ func (cs *ChainStore) StateBlockstore() bstore.Blockstore {
return cs.stateBlockstore
}
func (cs *ChainStore) ChainLocalBlockstore() bstore.Blockstore {
return cs.chainLocalBlockstore
}
func ActorStore(ctx context.Context, bs bstore.Blockstore) adt.Store {
return adt.WrapStore(ctx, cbor.NewCborStore(bs))
}

View File

@ -8,6 +8,7 @@ import (
"testing"
"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/crypto"
@ -125,6 +126,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) {
//stm: @CHAIN_GEN_NEXT_TIPSET_001
//stm: @CHAIN_STORE_IMPORT_001, @CHAIN_STORE_EXPORT_001, @CHAIN_STORE_SET_HEAD_001

View File

@ -231,6 +231,36 @@ func (tx *EthTxArgs) ToRlpUnsignedMsg() ([]byte, error) {
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 (&ethTxArgs).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) {
packed1, err := tx.packTxFields()
if err != nil {

View File

@ -36,10 +36,7 @@ var ErrInvalidAddress = errors.New("invalid Filecoin Eth address")
type EthUint64 uint64
func (e EthUint64) MarshalJSON() ([]byte, error) {
if e == 0 {
return json.Marshal("0x0")
}
return json.Marshal(fmt.Sprintf("0x%x", e))
return json.Marshal(e.Hex())
}
func (e *EthUint64) UnmarshalJSON(b []byte) error {
@ -64,6 +61,13 @@ func EthUint64FromHex(s string) (EthUint64, error) {
return EthUint64(parsedInt), nil
}
func (e EthUint64) Hex() string {
if e == 0 {
return "0x0"
}
return fmt.Sprintf("0x%x", e)
}
// EthBigInt represents a large integer whose zero value serializes to "0x0".
type EthBigInt big.Int
@ -360,14 +364,7 @@ func (h *EthHash) UnmarshalJSON(b []byte) error {
}
func decodeHexString(s string, expectedLen int) ([]byte, error) {
// Strip the leading 0x or 0X prefix since hex.DecodeString does not support it.
if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") {
s = s[2:]
}
// Sometimes clients will omit a leading zero in a byte; pad so we can decode correctly.
if len(s)%2 == 1 {
s = "0" + s
}
s = handleHexStringPrefix(s)
if len(s) != expectedLen*2 {
return nil, xerrors.Errorf("expected hex string length sans prefix %d, got %d", expectedLen*2, len(s))
}
@ -378,6 +375,27 @@ func decodeHexString(s string, expectedLen int) ([]byte, error) {
return b, nil
}
func DecodeHexString(s string) ([]byte, error) {
s = handleHexStringPrefix(s)
b, err := hex.DecodeString(s)
if err != nil {
return nil, xerrors.Errorf("cannot parse hex value: %w", err)
}
return b, nil
}
func handleHexStringPrefix(s string) string {
// Strip the leading 0x or 0X prefix since hex.DecodeString does not support it.
if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") {
s = s[2:]
}
// Sometimes clients will omit a leading zero in a byte; pad so we can decode correctly.
if len(s)%2 == 1 {
s = "0" + s
}
return s
}
func EthHashFromCid(c cid.Cid) (EthHash, error) {
return ParseEthHash(c.Hash().HexString()[8:])
}
@ -392,10 +410,21 @@ func ParseEthHash(s string) (EthHash, error) {
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 {
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 {
// err is always nil
mh, _ := multihash.EncodeName(h[:], "blake2b-256")
@ -556,7 +585,7 @@ type EthLog struct {
// The index corresponds to the sequence of messages produced by ChainGetParentMessages
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"`
// BlockHash is the hash of the tipset containing the message that produced the log.

View File

@ -38,25 +38,13 @@ var EvmCmd = &cli.Command{
}
var EvmGetInfoCmd = &cli.Command{
Name: "stat",
Usage: "Print eth/filecoin addrs and code cid",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "filAddr",
Usage: "Filecoin address",
},
&cli.StringFlag{
Name: "ethAddr",
Usage: "Ethereum address",
},
},
Name: "stat",
Usage: "Print eth/filecoin addrs and code cid",
ArgsUsage: "address",
Action: func(cctx *cli.Context) error {
filAddr := cctx.String("filAddr")
ethAddr := cctx.String("ethAddr")
var faddr address.Address
var eaddr ethtypes.EthAddress
if cctx.NArg() != 1 {
return IncorrectNumArgs(cctx)
}
api, closer, err := GetFullNodeAPI(cctx)
if err != nil {
@ -65,26 +53,25 @@ var EvmGetInfoCmd = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if filAddr != "" {
addr, err := address.NewFromString(filAddr)
if err != nil {
return err
}
eaddr, faddr, err = ethAddrFromFilecoinAddress(ctx, addr, api)
if err != nil {
return err
}
} else if ethAddr != "" {
eaddr, err = ethtypes.ParseEthAddress(ethAddr)
if err != nil {
return err
addrString := cctx.Args().Get(0)
var faddr address.Address
var eaddr ethtypes.EthAddress
addr, err := address.NewFromString(addrString)
if err != nil { // This isn't a filecoin address
eaddr, err = ethtypes.ParseEthAddress(addrString)
if err != nil { // This isn't an Eth address either
return xerrors.Errorf("address is not a filecoin or eth address")
}
faddr, err = eaddr.ToFilecoinAddress()
if err != nil {
return err
}
} else {
return xerrors.Errorf("Neither filAddr nor ethAddr specified")
eaddr, faddr, err = ethAddrFromFilecoinAddress(ctx, addr, api)
if err != nil {
return err
}
}
actor, err := api.StateGetActor(ctx, faddr, types.EmptyTSK)
@ -97,7 +84,6 @@ var EvmGetInfoCmd = &cli.Command{
fmt.Println("Code cid: ", actor.Code.String())
return nil
},
}
@ -121,7 +107,7 @@ var EvmCallSimulateCmd = &cli.Command{
return err
}
params, err := hex.DecodeString(cctx.Args().Get(2))
params, err := ethtypes.DecodeHexString(cctx.Args().Get(2))
if err != nil {
return err
}
@ -165,7 +151,7 @@ var EvmGetContractAddress = &cli.Command{
return err
}
salt, err := hex.DecodeString(cctx.Args().Get(1))
salt, err := ethtypes.DecodeHexString(cctx.Args().Get(1))
if err != nil {
return xerrors.Errorf("Could not decode salt: %w", err)
}
@ -184,7 +170,7 @@ var EvmGetContractAddress = &cli.Command{
return err
}
contract, err := hex.DecodeString(string(contractHex))
contract, err := ethtypes.DecodeHexString(string(contractHex))
if err != nil {
return xerrors.Errorf("Could not decode contract file: %w", err)
}
@ -233,7 +219,7 @@ var EvmDeployCmd = &cli.Command{
return xerrors.Errorf("failed to read contract: %w", err)
}
if cctx.Bool("hex") {
contract, err = hex.DecodeString(string(contract))
contract, err = ethtypes.DecodeHexString(string(contract))
if err != nil {
return xerrors.Errorf("failed to decode contract: %w", err)
}
@ -345,8 +331,8 @@ var EvmInvokeCmd = &cli.Command{
defer closer()
ctx := ReqContext(cctx)
if argc := cctx.Args().Len(); argc < 2 || argc > 3 {
return xerrors.Errorf("must pass the address, entry point and (optionally) input data")
if argc := cctx.Args().Len(); argc != 2 {
return xerrors.Errorf("must pass the address and calldata")
}
addr, err := address.NewFromString(cctx.Args().Get(0))
@ -355,7 +341,7 @@ var EvmInvokeCmd = &cli.Command{
}
var calldata []byte
calldata, err = hex.DecodeString(cctx.Args().Get(2))
calldata, err = ethtypes.DecodeHexString(cctx.Args().Get(1))
if err != nil {
return xerrors.Errorf("decoding hex input data: %w", err)
}
@ -388,7 +374,7 @@ var EvmInvokeCmd = &cli.Command{
To: addr,
From: fromAddr,
Value: val,
Method: abi.MethodNum(2),
Method: builtintypes.MethodsEVM.InvokeContract,
Params: calldata,
}

View File

@ -13,6 +13,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
)
var sendCmd = &cli.Command{
@ -24,6 +25,10 @@ var sendCmd = &cli.Command{
Name: "from",
Usage: "optionally specify the account to send funds from",
},
&cli.StringFlag{
Name: "from-eth-addr",
Usage: "optionally specify the eth addr to send funds from",
},
&cli.StringFlag{
Name: "gas-premium",
Usage: "specify gas price to use in AttoFIL",
@ -98,6 +103,18 @@ var sendCmd = &cli.Command{
}
params.From = addr
} else if from := cctx.String("from-eth-addr"); from != "" {
eaddr, err := ethtypes.ParseEthAddress(from)
if err != nil {
return err
}
faddr, err := eaddr.ToFilecoinAddress()
if err != nil {
fmt.Println("error on conversion to faddr")
return err
}
fmt.Println("f4 addr: ", faddr)
params.From = faddr
}
if cctx.IsSet("gas-premium") {

View File

@ -776,7 +776,9 @@ var StateGetActorCmd = &cli.Command{
fmt.Printf("Nonce:\t\t%d\n", a.Nonce)
fmt.Printf("Code:\t\t%s (%s)\n", a.Code, strtype)
fmt.Printf("Head:\t\t%s\n", a.Head)
fmt.Printf("Delegated address:\t\t%s\n", a.Address)
if a.Address != nil {
fmt.Printf("Delegated address:\t\t%s\n", a.Address)
}
return nil
},

View File

@ -83,11 +83,13 @@
* [EthGetFilterChanges](#EthGetFilterChanges)
* [EthGetFilterLogs](#EthGetFilterLogs)
* [EthGetLogs](#EthGetLogs)
* [EthGetMessageCidByTransactionHash](#EthGetMessageCidByTransactionHash)
* [EthGetStorageAt](#EthGetStorageAt)
* [EthGetTransactionByBlockHashAndIndex](#EthGetTransactionByBlockHashAndIndex)
* [EthGetTransactionByBlockNumberAndIndex](#EthGetTransactionByBlockNumberAndIndex)
* [EthGetTransactionByHash](#EthGetTransactionByHash)
* [EthGetTransactionCount](#EthGetTransactionCount)
* [EthGetTransactionHashByCid](#EthGetTransactionHashByCid)
* [EthGetTransactionReceipt](#EthGetTransactionReceipt)
* [EthMaxPriorityFeePerGas](#EthMaxPriorityFeePerGas)
* [EthNewBlockFilter](#EthNewBlockFilter)
@ -2640,6 +2642,25 @@ Response:
]
```
### EthGetMessageCidByTransactionHash
Perms: read
Inputs:
```json
[
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
]
```
Response:
```json
{
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
```
### EthGetStorageAt
@ -2778,6 +2799,22 @@ Inputs:
Response: `"0x5"`
### EthGetTransactionHashByCid
Perms: read
Inputs:
```json
[
{
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
]
```
Response: `"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"`
### EthGetTransactionReceipt

View File

@ -182,15 +182,16 @@ CATEGORY:
BASIC
OPTIONS:
--force Deprecated: use global 'force-send' (default: false)
--from value optionally specify the account to send funds from
--gas-feecap value specify gas fee cap to use in AttoFIL (default: "0")
--gas-limit value specify gas limit (default: 0)
--gas-premium value specify gas price to use in AttoFIL (default: "0")
--method value specify method to invoke (default: 0)
--nonce value specify the nonce to use (default: 0)
--params-hex value specify invocation parameters in hex
--params-json value specify invocation parameters in json
--force Deprecated: use global 'force-send' (default: false)
--from value optionally specify the account to send funds from
--from-eth-addr value optionally specify the eth addr to send funds from
--gas-feecap value specify gas fee cap to use in AttoFIL (default: "0")
--gas-limit value specify gas limit (default: 0)
--gas-premium value specify gas price to use in AttoFIL (default: "0")
--method value specify method to invoke (default: 0)
--nonce value specify the nonce to use (default: 0)
--params-hex value specify invocation parameters in hex
--params-json value specify invocation parameters in json
```
@ -2624,11 +2625,10 @@ NAME:
lotus evm stat - Print eth/filecoin addrs and code cid
USAGE:
lotus evm stat [command options] [arguments...]
lotus evm stat [command options] address
OPTIONS:
--ethAddr value Ethereum address
--filAddr value Filecoin address
--help, -h show help (default: false)
```

View File

@ -293,53 +293,71 @@
#Tracing = false
[ActorEvent]
# EnableRealTimeFilterAPI enables APIs that can create and query filters for actor events as they are emitted.
[Fevm]
# EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids.
# This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.
#
# type: bool
# env var: LOTUS_ACTOREVENT_ENABLEREALTIMEFILTERAPI
#EnableRealTimeFilterAPI = false
# env var: LOTUS_FEVM_ENABLEETHRPC
#EnableEthRPC = false
# EnableHistoricFilterAPI enables APIs that can create and query filters for actor events that occurred in the past.
# A queryable index of events will be maintained.
#
# type: bool
# env var: LOTUS_ACTOREVENT_ENABLEHISTORICFILTERAPI
#EnableHistoricFilterAPI = false
# FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than
# this time become eligible for automatic deletion.
#
# type: Duration
# env var: LOTUS_ACTOREVENT_FILTERTTL
#FilterTTL = "24h0m0s"
# MaxFilters specifies the maximum number of filters that may exist at any one time.
# 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_ACTOREVENT_MAXFILTERS
#MaxFilters = 100
# env var: LOTUS_FEVM_ETHTXHASHMAPPINGLIFETIMEDAYS
#EthTxHashMappingLifetimeDays = 0
# MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter.
#
# type: int
# env var: LOTUS_ACTOREVENT_MAXFILTERRESULTS
#MaxFilterResults = 10000
[Fevm.Events]
# EnableEthRPC enables APIs that
# DisableRealTimeFilterAPI will disable the RealTimeFilterAPI that can create and query filters for actor events as they are emitted.
# The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.
#
# type: bool
# env var: LOTUS_FEVM_EVENTS_DISABLEREALTIMEFILTERAPI
#DisableRealTimeFilterAPI = false
# MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying
# the entire chain)
#
# type: uint64
# env var: LOTUS_ACTOREVENT_MAXFILTERHEIGHTRANGE
#MaxFilterHeightRange = 2880
# DisableHistoricFilterAPI will disable the HistoricFilterAPI that can create and query filters for actor events
# that occurred in the past. HistoricFilterAPI maintains a queryable index of events.
# The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.
#
# type: bool
# env var: LOTUS_FEVM_EVENTS_DISABLEHISTORICFILTERAPI
#DisableHistoricFilterAPI = false
# ActorEventDatabasePath is the full path to a sqlite database that will be used to index actor events to
# support the historic filter APIs. If the database does not exist it will be created. The directory containing
# the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as
# relative to the CWD (current working directory).
#
# type: string
# env var: LOTUS_ACTOREVENT_ACTOREVENTDATABASEPATH
#ActorEventDatabasePath = ""
# FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than
# this time become eligible for automatic deletion.
#
# type: Duration
# env var: LOTUS_FEVM_EVENTS_FILTERTTL
#FilterTTL = "24h0m0s"
# MaxFilters specifies the maximum number of filters that may exist at any one time.
#
# type: int
# env var: LOTUS_FEVM_EVENTS_MAXFILTERS
#MaxFilters = 100
# MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter.
#
# type: int
# env var: LOTUS_FEVM_EVENTS_MAXFILTERRESULTS
#MaxFilterResults = 10000
# MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying
# the entire chain)
#
# type: uint64
# env var: LOTUS_FEVM_EVENTS_MAXFILTERHEIGHTRANGE
#MaxFilterHeightRange = 2880
# DatabasePath is the full path to a sqlite database that will be used to index actor events to
# support the historic filter APIs. If the database does not exist it will be created. The directory containing
# the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as
# relative to the CWD (current working directory).
#
# type: string
# env var: LOTUS_FEVM_EVENTS_DATABASEPATH
#DatabasePath = ""

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b5061018c806100206000396000f3fe6080604052600436106100345760003560e01c806361bc221a146100395780636466414b146100645780638ada066e14610080575b600080fd5b34801561004557600080fd5b5061004e6100ab565b60405161005b91906100dd565b60405180910390f35b61007e60048036038101906100799190610129565b6100b1565b005b34801561008c57600080fd5b506100956100bb565b6040516100a291906100dd565b60405180910390f35b60005481565b8060008190555050565b60008054905090565b6000819050919050565b6100d7816100c4565b82525050565b60006020820190506100f260008301846100ce565b92915050565b600080fd5b610106816100c4565b811461011157600080fd5b50565b600081359050610123816100fd565b92915050565b60006020828403121561013f5761013e6100f8565b5b600061014d84828501610114565b9150509291505056fea2646970667358221220cf4567855a30be48cde5cdbff495bdaa4052e2c4540678b97284af53a4e5dbd164736f6c63430008110033

View File

@ -0,0 +1,13 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract DelegatecallActor {
uint public counter;
function getCounter() public view returns (uint){
return counter;
}
function setVars(uint _counter) public payable {
counter = _counter;
}
}

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b50610477806100206000396000f3fe6080604052600436106100345760003560e01c806361bc221a146100395780638ada066e14610064578063d1e0f3081461008f575b600080fd5b34801561004557600080fd5b5061004e6100bf565b60405161005b919061022c565b60405180910390f35b34801561007057600080fd5b506100796100c5565b604051610086919061022c565b60405180910390f35b6100a960048036038101906100a491906102d6565b6100ce565b6040516100b6919061022c565b60405180910390f35b60005481565b60008054905090565b6000808373ffffffffffffffffffffffffffffffffffffffff16836040516024016100f9919061022c565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516101839190610387565b600060405180830381855af49150503d80600081146101be576040519150601f19603f3d011682016040523d82523d6000602084013e6101c3565b606091505b5050905080610207576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101fe90610421565b60405180910390fd5b60005491505092915050565b6000819050919050565b61022681610213565b82525050565b6000602082019050610241600083018461021d565b92915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102778261024c565b9050919050565b6102878161026c565b811461029257600080fd5b50565b6000813590506102a48161027e565b92915050565b6102b381610213565b81146102be57600080fd5b50565b6000813590506102d0816102aa565b92915050565b600080604083850312156102ed576102ec610247565b5b60006102fb85828601610295565b925050602061030c858286016102c1565b9150509250929050565b600081519050919050565b600081905092915050565b60005b8381101561034a57808201518184015260208101905061032f565b60008484015250505050565b600061036182610316565b61036b8185610321565b935061037b81856020860161032c565b80840191505092915050565b60006103938284610356565b915081905092915050565b600082825260208201905092915050565b7f4572726f72206d6573736167653a2044656c656761746563616c6c206661696c60008201527f6564000000000000000000000000000000000000000000000000000000000000602082015250565b600061040b60228361039e565b9150610416826103af565b604082019050919050565b6000602082019050818103600083015261043a816103fe565b905091905056fea26469706673582212203663909b8221e9b87047be99420c00339af1430c085260df209b909ed8e0f05164736f6c63430008110033

View File

@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
contract DelegatecallStorage {
uint public counter;
function getCounter() public view returns (uint){
return counter;
}
function setVars(address _contract, uint _counter) public payable returns (uint){
(bool success, ) = _contract.delegatecall(
abi.encodeWithSignature("setVars(uint256)", _counter)
);
require(success, 'Error message: Delegatecall failed');
return counter;
}
}

View File

@ -0,0 +1 @@
608060405234801561001057600080fd5b506105eb806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063c755553811610071578063c755553814610198578063cbfc3b58146101c6578063cc6f8faf14610212578063cd5b6c3d14610254578063e2a614731461028c578063fb62b28b146102d8576100a9565b80630919b8be146100ae5780636199074d146100e657806366eef3461461012857806375091b1f14610132578063a63ae81a1461016a575b600080fd5b6100e4600480360360408110156100c457600080fd5b81019080803590602001909291908035906020019092919050505061031a565b005b610126600480360360608110156100fc57600080fd5b8101908080359060200190929190803590602001909291908035906020019092919050505061035d565b005b610130610391565b005b6101686004803603604081101561014857600080fd5b8101908080359060200190929190803590602001909291905050506103bf565b005b6101966004803603602081101561018057600080fd5b81019080803590602001909291905050506103fb565b005b6101c4600480360360208110156101ae57600080fd5b8101908080359060200190929190505050610435565b005b610210600480360360808110156101dc57600080fd5b8101908080359060200190929190803590602001909291908035906020019092919080359060200190929190505050610465565b005b6102526004803603606081101561022857600080fd5b810190808035906020019092919080359060200190929190803590602001909291905050506104ba565b005b61028a6004803603604081101561026a57600080fd5b8101908080359060200190929190803590602001909291905050506104f8565b005b6102d6600480360360808110156102a257600080fd5b810190808035906020019092919080359060200190929190803590602001909291908035906020019092919050505061052a565b005b610318600480360360608110156102ee57600080fd5b8101908080359060200190929190803590602001909291908035906020019092919050505061056a565b005b7f5469c6b769315f5668523937f05ca07d4cc87849432bc5f5907f1d90fa73b9f98282604051808381526020018281526020019250505060405180910390a15050565b8082847fb89dabcdb7ff41f1794c0da92f65ece6c19b6b0caeac5407b2a721efe27c080460405160405180910390a4505050565b7fc3f6f1c76bd4e74ee5782052b0b4f8bd5c50b86c3c5a2f52638e03066e50a91b60405160405180910390a1565b817f6709824ebe5f6e620ca3f4b02a3428e8ce2dc97c550816eaeeb3a342b214bd85826040518082815260200191505060405180910390a25050565b7fc804e53d6048af1b3e6a352e246d5f3864fea9d635ace499e023a58c383b3a88816040518082815260200191505060405180910390a150565b807f44a227a31429ab5eb00daf6611c6422f10571619f2267e0e149e9ebe6d2a5d0560405160405180910390a250565b7f28d45631a87b2a52a9625f8520fa37ff8c4d926cdf17042e241985da5cb7b850848484846040518085815260200184815260200183815260200182815260200194505050505060405180910390a150505050565b81837fcd5fe5fbc1d27b90036997224cea7aa565e3779622867265081f636b3a5ccb08836040518082815260200191505060405180910390a3505050565b80827f232f09cef3babc26e58d1cc1346c0a8bc626ffe600c9605b5d747783eda484a760405160405180910390a35050565b8183857f812e73dbcf7e267f27ecb1383bfc902a6650b41b6e7d03ac265108c369673d95846040518082815260200191505060405180910390a450505050565b7fd4d143faaf60340ad98e1f2c96fc26f5695834c21b5200edad339ee7e9a372cc83838360405180848152602001838152602001828152602001935050505060405180910390a150505056fea265627a7a72315820954561fde80ab925299e0a9f3356b01f64fb1976dd335ac2ebd9367441e29f0564736f6c63430005110032

View File

@ -0,0 +1,51 @@
pragma solidity ^0.5.0;
contract EventMatrix {
event EventZeroData();
event EventOneData(uint a);
event EventTwoData(uint a, uint b);
event EventThreeData(uint a, uint b, uint c);
event EventFourData(uint a, uint b, uint c, uint d);
event EventOneIndexed(uint indexed a);
event EventTwoIndexed(uint indexed a, uint indexed b);
event EventThreeIndexed(uint indexed a, uint indexed b, uint indexed c);
event EventOneIndexedWithData(uint indexed a, uint b);
event EventTwoIndexedWithData(uint indexed a, uint indexed b, uint c);
event EventThreeIndexedWithData(uint indexed a, uint indexed b, uint indexed c, uint d);
function logEventZeroData() public {
emit EventZeroData();
}
function logEventOneData(uint a) public {
emit EventOneData(a);
}
function logEventTwoData(uint a, uint b) public {
emit EventTwoData(a,b);
}
function logEventThreeData(uint a, uint b, uint c) public {
emit EventThreeData(a,b,c);
}
function logEventFourData(uint a, uint b, uint c, uint d) public {
emit EventFourData(a,b,c,d);
}
function logEventOneIndexed(uint a) public {
emit EventOneIndexed(a);
}
function logEventTwoIndexed(uint a, uint b) public {
emit EventTwoIndexed(a,b);
}
function logEventThreeIndexed(uint a, uint b, uint c) public {
emit EventThreeIndexed(a,b,c);
}
function logEventOneIndexedWithData(uint a, uint b) public {
emit EventOneIndexedWithData(a,b);
}
function logEventTwoIndexedWithData(uint a, uint b, uint c) public {
emit EventTwoIndexedWithData(a,b,c);
}
function logEventThreeIndexedWithData(uint a, uint b, uint c, uint d) public {
emit EventThreeIndexedWithData(a,b,c,d);
}
}

View File

@ -1 +1 @@
608060405234801561001057600080fd5b506127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061051c806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637bd703e81461004657806390b98a1114610076578063f8b2cb4f146100a6575b600080fd5b610060600480360381019061005b919061030a565b6100d6565b60405161006d9190610350565b60405180910390f35b610090600480360381019061008b9190610397565b6100f4565b60405161009d91906103f2565b60405180910390f35b6100c060048036038101906100bb919061030a565b61025f565b6040516100cd9190610350565b60405180910390f35b600060026100e38361025f565b6100ed919061043c565b9050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101455760009050610259565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610193919061047e565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101e891906104b2565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161024c9190610350565b60405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d7826102ac565b9050919050565b6102e7816102cc565b81146102f257600080fd5b50565b600081359050610304816102de565b92915050565b6000602082840312156103205761031f6102a7565b5b600061032e848285016102f5565b91505092915050565b6000819050919050565b61034a81610337565b82525050565b60006020820190506103656000830184610341565b92915050565b61037481610337565b811461037f57600080fd5b50565b6000813590506103918161036b565b92915050565b600080604083850312156103ae576103ad6102a7565b5b60006103bc858286016102f5565b92505060206103cd85828601610382565b9150509250929050565b60008115159050919050565b6103ec816103d7565b82525050565b600060208201905061040760008301846103e3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061044782610337565b915061045283610337565b925082820261046081610337565b915082820484148315176104775761047661040d565b5b5092915050565b600061048982610337565b915061049483610337565b92508282039050818111156104ac576104ab61040d565b5b92915050565b60006104bd82610337565b91506104c883610337565b92508282019050808211156104e0576104df61040d565b5b9291505056fea26469706673582212205ede41ff9072784ccc19ac18de0781558d305a8139361fa85dc51a8614e47d8c64736f6c63430008110033
608060405234801561001057600080fd5b506127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061051c806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637bd703e81461004657806390b98a1114610076578063f8b2cb4f146100a6575b600080fd5b610060600480360381019061005b919061030a565b6100d6565b60405161006d9190610350565b60405180910390f35b610090600480360381019061008b9190610397565b6100f4565b60405161009d91906103f2565b60405180910390f35b6100c060048036038101906100bb919061030a565b61025f565b6040516100cd9190610350565b60405180910390f35b600060026100e38361025f565b6100ed919061043c565b9050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101455760009050610259565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610193919061047e565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101e891906104b2565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161024c9190610350565b60405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d7826102ac565b9050919050565b6102e7816102cc565b81146102f257600080fd5b50565b600081359050610304816102de565b92915050565b6000602082840312156103205761031f6102a7565b5b600061032e848285016102f5565b91505092915050565b6000819050919050565b61034a81610337565b82525050565b60006020820190506103656000830184610341565b92915050565b61037481610337565b811461037f57600080fd5b50565b6000813590506103918161036b565b92915050565b600080604083850312156103ae576103ad6102a7565b5b60006103bc858286016102f5565b92505060206103cd85828601610382565b9150509250929050565b60008115159050919050565b6103ec816103d7565b82525050565b600060208201905061040760008301846103e3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061044782610337565b915061045283610337565b925082820261046081610337565b915082820484148315176104775761047661040d565b5b5092915050565b600061048982610337565b915061049483610337565b92508282039050818111156104ac576104ab61040d565b5b92915050565b60006104bd82610337565b91506104c883610337565b92508282019050808211156104e0576104df61040d565b5b9291505056fea2646970667358221220050cdcfbe2911d041d2e6c355dbb6a0ca8ca70b500865bf33d9a2e5f4ac5a4e164736f6c63430008110033

6
itests/contracts/compile.sh Executable file
View File

@ -0,0 +1,6 @@
#use the solc compiler https://docs.soliditylang.org/en/v0.8.17/installing-solidity.html
# to compile all of the .sol files to their corresponding evm binary files stored as .hex
# solc outputs to stdout a format that we just want to grab the last line of and then remove the trailing newline on that line
find -type f -name \*.sol -print0 |
xargs -0 -I{} bash -c 'solc --bin {} |tail -n1 | tr -d "\n" > $(echo {} | sed -e s/.sol$/.hex/)'

View File

@ -0,0 +1,47 @@
# https://github.com/filecoin-project/builtin-actors/blob/b1ba61053de2ceaddd5116e87823d20a8f5e38d7/actors/evm/tests/events.rs
# method dispatch:
# - 0x00000000 -> log_zero_data
# - 0x00000001 -> log_zero_nodata
# - 0x00000002 -> log_four_data
%dispatch_begin()
%dispatch(0x00, log_zero_data)
%dispatch(0x01, log_zero_nodata)
%dispatch(0x02, log_four_data)
%dispatch_end()
#### log a zero topic event with data
log_zero_data:
jumpdest
push8 0x1122334455667788
push1 0x00
mstore
push1 0x08
push1 0x18 ## index 24 into memory as mstore writes a full word
log0
push1 0x00
push1 0x00
return
#### log a zero topic event with no data
log_zero_nodata:
jumpdest
push1 0x00
push1 0x00
log0
push1 0x00
push1 0x00
return
#### log a four topic event with data
log_four_data:
jumpdest
push8 0x1122334455667788
push1 0x00
mstore
push4 0x4444
push3 0x3333
push2 0x2222
push2 0x1111
push1 0x08
push1 0x18 ## index 24 into memory as mstore writes a full word
log4
push1 0x00
push1 0x00
return

View File

@ -33,7 +33,7 @@ func TestDealPadding(t *testing.T) {
dh := kit.NewDealHarness(t, client, miner, miner)
ctx := context.Background()
client.WaitTillChain(ctx, kit.BlockMinedBy(miner.ActorAddr))
client.WaitTillChain(ctx, kit.BlocksMinedByAll(miner.ActorAddr))
// Create a random file, would originally be a 256-byte sector
res, inFile := client.CreateImportFile(ctx, 1, 200)

View File

@ -52,7 +52,7 @@ func TestFirstDealEnablesMining(t *testing.T) {
providerMined := make(chan struct{})
go func() {
_ = client.WaitTillChain(ctx, kit.BlockMinedBy(provider.ActorAddr))
_ = client.WaitTillChain(ctx, kit.BlocksMinedByAll(provider.ActorAddr))
close(providerMined)
}()

View File

@ -0,0 +1,65 @@
package itests
import (
"context"
"fmt"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/lotus/itests/kit"
)
// TestEthBlockHashesCorrect_MultiBlockTipset validates that blocks retrieved through
// EthGetBlockByNumber are identical to blocks retrieved through
// EthGetBlockByHash, when using the block hash returned by the former.
//
// Specifically, it checks the system behaves correctly with multiblock tipsets.
//
// Catches regressions around https://github.com/filecoin-project/lotus/issues/10061.
func TestEthBlockHashesCorrect_MultiBlockTipset(t *testing.T) {
// miner is connected to the first node, and we want to observe the chain
// from the second node.
blocktime := 100 * time.Millisecond
n1, m1, m2, ens := kit.EnsembleOneTwo(t,
kit.MockProofs(),
kit.ThroughRPC(),
)
ens.InterconnectAll().BeginMining(blocktime)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
n1.WaitTillChain(ctx, kit.HeightAtLeast(abi.ChainEpoch(25)))
defer cancel()
var n2 kit.TestFullNode
ens.FullNode(&n2, kit.ThroughRPC()).Start().Connect(n2, n1)
// find the first tipset where all miners mined a block.
ctx, cancel = context.WithTimeout(context.Background(), 1*time.Minute)
n2.WaitTillChain(ctx, kit.BlocksMinedByAll(m1.ActorAddr, m2.ActorAddr))
defer cancel()
head, err := n2.ChainHead(context.Background())
require.NoError(t, err)
// let the chain run a little bit longer to minimise the chance of reorgs
n2.WaitTillChain(ctx, kit.HeightAtLeast(head.Height()+50))
head, err = n2.ChainHead(context.Background())
require.NoError(t, err)
for i := 1; i <= int(head.Height()); i++ {
hex := fmt.Sprintf("0x%x", i)
ethBlockA, err := n2.EthGetBlockByNumber(ctx, hex, true)
require.NoError(t, err)
ethBlockB, err := n2.EthGetBlockByHash(ctx, ethBlockA.Hash, true)
require.NoError(t, err)
require.Equal(t, ethBlockA, ethBlockB)
}
}

View File

@ -20,7 +20,6 @@ import (
"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"
)
// TestDeployment smoke tests the deployment of a contract via the
@ -36,12 +35,7 @@ func TestDeployment(t *testing.T) {
client, _, ens := kit.EnsembleMinimal(
t,
kit.MockProofs(),
kit.ThroughRPC(),
kit.WithCfgOpt(func(cfg *config.FullNode) error {
cfg.ActorEvent.EnableRealTimeFilterAPI = true
return nil
}),
)
kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
@ -99,6 +93,7 @@ func TestDeployment(t *testing.T) {
mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash)
require.NoError(t, err)
require.NotNil(t, mpoolTx)
// require that the hashes are identical
require.Equal(t, hash, mpoolTx.Hash)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,510 @@
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"
)
// 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(),
)
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: &ethAddr,
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
}
// 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(),
)
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(),
)
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(),
)
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(),
)
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: &ethAddr,
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(),
)
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(),
)
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)
}

View File

@ -12,6 +12,7 @@ import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/itests/kit"
)
@ -45,22 +46,22 @@ func TestFEVMEvents(t *testing.T) {
require.NoError(err)
t.Logf("actor ID address is %s", idAddr)
// var (
// earliest = "earliest"
// latest = "latest"
// )
//
// // Install a filter.
// filter, err := client.EthNewFilter(ctx, &api.EthFilterSpec{
// FromBlock: &earliest,
// ToBlock: &latest,
// })
// require.NoError(err)
//
// // No logs yet.
// res, err := client.EthGetFilterLogs(ctx, filter)
// require.NoError(err)
// require.Empty(res.NewLogs)
var (
earliest = "earliest"
latest = "latest"
)
// Install a filter.
filter, err := client.EthNewFilter(ctx, &ethtypes.EthFilterSpec{
FromBlock: &earliest,
ToBlock: &latest,
})
require.NoError(err)
// No logs yet.
res, err := client.EthGetFilterLogs(ctx, filter)
require.NoError(err)
require.Empty(res.Results)
// log a zero topic event with data
ret := client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x00}, nil)

View File

@ -1,67 +1,64 @@
package itests
import (
"bytes"
"context"
"encoding/hex"
"os"
"testing"
"time"
"github.com/stretchr/testify/require"
cbg "github.com/whyrusleeping/cbor-gen"
"github.com/filecoin-project/go-address"
builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/manifest"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/itests/kit"
)
// TestFEVMBasic does a basic fevm contract installation and invocation
func TestFEVMBasic(t *testing.T) {
// TODO the contract installation and invocation can be lifted into utility methods
// He who writes the second test, shall do that.
kit.QuietMiningLogs()
// convert a simple byte array into input data which is a left padded 32 byte array
func inputDataFromArray(input []byte) []byte {
inputData := make([]byte, 32)
copy(inputData[32-len(input):], input[:])
return inputData
}
// convert a "from" address into input data which is a left padded 32 byte array
func inputDataFromFrom(ctx context.Context, t *testing.T, client *kit.TestFullNode, from address.Address) []byte {
fromId, err := client.StateLookupID(ctx, from, types.EmptyTSK)
require.NoError(t, err)
senderEthAddr, err := ethtypes.EthAddressFromFilecoinAddress(fromId)
require.NoError(t, err)
inputData := make([]byte, 32)
copy(inputData[32-len(senderEthAddr):], senderEthAddr[:])
return inputData
}
func setupFEVMTest(t *testing.T) (context.Context, context.CancelFunc, *kit.TestFullNode) {
kit.QuietMiningLogs()
blockTime := 100 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
return ctx, cancel, client
}
// TestFEVMBasic does a basic fevm contract installation and invocation
func TestFEVMBasic(t *testing.T) {
ctx, cancel, client := setupFEVMTest(t)
defer cancel()
filename := "contracts/SimpleCoin.hex"
// install contract
contractHex, err := os.ReadFile("contracts/SimpleCoin.hex")
require.NoError(t, err)
contract, err := hex.DecodeString(string(contractHex))
require.NoError(t, err)
fromAddr, err := client.WalletDefaultAddress(ctx)
require.NoError(t, err)
result := client.EVM().DeployContract(ctx, fromAddr, contract)
idAddr, err := address.NewIDAddress(result.ActorID)
require.NoError(t, err)
t.Logf("actor ID address is %s", idAddr)
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
// invoke the contract with owner
{
entryPoint, err := hex.DecodeString("f8b2cb4f")
require.NoError(t, err)
inputData, err := hex.DecodeString("000000000000000000000000ff00000000000000000000000000000000000064")
require.NoError(t, err)
wait := client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
require.True(t, wait.Receipt.ExitCode.IsSuccess(), "contract execution failed")
result, err := cbg.ReadByteArray(bytes.NewBuffer(wait.Receipt.Return), uint64(len(wait.Receipt.Return)))
require.NoError(t, err)
inputData := inputDataFromFrom(ctx, t, client, fromAddr)
result := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData)
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000002710")
require.NoError(t, err)
@ -70,34 +67,19 @@ func TestFEVMBasic(t *testing.T) {
// invoke the contract with non owner
{
entryPoint, err := hex.DecodeString("f8b2cb4f")
require.NoError(t, err)
inputData, err := hex.DecodeString("000000000000000000000000ff00000000000000000000000000000000000065")
require.NoError(t, err)
wait := client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
require.True(t, wait.Receipt.ExitCode.IsSuccess(), "contract execution failed")
result, err := cbg.ReadByteArray(bytes.NewBuffer(wait.Receipt.Return), uint64(len(wait.Receipt.Return)))
require.NoError(t, err)
inputData := inputDataFromFrom(ctx, t, client, fromAddr)
inputData[31]++ // change the pub address to one that has 0 balance by incrementing the last byte of the address
result := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData)
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
require.NoError(t, err)
require.Equal(t, result, expectedResult)
}
}
// TestFEVMETH0 tests that the ETH0 actor is in genesis
func TestFEVMETH0(t *testing.T) {
kit.QuietMiningLogs()
blockTime := 100 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
ctx, cancel, client := setupFEVMTest(t)
defer cancel()
eth0id, err := address.NewIDAddress(1001)
@ -112,3 +94,48 @@ func TestFEVMETH0(t *testing.T) {
require.NoError(t, err)
require.Equal(t, *act.Address, eth0Addr)
}
// TestFEVMDelegateCall deploys two contracts and makes a delegate call transaction
func TestFEVMDelegateCall(t *testing.T) {
ctx, cancel, client := setupFEVMTest(t)
defer cancel()
//install contract Actor
filenameActor := "contracts/DelegatecallActor.hex"
fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)
//install contract Storage
filenameStorage := "contracts/DelegatecallStorage.hex"
fromAddrStorage, storageAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
require.Equal(t, fromAddr, fromAddrStorage)
//call Contract Storage which makes a delegatecall to contract Actor
//this contract call sets the "counter" variable to 7, from default value 0
inputDataContract := inputDataFromFrom(ctx, t, client, actorAddr)
inputDataValue := inputDataFromArray([]byte{7})
inputData := append(inputDataContract, inputDataValue...)
//verify that the returned value of the call to setvars is 7
result := client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "setVars(address,uint256)", inputData)
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000007")
require.NoError(t, err)
require.Equal(t, result, expectedResult)
//test the value is 7 via calling the getter
result = client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "getCounter()", []byte{})
require.Equal(t, result, expectedResult)
//test the value is 0 via calling the getter on the Actor contract
result = client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "getCounter()", []byte{})
expectedResultActor, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
require.NoError(t, err)
require.Equal(t, result, expectedResultActor)
}
func TestEVMRpcDisable(t *testing.T) {
client, _, _ := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.DisableEthRPC())
_, err := client.EthBlockNumber(context.Background())
require.ErrorContains(t, err, "module disabled, enable with Fevm.EnableEthRPC")
}

View File

@ -4,7 +4,9 @@ import (
"bytes"
"context"
"encoding/binary"
"encoding/hex"
"fmt"
"os"
"github.com/ipfs/go-cid"
"github.com/multiformats/go-varint"
@ -77,6 +79,26 @@ func (e *EVM) DeployContract(ctx context.Context, sender address.Address, byteco
return result
}
func (e *EVM) DeployContractFromFilename(ctx context.Context, binFilename string) (address.Address, address.Address) {
contractHex, err := os.ReadFile(binFilename)
require.NoError(e.t, err)
// strip any trailing newlines from the file
contractHex = bytes.TrimRight(contractHex, "\n")
contract, err := hex.DecodeString(string(contractHex))
require.NoError(e.t, err)
fromAddr, err := e.WalletDefaultAddress(ctx)
require.NoError(e.t, err)
result := e.DeployContract(ctx, fromAddr, contract)
idAddr, err := address.NewIDAddress(result.ActorID)
require.NoError(e.t, err)
return fromAddr, idAddr
}
func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte) *api.MsgLookup {
require := require.New(e.t)
@ -212,6 +234,23 @@ func (e *EVM) ComputeContractAddress(deployer ethtypes.EthAddress, nonce uint64)
return *(*ethtypes.EthAddress)(hasher.Sum(nil)[12:])
}
func (e *EVM) InvokeContractByFuncName(ctx context.Context, fromAddr address.Address, idAddr address.Address, funcSignature string, inputData []byte) []byte {
entryPoint := CalcFuncSignature(funcSignature)
wait := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
require.True(e.t, wait.Receipt.ExitCode.IsSuccess(), "contract execution failed")
result, err := cbg.ReadByteArray(bytes.NewBuffer(wait.Receipt.Return), uint64(len(wait.Receipt.Return)))
require.NoError(e.t, err)
return result
}
// function signatures are the first 4 bytes of the hash of the function name and types
func CalcFuncSignature(funcName string) []byte {
hasher := sha3.NewLegacyKeccak256()
hasher.Write([]byte(funcName))
hash := hasher.Sum(nil)
return hash[:4]
}
// TODO: cleanup and put somewhere reusable.
type apiIpldStore struct {
ctx context.Context

View File

@ -1,6 +1,9 @@
package kit
import (
"io"
"log"
logging "github.com/ipfs/go-log/v2"
"github.com/filecoin-project/lotus/lib/lotuslog"
@ -20,3 +23,13 @@ func QuietMiningLogs() {
_ = logging.SetLogLevel("rpc", "ERROR")
_ = logging.SetLogLevel("dht/RtRefreshManager", "ERROR")
}
func QuietAllLogsExcept(names ...string) {
log.SetOutput(io.Discard) // suppress LogDatastore messages
lotuslog.SetupLogLevels()
logging.SetAllLoggers(logging.LevelError)
for _, name := range names {
_ = logging.SetLogLevel(name, "INFO")
}
}

View File

@ -135,13 +135,21 @@ func HeightAtLeast(target abi.ChainEpoch) ChainPredicate {
}
}
// BlockMinedBy returns a ChainPredicate that is satisfied when we observe the
// first block mined by the specified miner.
func BlockMinedBy(miner address.Address) ChainPredicate {
// BlocksMinedByAll returns a ChainPredicate that is satisfied when we observe a
// tipset including blocks from all the specified miners, in no particular order.
func BlocksMinedByAll(miner ...address.Address) ChainPredicate {
return func(ts *types.TipSet) bool {
seen := make([]bool, len(miner))
var done int
for _, b := range ts.Blocks() {
if b.Miner == miner {
return true
for i, m := range miner {
if b.Miner != m || seen[i] {
continue
}
seen[i] = true
if done++; done == len(miner) {
return true
}
}
}
return false

View File

@ -58,6 +58,15 @@ var DefaultNodeOpts = nodeOpts{
sectors: DefaultPresealsPerBootstrapMiner,
sectorSize: abi.SectorSize(2 << 10), // 2KiB.
cfgOpts: []CfgOption{
func(cfg *config.FullNode) error {
// test defaults
cfg.Fevm.EnableEthRPC = true
return nil
},
},
workerTasks: []sealtasks.TaskType{sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed},
workerStorageOpt: func(store paths.Store) paths.Store { return store },
}
@ -281,18 +290,16 @@ func SplitstoreMessges() NodeOpt {
})
}
func RealTimeFilterAPI() NodeOpt {
func WithEthRPC() NodeOpt {
return WithCfgOpt(func(cfg *config.FullNode) error {
cfg.ActorEvent.EnableRealTimeFilterAPI = true
cfg.Fevm.EnableEthRPC = true
return nil
})
}
func HistoricFilterAPI(dbpath string) NodeOpt {
func DisableEthRPC() NodeOpt {
return WithCfgOpt(func(cfg *config.FullNode) error {
cfg.ActorEvent.EnableRealTimeFilterAPI = true
cfg.ActorEvent.EnableHistoricFilterAPI = true
cfg.ActorEvent.ActorEventDatabasePath = dbpath
cfg.Fevm.EnableEthRPC = false
return nil
})
}

View File

@ -351,13 +351,11 @@ func splitStorePruneIndex(ctx context.Context, t *testing.T, n *kit.TestFullNode
}
func ipldExists(ctx context.Context, t *testing.T, c cid.Cid, n *kit.TestFullNode) bool {
_, err := n.ChainReadObj(ctx, c)
if ipld.IsNotFound(err) {
return false
} else if err != nil {
t.Fatalf("ChainReadObj failure on existence check: %s", err)
found, err := n.ChainHasObj(ctx, c)
if err != nil {
t.Fatalf("ChainHasObj failure: %s", err)
}
return true
return found
}
// Create on chain unreachable garbage for a network to exercise splitstore
@ -414,12 +412,10 @@ func (g *Garbager) Exists(ctx context.Context, c cid.Cid) bool {
return false
} else if err != nil {
g.t.Fatalf("ChainReadObj failure on existence check: %s", err)
return false // unreachable
} else {
return true
}
g.t.Fatal("unreachable")
return false
}
func (g *Garbager) newPeerID(ctx context.Context) abi.ChainEpoch {

View File

@ -68,7 +68,7 @@ func (delegatedSigner) Verify(sig []byte, a address.Address, msg []byte) error {
}
if maybeaddr != a {
return fmt.Errorf("signature did not match")
return fmt.Errorf("signature did not match maybeaddr: %s, signer: %s", maybeaddr, a)
}
return nil

View File

@ -161,7 +161,6 @@ var ChainNode = Options(
Override(new(messagepool.Provider), messagepool.NewProvider),
Override(new(messagepool.MpoolNonceAPI), From(new(*messagepool.MessagePool))),
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.MpoolModuleAPI), From(new(full.MpoolModule))),
Override(new(full.StateModuleAPI), From(new(full.StateModule))),
@ -260,7 +259,10 @@ func ConfigFullNode(c interface{}) Option {
// Actor event filtering support
Override(new(events.EventAPI), From(new(modules.EventAPI))),
// 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.Fevm))),
If(cfg.Fevm.EnableEthRPC, Override(new(full.EthModuleAPI), modules.EthModuleAPI(cfg.Fevm))),
If(!cfg.Fevm.EnableEthRPC, Override(new(full.EthModuleAPI), &full.EthModuleDummy{})),
)
}

View File

@ -99,13 +99,17 @@ func DefaultFullNode() *FullNode {
},
},
Cluster: *DefaultUserRaftConfig(),
ActorEvent: ActorEventConfig{
EnableRealTimeFilterAPI: false,
EnableHistoricFilterAPI: false,
FilterTTL: Duration(time.Hour * 24),
MaxFilters: 100,
MaxFilterResults: 10000,
MaxFilterHeightRange: 2880, // conservative limit of one day
Fevm: FevmConfig{
EnableEthRPC: false,
EthTxHashMappingLifetimeDays: 0,
Events: Events{
DisableRealTimeFilterAPI: false,
DisableHistoricFilterAPI: false,
FilterTTL: Duration(time.Hour * 24),
MaxFilters: 100,
MaxFilterResults: 10000,
MaxFilterHeightRange: 2880, // conservative limit of one day
},
},
}
}

View File

@ -29,56 +29,6 @@ var Doc = map[string][]DocField{
Comment: ``,
},
},
"ActorEventConfig": []DocField{
{
Name: "EnableRealTimeFilterAPI",
Type: "bool",
Comment: `EnableRealTimeFilterAPI enables APIs that can create and query filters for actor events as they are emitted.`,
},
{
Name: "EnableHistoricFilterAPI",
Type: "bool",
Comment: `EnableHistoricFilterAPI enables APIs that can create and query filters for actor events that occurred in the past.
A queryable index of events will be maintained.`,
},
{
Name: "FilterTTL",
Type: "Duration",
Comment: `FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than
this time become eligible for automatic deletion.`,
},
{
Name: "MaxFilters",
Type: "int",
Comment: `MaxFilters specifies the maximum number of filters that may exist at any one time.`,
},
{
Name: "MaxFilterResults",
Type: "int",
Comment: `MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter.`,
},
{
Name: "MaxFilterHeightRange",
Type: "uint64",
Comment: `MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying
the entire chain)`,
},
{
Name: "ActorEventDatabasePath",
Type: "string",
Comment: `ActorEventDatabasePath is the full path to a sqlite database that will be used to index actor events to
support the historic filter APIs. If the database does not exist it will be created. The directory containing
the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as
relative to the CWD (current working directory).`,
},
},
"Backup": []DocField{
{
Name: "DisableMetadataLog",
@ -391,6 +341,59 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
Comment: ``,
},
},
"Events": []DocField{
{
Name: "DisableRealTimeFilterAPI",
Type: "bool",
Comment: `EnableEthRPC enables APIs that
DisableRealTimeFilterAPI will disable the RealTimeFilterAPI that can create and query filters for actor events as they are emitted.
The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.`,
},
{
Name: "DisableHistoricFilterAPI",
Type: "bool",
Comment: `DisableHistoricFilterAPI will disable the HistoricFilterAPI that can create and query filters for actor events
that occurred in the past. HistoricFilterAPI maintains a queryable index of events.
The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.`,
},
{
Name: "FilterTTL",
Type: "Duration",
Comment: `FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than
this time become eligible for automatic deletion.`,
},
{
Name: "MaxFilters",
Type: "int",
Comment: `MaxFilters specifies the maximum number of filters that may exist at any one time.`,
},
{
Name: "MaxFilterResults",
Type: "int",
Comment: `MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter.`,
},
{
Name: "MaxFilterHeightRange",
Type: "uint64",
Comment: `MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying
the entire chain)`,
},
{
Name: "DatabasePath",
Type: "string",
Comment: `DatabasePath is the full path to a sqlite database that will be used to index actor events to
support the historic filter APIs. If the database does not exist it will be created. The directory containing
the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as
relative to the CWD (current working directory).`,
},
},
"FeeConfig": []DocField{
{
Name: "DefaultMaxFee",
@ -399,6 +402,28 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
Comment: ``,
},
},
"FevmConfig": []DocField{
{
Name: "EnableEthRPC",
Type: "bool",
Comment: `EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids.
This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.`,
},
{
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`,
},
{
Name: "Events",
Type: "Events",
Comment: ``,
},
},
"FullNode": []DocField{
{
Name: "Client",
@ -431,8 +456,8 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
Comment: ``,
},
{
Name: "ActorEvent",
Type: "ActorEventConfig",
Name: "Fevm",
Type: "FevmConfig",
Comment: ``,
},

View File

@ -27,7 +27,7 @@ type FullNode struct {
Fees FeeConfig
Chainstore Chainstore
Cluster UserRaftConfig
ActorEvent ActorEventConfig
Fevm FevmConfig
}
// // Common
@ -659,13 +659,28 @@ type UserRaftConfig struct {
Tracing bool
}
type ActorEventConfig struct {
// EnableRealTimeFilterAPI enables APIs that can create and query filters for actor events as they are emitted.
EnableRealTimeFilterAPI bool
type FevmConfig struct {
// EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids.
// This will also enable the RealTimeFilterAPI and HistoricFilterAPI by default, but they can be disabled by config options above.
EnableEthRPC bool
// EnableHistoricFilterAPI enables APIs that can create and query filters for actor events that occurred in the past.
// A queryable index of events will be maintained.
EnableHistoricFilterAPI 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
Events Events
}
type Events struct {
// EnableEthRPC enables APIs that
// DisableRealTimeFilterAPI will disable the RealTimeFilterAPI that can create and query filters for actor events as they are emitted.
// The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.
DisableRealTimeFilterAPI bool
// DisableHistoricFilterAPI will disable the HistoricFilterAPI that can create and query filters for actor events
// that occurred in the past. HistoricFilterAPI maintains a queryable index of events.
// The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.
DisableHistoricFilterAPI bool
// FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than
// this time become eligible for automatic deletion.
@ -681,11 +696,11 @@ type ActorEventConfig struct {
// the entire chain)
MaxFilterHeightRange uint64
// ActorEventDatabasePath is the full path to a sqlite database that will be used to index actor events to
// DatabasePath is the full path to a sqlite database that will be used to index actor events to
// support the historic filter APIs. If the database does not exist it will be created. The directory containing
// the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as
// relative to the CWD (current working directory).
ActorEventDatabasePath string
DatabasePath string
// Others, not implemented yet:
// Set a limit on the number of active websocket subscriptions (may be zero)

View File

@ -4,106 +4,118 @@ import (
"context"
"errors"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
)
var ErrImplementMe = errors.New("Not implemented yet")
var ErrModuleDisabled = errors.New("module disabled, enable with Fevm.EnableEthRPC / LOTUS_FEVM_ENABLEETHPRC")
type EthModuleDummy struct{}
func (e *EthModuleDummy) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) {
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) {
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe
return 0, ErrModuleDisabled
}
func (e *EthModuleDummy) EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) {
return nil, ErrImplementMe
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe
return 0, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe
return 0, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) {
return ethtypes.EthBlock{}, ErrImplementMe
return ethtypes.EthBlock{}, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) {
return ethtypes.EthBlock{}, ErrImplementMe
return ethtypes.EthBlock{}, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) {
return nil, ErrImplementMe
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe
return 0, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) {
return nil, ErrImplementMe
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) {
return ethtypes.EthTx{}, ErrImplementMe
return ethtypes.EthTx{}, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) {
return ethtypes.EthTx{}, ErrImplementMe
return ethtypes.EthTx{}, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) {
return nil, ErrImplementMe
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) {
return nil, ErrImplementMe
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) {
return ethtypes.EthBigIntZero, ErrImplementMe
return ethtypes.EthBigIntZero, ErrModuleDisabled
}
func (e *EthModuleDummy) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) {
return ethtypes.EthFeeHistory{}, ErrImplementMe
return ethtypes.EthFeeHistory{}, ErrModuleDisabled
}
func (e *EthModuleDummy) EthChainId(ctx context.Context) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe
return 0, ErrModuleDisabled
}
func (e *EthModuleDummy) NetVersion(ctx context.Context) (string, error) {
return "", ErrImplementMe
return "", ErrModuleDisabled
}
func (e *EthModuleDummy) NetListening(ctx context.Context) (bool, error) {
return false, ErrImplementMe
return false, ErrModuleDisabled
}
func (e *EthModuleDummy) EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe
return 0, ErrModuleDisabled
}
func (e *EthModuleDummy) EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) {
return ethtypes.EthBigIntZero, ErrImplementMe
return ethtypes.EthBigIntZero, ErrModuleDisabled
}
func (e *EthModuleDummy) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) {
return 0, ErrImplementMe
return 0, ErrModuleDisabled
}
func (e *EthModuleDummy) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) {
return nil, ErrImplementMe
return nil, ErrModuleDisabled
}
func (e *EthModuleDummy) EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) {
return ethtypes.EthBigIntZero, ErrImplementMe
return ethtypes.EthBigIntZero, ErrModuleDisabled
}
func (e *EthModuleDummy) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) {
return ethtypes.EthHash{}, ErrImplementMe
return ethtypes.EthHash{}, ErrModuleDisabled
}
var _ EthModuleAPI = &EthModuleDummy{}

View File

@ -21,11 +21,13 @@ import (
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/evm"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors"
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/messagepool"
"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)
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, 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)
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, 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
// within the HEAD tipset.
type EthModule struct {
fx.In
Chain *store.ChainStore
Mpool *messagepool.MessagePool
StateManager *stmgr.StateManager
Chain *store.ChainStore
Mpool *messagepool.MessagePool
StateManager *stmgr.StateManager
EthTxHashManager *EthTxHashManager
ChainAPI
MpoolAPI
@ -254,10 +257,18 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
return nil, nil
}
cid := txHash.ToCid()
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
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 {
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI)
if err == nil {
@ -274,8 +285,8 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
}
for _, p := range pending {
if p.Cid() == cid {
tx, err := newEthTxFromFilecoinMessage(ctx, p, a.StateAPI)
if p.Cid() == c {
tx, err := NewEthTxFromFilecoinMessage(ctx, p, a.StateAPI)
if err != nil {
return nil, fmt.Errorf("could not convert Filecoin message into tx: %s", err)
}
@ -286,6 +297,53 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
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, 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) {
addr, err := sender.ToFilecoinAddress()
if err != nil {
@ -305,10 +363,18 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.
}
func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) {
cid := txHash.ToCid()
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, cid, api.LookbackNoLimit, true)
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, c, api.LookbackNoLimit, true)
if err != nil || msgLookup == nil {
return nil, nil
}
@ -317,7 +383,7 @@ func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtype
return nil, nil
}
replay, err := a.StateAPI.StateReplay(ctx, types.EmptyTSK, cid)
replay, err := a.StateAPI.StateReplay(ctx, types.EmptyTSK, c)
if err != nil {
return nil, nil
}
@ -640,11 +706,12 @@ func (a *EthModule) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.Et
smsg.Message.Method = builtinactors.MethodSend
}
cid, err := a.MpoolAPI.MpoolPush(ctx, smsg)
_, err = a.MpoolAPI.MpoolPush(ctx, smsg)
if err != nil {
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) {
@ -791,7 +858,7 @@ func (e *EthEvent) EthGetLogs(ctx context.Context, filterSpec *ethtypes.EthFilte
_ = 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) {
@ -806,11 +873,11 @@ func (e *EthEvent) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilte
switch fc := f.(type) {
case filterEventCollector:
return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx))
return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx), e.SubManager.StateAPI)
case filterTipSetCollector:
return ethFilterResultFromTipSets(fc.TakeCollectedTipSets(ctx))
case filterMessageCollector:
return ethFilterResultFromMessages(fc.TakeCollectedMessages(ctx))
return ethFilterResultFromMessages(fc.TakeCollectedMessages(ctx), e.SubManager.StateAPI)
}
return nil, xerrors.Errorf("unknown filter type")
@ -828,7 +895,7 @@ func (e *EthEvent) EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID
switch fc := f.(type) {
case filterEventCollector:
return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx))
return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx), e.SubManager.StateAPI)
}
return nil, xerrors.Errorf("wrong filter type")
@ -885,18 +952,20 @@ func (e *EthEvent) installEthFilterSpec(ctx context.Context, filterSpec *ethtype
// Here the client is looking for events between the head and some future height
ts := e.Chain.GetHeaviestTipSet()
if maxHeight-ts.Height() > e.MaxFilterHeightRange {
return nil, xerrors.Errorf("invalid epoch range")
return nil, xerrors.Errorf("invalid epoch range: to block is too far in the future (maximum: %d)", e.MaxFilterHeightRange)
}
} else if minHeight >= 0 && maxHeight == -1 {
// Here the client is looking for events between some time in the past and the current head
ts := e.Chain.GetHeaviestTipSet()
if ts.Height()-minHeight > e.MaxFilterHeightRange {
return nil, xerrors.Errorf("invalid epoch range")
return nil, xerrors.Errorf("invalid epoch range: from block is too far in the past (maximum: %d)", e.MaxFilterHeightRange)
}
} else if minHeight >= 0 && maxHeight >= 0 {
if minHeight > maxHeight || maxHeight-minHeight > e.MaxFilterHeightRange {
return nil, xerrors.Errorf("invalid epoch range")
if minHeight > maxHeight {
return nil, xerrors.Errorf("invalid epoch range: to block (%d) must be after from block (%d)", minHeight, maxHeight)
} else if maxHeight-minHeight > e.MaxFilterHeightRange {
return nil, xerrors.Errorf("invalid epoch range: range between to and from blocks is too large (maximum: %d)", e.MaxFilterHeightRange)
}
}
@ -912,13 +981,16 @@ func (e *EthEvent) installEthFilterSpec(ctx context.Context, filterSpec *ethtype
}
for idx, vals := range filterSpec.Topics {
if len(vals) == 0 {
continue
}
// Ethereum topics are emitted using `LOG{0..4}` opcodes resulting in topics1..4
key := fmt.Sprintf("topic%d", idx+1)
keyvals := make([][]byte, len(vals))
for i, v := range vals {
keyvals[i] = v[:]
for _, v := range vals {
buf := make([]byte, len(v[:]))
copy(buf, v[:])
keys[key] = append(keys[key], buf)
}
keys[key] = keyvals
}
return e.EventFilterManager.Install(ctx, minHeight, maxHeight, tipsetCid, addresses, keys)
@ -1141,14 +1213,14 @@ type filterEventCollector interface {
}
type filterMessageCollector interface {
TakeCollectedMessages(context.Context) []cid.Cid
TakeCollectedMessages(context.Context) []*types.SignedMessage
}
type filterTipSetCollector interface {
TakeCollectedTipSets(context.Context) []types.TipSetKey
}
func ethFilterResultFromEvents(evs []*filter.CollectedEvent) (*ethtypes.EthFilterResult, error) {
func ethFilterResultFromEvents(evs []*filter.CollectedEvent, sa StateAPI) (*ethtypes.EthFilterResult, error) {
res := &ethtypes.EthFilterResult{}
for _, ev := range evs {
log := ethtypes.EthLog{
@ -1161,7 +1233,7 @@ func ethFilterResultFromEvents(evs []*filter.CollectedEvent) (*ethtypes.EthFilte
var err error
for _, entry := range ev.Entries {
value := ethtypes.EthBytes(leftpad32(decodeLogBytes(entry.Value)))
value := ethtypes.EthBytes(leftpad32(entry.Value)) // value has already been cbor-decoded but see https://github.com/filecoin-project/ref-fvm/issues/1345
if entry.Key == ethtypes.EthTopic1 || entry.Key == ethtypes.EthTopic2 || entry.Key == ethtypes.EthTopic3 || entry.Key == ethtypes.EthTopic4 {
log.Topics = append(log.Topics, value)
} else {
@ -1174,11 +1246,10 @@ func ethFilterResultFromEvents(evs []*filter.CollectedEvent) (*ethtypes.EthFilte
return nil, err
}
log.TransactionHash, err = ethtypes.EthHashFromCid(ev.MsgCid)
log.TransactionHash, err = EthTxHashFromFilecoinMessageCid(context.TODO(), ev.MsgCid, sa)
if err != nil {
return nil, err
}
c, err := ev.TipSetKey.Cid()
if err != nil {
return nil, err
@ -1213,11 +1284,11 @@ func ethFilterResultFromTipSets(tsks []types.TipSetKey) (*ethtypes.EthFilterResu
return res, nil
}
func ethFilterResultFromMessages(cs []cid.Cid) (*ethtypes.EthFilterResult, error) {
func ethFilterResultFromMessages(cs []*types.SignedMessage, sa StateAPI) (*ethtypes.EthFilterResult, error) {
res := &ethtypes.EthFilterResult{}
for _, c := range cs {
hash, err := ethtypes.EthHashFromCid(c)
hash, err := EthTxHashFromSignedFilecoinMessage(context.TODO(), c, sa)
if err != nil {
return nil, err
}
@ -1316,7 +1387,7 @@ func (e *ethSubscription) start(ctx context.Context) {
var err error
switch vt := v.(type) {
case *filter.CollectedEvent:
resp.Result, err = ethFilterResultFromEvents([]*filter.CollectedEvent{vt})
resp.Result, err = ethFilterResultFromEvents([]*filter.CollectedEvent{vt}, e.StateAPI)
case *types.TipSet:
eb, err := newEthBlockFromFilecoinTipSet(ctx, vt, true, e.Chain, e.ChainAPI, e.StateAPI)
if err != nil {
@ -1391,18 +1462,15 @@ func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTx
}
gasUsed += msgLookup.Receipt.GasUsed
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, txIdx, cs, sa)
if err != nil {
return ethtypes.EthBlock{}, nil
}
if fullTxInfo {
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, txIdx, cs, sa)
if err != nil {
return ethtypes.EthBlock{}, nil
}
block.Transactions = append(block.Transactions, tx)
} else {
hash, err := ethtypes.EthHashFromCid(msg.Cid())
if err != nil {
return ethtypes.EthBlock{}, err
}
block.Transactions = append(block.Transactions, hash.String())
block.Transactions = append(block.Transactions, tx.Hash.String())
}
}
@ -1454,19 +1522,42 @@ func lookupEthAddress(ctx context.Context, addr address.Address, sa StateAPI) (e
return ethtypes.EthAddressFromFilecoinAddress(idAddr)
}
func newEthTxFromFilecoinMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthTx, error) {
fromEthAddr, err := lookupEthAddress(ctx, smsg.Message.From, sa)
if err != nil {
return ethtypes.EthTx{}, err
func EthTxHashFromFilecoinMessageCid(ctx context.Context, c cid.Cid, sa StateAPI) (ethtypes.EthHash, error) {
smsg, err := sa.Chain.GetSignedMessage(ctx, c)
if err == nil {
// 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)
if err != nil {
return ethtypes.EthTx{}, err
_, err = sa.Chain.GetMessage(ctx, c)
if err == nil {
// 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
input := smsg.Message.Params
var err error
// 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).
if smsg.Message.To == builtintypes.EthereumAddressManagerActorAddr {
@ -1505,26 +1596,38 @@ func newEthTxFromFilecoinMessage(ctx context.Context, smsg *types.SignedMessage,
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{
Hash: hash,
Nonce: ethtypes.EthUint64(smsg.Message.Nonce),
ChainID: ethtypes.EthUint64(build.Eip155ChainId),
From: fromEthAddr,
To: toAddr,
Value: ethtypes.EthBigInt(smsg.Message.Value),
Type: ethtypes.EthUint64(2),
Input: input,
Gas: ethtypes.EthUint64(smsg.Message.GasLimit),
MaxFeePerGas: ethtypes.EthBigInt(smsg.Message.GasFeeCap),
MaxPriorityFeePerGas: ethtypes.EthBigInt(smsg.Message.GasPremium),
V: v,
R: r,
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
@ -1537,11 +1640,6 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
if msgLookup == nil {
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)
if err != nil {
@ -1583,10 +1681,21 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
smsg, err := cs.GetSignedMessage(ctx, msgLookup.Message)
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 {
return ethtypes.EthTx{}, err
}
@ -1597,7 +1706,6 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
)
tx.ChainID = ethtypes.EthUint64(build.Eip155ChainId)
tx.Hash = txHash
tx.BlockHash = &blkHash
tx.BlockNumber = &bn
tx.TransactionIndex = &ti
@ -1668,7 +1776,7 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook
}
for _, entry := range evt.Entries {
value := ethtypes.EthBytes(leftpad32(decodeLogBytes(entry.Value)))
value := ethtypes.EthBytes(leftpad32(entry.Value)) // value has already been cbor-decoded but see https://github.com/filecoin-project/ref-fvm/issues/1345
if entry.Key == ethtypes.EthTopic1 || entry.Key == ethtypes.EthTopic2 || entry.Key == ethtypes.EthTopic3 || entry.Key == ethtypes.EthTopic4 {
l.Topics = append(l.Topics, value)
} else {
@ -1701,19 +1809,82 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook
return receipt, nil
}
// decodeLogBytes decodes a CBOR-serialized array into its original form.
//
// This function swallows errors and returns the original array if it failed
// to decode.
func decodeLogBytes(orig []byte) []byte {
if orig == nil {
return orig
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
}
}
}
decoded, err := cbg.ReadByteArray(bytes.NewReader(orig), uint64(len(orig)))
if err != nil {
return orig
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)
}
return decoded
}
// TODO we could also emit full EVM words from the EVM runtime, but not doing so

View File

@ -11,9 +11,11 @@ import (
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/messagesigner"
"github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/chain/wallet/key"
"github.com/filecoin-project/lotus/lib/sigs"
)
@ -51,12 +53,20 @@ func (a *WalletAPI) WalletSignMessage(ctx context.Context, k address.Address, ms
return nil, xerrors.Errorf("failed to resolve ID address: %w", keyAddr)
}
keyInfo, err := a.Wallet.WalletExport(ctx, k)
if err != nil {
return nil, err
}
sb, err := messagesigner.SigningBytes(msg, key.ActSigType(keyInfo.Type))
if err != nil {
return nil, err
}
mb, err := msg.ToStorageBlock()
if err != nil {
return nil, xerrors.Errorf("serializing message: %w", err)
}
sig, err := a.Wallet.WalletSign(ctx, keyAddr, mb.Cid().Bytes(), api.MsgMeta{
sig, err := a.Wallet.WalletSign(ctx, keyAddr, sb, api.MsgMeta{
Type: api.MTChainMsg,
Extra: mb.RawData(),
})

View File

@ -2,6 +2,7 @@ package modules
import (
"context"
"path/filepath"
"time"
"github.com/multiformats/go-varint"
@ -20,6 +21,7 @@ import (
"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"
)
type EventAPI struct {
@ -31,16 +33,16 @@ type EventAPI struct {
var _ events.EventAPI = &EventAPI{}
func EthEventAPI(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI) (*full.EthEvent, error) {
return func(mctx helpers.MetricsCtx, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi full.ChainAPI) (*full.EthEvent, error) {
func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo, fx.Lifecycle, *store.ChainStore, *stmgr.StateManager, EventAPI, *messagepool.MessagePool, full.StateAPI, full.ChainAPI) (*full.EthEvent, 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) (*full.EthEvent, error) {
ctx := helpers.LifecycleCtx(mctx, lc)
ee := &full.EthEvent{
Chain: cs,
MaxFilterHeightRange: abi.ChainEpoch(cfg.MaxFilterHeightRange),
MaxFilterHeightRange: abi.ChainEpoch(cfg.Events.MaxFilterHeightRange),
}
if !cfg.EnableRealTimeFilterAPI {
if !cfg.EnableEthRPC || cfg.Events.DisableRealTimeFilterAPI {
// all event functionality is disabled
// the historic filter API relies on the real time one
return ee, nil
@ -51,21 +53,32 @@ func EthEventAPI(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecy
StateAPI: stateapi,
ChainAPI: chainapi,
}
ee.FilterStore = filter.NewMemFilterStore(cfg.MaxFilters)
ee.FilterStore = filter.NewMemFilterStore(cfg.Events.MaxFilters)
// Start garbage collection for filters
lc.Append(fx.Hook{
OnStart: func(context.Context) error {
go ee.GC(ctx, time.Duration(cfg.FilterTTL))
go ee.GC(ctx, time.Duration(cfg.Events.FilterTTL))
return nil
},
})
// Enable indexing of actor events
var eventIndex *filter.EventIndex
if cfg.EnableHistoricFilterAPI {
if !cfg.Events.DisableHistoricFilterAPI {
var dbPath string
if cfg.Events.DatabasePath == "" {
sqlitePath, err := r.SqlitePath()
if err != nil {
return nil, err
}
dbPath = filepath.Join(sqlitePath, "events.db")
} else {
dbPath = cfg.Events.DatabasePath
}
var err error
eventIndex, err = filter.NewEventIndex(cfg.ActorEventDatabasePath)
eventIndex, err = filter.NewEventIndex(dbPath)
if err != nil {
return nil, err
}
@ -103,13 +116,13 @@ func EthEventAPI(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecy
return *actor.Address, true
},
MaxFilterResults: cfg.MaxFilterResults,
MaxFilterResults: cfg.Events.MaxFilterResults,
}
ee.TipSetFilterManager = &filter.TipSetFilterManager{
MaxFilterResults: cfg.MaxFilterResults,
MaxFilterResults: cfg.Events.MaxFilterResults,
}
ee.MemPoolFilterManager = &filter.MemPoolFilterManager{
MaxFilterResults: cfg.MaxFilterResults,
MaxFilterResults: cfg.Events.MaxFilterResults,
}
const ChainHeadConfidence = 1

79
node/modules/ethmodule.go Normal file
View File

@ -0,0 +1,79 @@
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) {
sqlitePath, err := r.SqlitePath()
if err != nil {
return nil, err
}
transactionHashLookup, err := ethhashlookup.NewTransactionHashLookup(filepath.Join(sqlitePath, "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,
}
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(&ethTxHashManager)
ch, err := mp.Updates(ctx)
if err != nil {
return err
}
go full.WaitForMpoolUpdates(ctx, ch, &ethTxHashManager)
go full.EthTxHashGC(ctx, cfg.EthTxHashMappingLifetimeDays, &ethTxHashManager)
return nil
},
})
return &full.EthModule{
Chain: cs,
Mpool: mp,
StateManager: sm,
ChainAPI: chainapi,
MpoolAPI: mpoolapi,
StateAPI: stateapi,
EthTxHashManager: &ethTxHashManager,
}, nil
}
}

View File

@ -37,6 +37,7 @@ const (
fsDatastore = "datastore"
fsLock = "repo.lock"
fsKeystore = "keystore"
fsSqlite = "sqlite"
)
func NewRepoTypeFromString(t string) RepoType {
@ -411,6 +412,10 @@ type fsLockedRepo struct {
ssErr error
ssOnce sync.Once
sqlPath string
sqlErr error
sqlOnce sync.Once
storageLk sync.Mutex
configLk sync.Mutex
}
@ -515,6 +520,21 @@ func (fsr *fsLockedRepo) SplitstorePath() (string, error) {
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
func (fsr *fsLockedRepo) join(paths ...string) string {
return filepath.Join(append([]string{fsr.path}, paths...)...)

View File

@ -69,6 +69,9 @@ type LockedRepo interface {
// SplitstorePath returns the path for the SplitStore
SplitstorePath() (string, error)
// SqlitePath returns the path for the Sqlite database
SqlitePath() (string, error)
// Returns config in this repo
Config() (interface{}, error)
SetConfig(func(interface{})) error

View File

@ -277,6 +277,14 @@ func (lmem *lockedMemRepo) SplitstorePath() (string, error) {
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) {
return nil, nil
}

View File

@ -1,26 +0,0 @@
#!/usr/bin/env bash
set -ex
REQUIRED=(
"ipfs"
"sha512sum"
)
for REQUIRE in "${REQUIRED[@]}"
do
command -v "${REQUIRE}" >/dev/null 2>&1 || echo >&2 "'${REQUIRE}' must be installed"
done
mkdir bundle
pushd bundle
export IPFS_PATH=`mktemp -d`
ipfs init
ipfs daemon &
PID="$!"
trap "kill -9 ${PID}" EXIT
sleep 30
cp "/tmp/workspace/appimage/Lotus-${CIRCLE_TAG}-x86_64.AppImage" .
sha512sum "Lotus-${CIRCLE_TAG}-x86_64.AppImage" > "Lotus-${CIRCLE_TAG}-x86_64.AppImage.sha512"
ipfs add -q "Lotus-${CIRCLE_TAG}-x86_64.AppImage" > "Lotus-${CIRCLE_TAG}-x86_64.AppImage.cid"
popd

View File

@ -1,46 +0,0 @@
#!/usr/bin/env bash
set -ex
ARCH=$1
REQUIRED=(
"ipfs"
"sha512sum"
)
for REQUIRE in "${REQUIRED[@]}"
do
command -v "${REQUIRE}" >/dev/null 2>&1 || echo >&2 "'${REQUIRE}' must be installed"
done
mkdir bundle
pushd bundle
BINARIES=(
"lotus"
"lotus-miner"
"lotus-worker"
)
export IPFS_PATH=`mktemp -d`
ipfs init
ipfs daemon &
PID="$!"
trap "kill -9 ${PID}" EXIT
sleep 30
mkdir -p "${ARCH}/lotus"
pushd "${ARCH}"
for BINARY in "${BINARIES[@]}"
do
cp "../../${ARCH}/${BINARY}" "lotus/"
chmod +x "lotus/${BINARY}"
done
tar -zcvf "../lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz" lotus
popd
rm -rf "${ARCH}"
sha512sum "lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz" > "lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz.sha512"
ipfs add -q "lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz" > "lotus_${CIRCLE_TAG}_${ARCH}-amd64.tar.gz.cid"
popd

View File

@ -1,121 +0,0 @@
#!/usr/bin/env bash
set -e
ARCH=$1
pushd bundle
# make sure we have a token set, api requests won't work otherwise
if [ -z "${GITHUB_TOKEN}" ]; then
echo "\${GITHUB_TOKEN} not set, publish failed"
exit 1
fi
REQUIRED=(
"jq"
"curl"
)
for REQUIRE in "${REQUIRED[@]}"
do
command -v "${REQUIRE}" >/dev/null 2>&1 || echo >&2 "'${REQUIRE}' must be installed"
done
#see if the release already exists by tag
RELEASE_RESPONSE=`
curl \
--header "Authorization: token ${GITHUB_TOKEN}" \
"https://api.github.com/repos/${CIRCLE_PROJECT_USERNAME}/${CIRCLE_PROJECT_REPONAME}/releases/tags/${CIRCLE_TAG}"
`
RELEASE_ID=`echo "${RELEASE_RESPONSE}" | jq '.id'`
if [ "${RELEASE_ID}" = "null" ]; then
echo "creating release"
COND_CREATE_DISCUSSION=""
PRERELEASE=true
if [[ ${CIRCLE_TAG} =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
COND_CREATE_DISCUSSION="\"discussion_category_name\": \"announcement\","
PRERELEASE=false
fi
RELEASE_DATA="{
\"tag_name\": \"${CIRCLE_TAG}\",
\"target_commitish\": \"${CIRCLE_SHA1}\",
${COND_CREATE_DISCUSSION}
\"name\": \"${CIRCLE_TAG}\",
\"body\": \"\",
\"prerelease\": ${PRERELEASE}
}"
# create it if it doesn't exist yet
RELEASE_RESPONSE=`
curl \
--request POST \
--header "Authorization: token ${GITHUB_TOKEN}" \
--header "Content-Type: application/json" \
--data "${RELEASE_DATA}" \
"https://api.github.com/repos/$CIRCLE_PROJECT_USERNAME/${CIRCLE_PROJECT_REPONAME}/releases"
`
else
echo "release already exists"
fi
RELEASE_UPLOAD_URL=`echo "${RELEASE_RESPONSE}" | jq -r '.upload_url' | cut -d'{' -f1`
echo "Preparing to send artifacts to ${RELEASE_UPLOAD_URL}"
if [ $ARCH = 'linux' ]; then
artifacts=(
"lotus_${CIRCLE_TAG}_linux-amd64.tar.gz"
"lotus_${CIRCLE_TAG}_linux-amd64.tar.gz.cid"
"lotus_${CIRCLE_TAG}_linux-amd64.tar.gz.sha512"
)
elif [ $ARCH = 'darwin' ]; then
artifacts=(
"lotus_${CIRCLE_TAG}_darwin-amd64.tar.gz"
"lotus_${CIRCLE_TAG}_darwin-amd64.tar.gz.cid"
"lotus_${CIRCLE_TAG}_darwin-amd64.tar.gz.sha512"
)
elif [ $ARCH = 'appimage' ]; then
artifacts=(
"Lotus-${CIRCLE_TAG}-x86_64.AppImage"
"Lotus-${CIRCLE_TAG}-x86_64.AppImage.cid"
"Lotus-${CIRCLE_TAG}-x86_64.AppImage.sha512"
)
else
echo "$1 is not a supported architecture to publish a release for" 1>&2
exit 1
fi
for RELEASE_FILE in "${artifacts[@]}"
do
echo "Uploading ${RELEASE_FILE}..."
curl \
--request POST \
--fail \
--header "Authorization: token ${GITHUB_TOKEN}" \
--header "Content-Type: application/octet-stream" \
--data-binary "@${RELEASE_FILE}" \
"$RELEASE_UPLOAD_URL?name=$(basename "${RELEASE_FILE}")"
echo "Uploaded ${RELEASE_FILE}"
done
popd
miscellaneous=(
"README.md"
"LICENSE-MIT"
"LICENSE-APACHE"
)
for MISC in "${miscellaneous[@]}"
do
echo "Uploading release bundle: ${MISC}"
curl \
--request POST \
--header "Authorization: token ${GITHUB_TOKEN}" \
--header "Content-Type: application/octet-stream" \
--data-binary "@${MISC}" \
"$RELEASE_UPLOAD_URL?name=$(basename "${MISC}")"
echo "Release bundle uploaded: ${MISC}"
done