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/generate-checksums.sh
- run: ./scripts/publish-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: gofmt:
executor: golang executor: golang
working_directory: ~/lotus working_directory: ~/lotus
@ -572,7 +522,7 @@ jobs:
equal: [ mainnet, <<parameters.network>> ] equal: [ mainnet, <<parameters.network>> ]
steps: steps:
- when: - when:
condition: <parameters.push>> condition: <<parameters.push>>
steps: steps:
- docker/build: - docker/build:
image: filecoin/<<parameters.image>> image: filecoin/<<parameters.image>>
@ -583,7 +533,7 @@ jobs:
command: | command: |
docker push filecoin/<<parameters.image>>:<<parameters.channel>> docker push filecoin/<<parameters.image>>:<<parameters.channel>>
if [[ ! -z $CIRCLE_SHA ]]; then 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}" docker push filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"
fi fi
if [[ ! -z $CIRCLE_TAG ]]; then if [[ ! -z $CIRCLE_TAG ]]; then
@ -611,7 +561,7 @@ jobs:
- run: - run:
name: Docker push name: Docker push
command: | command: |
docker push filecoin/<<parameters.image>>:<<parameters.channel>>-<<parameters.network>> docker push filecoin/<<parameters.image>>:<<parameters.channel>>
if [[ ! -z $CIRCLE_SHA ]]; then 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 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>> docker push filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"-<<parameters.network>>
@ -785,6 +735,11 @@ workflows:
- build - build
suite: itest-eth_balance suite: itest-eth_balance
target: "./itests/eth_balance_test.go" 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: - test:
name: test-itest-eth_deploy name: test-itest-eth_deploy
requires: requires:
@ -797,6 +752,11 @@ workflows:
- build - build
suite: itest-eth_filter suite: itest-eth_filter
target: "./itests/eth_filter_test.go" target: "./itests/eth_filter_test.go"
- test:
name: test-itest-eth_hash_lookup
suite: itest-eth_hash_lookup
target: "./itests/eth_hash_lookup_test.go"
- test: - test:
name: test-itest-eth_transactions name: test-itest-eth_transactions
requires: requires:
@ -1182,71 +1142,6 @@ workflows:
branches: branches:
only: only:
- /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - /^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: - build-docker:
name: "Docker push (lotus-all-in-one / stable / mainnet)" name: "Docker push (lotus-all-in-one / stable / mainnet)"
image: lotus-all-in-one image: lotus-all-in-one
@ -1482,14 +1377,6 @@ workflows:
only: only:
- master - master
jobs: 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: - build-docker:
name: "Docker (lotus-all-in-one / nightly / mainnet)" name: "Docker (lotus-all-in-one / nightly / mainnet)"
image: lotus-all-in-one image: lotus-all-in-one

View File

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

View File

@ -355,56 +355,6 @@ jobs:
- run: ./scripts/generate-checksums.sh - run: ./scripts/generate-checksums.sh
- run: ./scripts/publish-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: gofmt:
executor: golang executor: golang
working_directory: ~/lotus working_directory: ~/lotus
@ -572,7 +522,7 @@ jobs:
equal: [ mainnet, <<parameters.network>> ] equal: [ mainnet, <<parameters.network>> ]
steps: steps:
- when: - when:
condition: <parameters.push>> condition: <<parameters.push>>
steps: steps:
- docker/build: - docker/build:
image: filecoin/<<parameters.image>> image: filecoin/<<parameters.image>>
@ -583,7 +533,7 @@ jobs:
command: | command: |
docker push filecoin/<<parameters.image>>:<<parameters.channel>> docker push filecoin/<<parameters.image>>:<<parameters.channel>>
if [["[[ ! -z $CIRCLE_SHA ]]"]]; then 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}" docker push filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"
fi fi
if [["[[ ! -z $CIRCLE_TAG ]]"]]; then if [["[[ ! -z $CIRCLE_TAG ]]"]]; then
@ -611,7 +561,7 @@ jobs:
- run: - run:
name: Docker push name: Docker push
command: | command: |
docker push filecoin/<<parameters.image>>:<<parameters.channel>>-<<parameters.network>> docker push filecoin/<<parameters.image>>:<<parameters.channel>>
if [["[[ ! -z $CIRCLE_SHA ]]"]]; then 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 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>> docker push filecoin/<<parameters.image>>:"${CIRCLE_SHA:0:7}"-<<parameters.network>>
@ -743,51 +693,6 @@ workflows:
branches: branches:
only: only:
- /^release\/v\d+\.\d+\.\d+(-rc\d+)?$/ - /^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]] [[- range .Networks]]
- build-docker: - build-docker:
name: "Docker push (lotus-all-in-one / stable / [[.]])" name: "Docker push (lotus-all-in-one / stable / [[.]])"
@ -890,12 +795,6 @@ workflows:
only: only:
- master - master
jobs: jobs:
[[- range .SnapNames]]
- publish-snapcraft:
name: "Publish Snapcraft ([[.]] / edge)"
channel: edge
snap-name: [[.]]
[[- end]]
[[- range .Networks]] [[- range .Networks]]
- build-docker: - build-docker:
name: "Docker (lotus-all-in-one / nightly / [[.]])" name: "Docker (lotus-all-in-one / nightly / [[.]])"

View File

@ -84,12 +84,6 @@ butterflynet: build-devnets
interopnet: GOFLAGS+=-tags=interopnet interopnet: GOFLAGS+=-tags=interopnet
interopnet: build-devnets interopnet: build-devnets
wallabynet: GOFLAGS+=-tags=wallabynet
wallabynet: build-devnets
hyperspacenet: GOFLAGS+=-tags=hyperspacenet
hyperspacenet: build-devnets
lotus: $(BUILD_DEPS) lotus: $(BUILD_DEPS)
rm -f lotus rm -f lotus
$(GOCC) build $(GOFLAGS) -o lotus ./cmd/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 EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read
EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) //perm:read
EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) //perm:read
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) //perm:read EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) //perm:read
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read

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) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetLogs", reflect.TypeOf((*MockFullNode)(nil).EthGetLogs), arg0, arg1)
} }
// EthGetMessageCidByTransactionHash mocks base method.
func (m *MockFullNode) EthGetMessageCidByTransactionHash(arg0 context.Context, arg1 *ethtypes.EthHash) (*cid.Cid, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetMessageCidByTransactionHash", arg0, arg1)
ret0, _ := ret[0].(*cid.Cid)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetMessageCidByTransactionHash indicates an expected call of EthGetMessageCidByTransactionHash.
func (mr *MockFullNodeMockRecorder) EthGetMessageCidByTransactionHash(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetMessageCidByTransactionHash", reflect.TypeOf((*MockFullNode)(nil).EthGetMessageCidByTransactionHash), arg0, arg1)
}
// EthGetStorageAt mocks base method. // EthGetStorageAt mocks base method.
func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 string) (ethtypes.EthBytes, error) { func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 string) (ethtypes.EthBytes, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()
@ -1252,6 +1267,21 @@ func (mr *MockFullNodeMockRecorder) EthGetTransactionCount(arg0, arg1, arg2 inte
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionCount", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionCount), arg0, arg1, arg2) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionCount", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionCount), arg0, arg1, arg2)
} }
// EthGetTransactionHashByCid mocks base method.
func (m *MockFullNode) EthGetTransactionHashByCid(arg0 context.Context, arg1 cid.Cid) (*ethtypes.EthHash, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "EthGetTransactionHashByCid", arg0, arg1)
ret0, _ := ret[0].(*ethtypes.EthHash)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// EthGetTransactionHashByCid indicates an expected call of EthGetTransactionHashByCid.
func (mr *MockFullNodeMockRecorder) EthGetTransactionHashByCid(arg0, arg1 interface{}) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionHashByCid", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionHashByCid), arg0, arg1)
}
// EthGetTransactionReceipt mocks base method. // EthGetTransactionReceipt mocks base method.
func (m *MockFullNode) EthGetTransactionReceipt(arg0 context.Context, arg1 ethtypes.EthHash) (*api.EthTxReceipt, error) { func (m *MockFullNode) EthGetTransactionReceipt(arg0 context.Context, arg1 ethtypes.EthHash) (*api.EthTxReceipt, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -253,6 +253,8 @@ type FullNodeStruct struct {
EthGetLogs func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) `perm:"read"` EthGetLogs func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) `perm:"read"`
EthGetMessageCidByTransactionHash func(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) `perm:"read"`
EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) `perm:"read"` EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) `perm:"read"`
EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `perm:"read"` EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `perm:"read"`
@ -263,6 +265,8 @@ type FullNodeStruct struct {
EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `perm:"read"` EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `perm:"read"`
EthGetTransactionHashByCid func(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) `perm:"read"`
EthGetTransactionReceipt func(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) `perm:"read"` EthGetTransactionReceipt func(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) `perm:"read"`
EthMaxPriorityFeePerGas func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"` EthMaxPriorityFeePerGas func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"`
@ -2117,6 +2121,17 @@ func (s *FullNodeStub) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec
return nil, ErrNotSupported return nil, ErrNotSupported
} }
func (s *FullNodeStruct) EthGetMessageCidByTransactionHash(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) {
if s.Internal.EthGetMessageCidByTransactionHash == nil {
return nil, ErrNotSupported
}
return s.Internal.EthGetMessageCidByTransactionHash(p0, p1)
}
func (s *FullNodeStub) EthGetMessageCidByTransactionHash(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) {
return nil, ErrNotSupported
}
func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) { func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) {
if s.Internal.EthGetStorageAt == nil { if s.Internal.EthGetStorageAt == nil {
return *new(ethtypes.EthBytes), ErrNotSupported return *new(ethtypes.EthBytes), ErrNotSupported
@ -2172,6 +2187,17 @@ func (s *FullNodeStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.Et
return *new(ethtypes.EthUint64), ErrNotSupported return *new(ethtypes.EthUint64), ErrNotSupported
} }
func (s *FullNodeStruct) EthGetTransactionHashByCid(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) {
if s.Internal.EthGetTransactionHashByCid == nil {
return nil, ErrNotSupported
}
return s.Internal.EthGetTransactionHashByCid(p0, p1)
}
func (s *FullNodeStub) EthGetTransactionHashByCid(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) {
return nil, ErrNotSupported
}
func (s *FullNodeStruct) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) { func (s *FullNodeStruct) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) {
if s.Internal.EthGetTransactionReceipt == nil { if s.Internal.EthGetTransactionReceipt == nil {
return nil, ErrNotSupported return nil, ErrNotSupported

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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 //go:build !debug && !2k && !testground && !calibnet && !butterflynet && !interopnet
// +build !debug,!2k,!testground,!calibnet,!butterflynet,!interopnet,!wallabynet,!hyperspacenet // +build !debug,!2k,!testground,!calibnet,!butterflynet,!interopnet
package build package build

View File

@ -42,9 +42,6 @@ var (
AllowableClockDriftSecs = uint64(1) AllowableClockDriftSecs = uint64(1)
Finality = policy.ChainFinality
ForkLengthThreshold = Finality
SlashablePowerDelay = 20 SlashablePowerDelay = 20
InteractivePoRepConfidence = 6 InteractivePoRepConfidence = 6
@ -130,6 +127,9 @@ var (
GenesisFile = "" GenesisFile = ""
) )
const Finality = policy.ChainFinality
const ForkLengthThreshold = Finality
const BootstrapPeerThreshold = 1 const BootstrapPeerThreshold = 1
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint. // 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 var BuildType int
const ( const (
BuildDefault = 0 BuildDefault = 0
BuildMainnet = 0x1 BuildMainnet = 0x1
Build2k = 0x2 Build2k = 0x2
BuildDebug = 0x3 BuildDebug = 0x3
BuildCalibnet = 0x4 BuildCalibnet = 0x4
BuildInteropnet = 0x5 BuildInteropnet = 0x5
BuildButterflynet = 0x7 BuildButterflynet = 0x7
BuildWallabynet = 0x8
BuildHyperspacenet = 0x9
) )
func BuildTypeString() string { func BuildTypeString() string {
@ -33,10 +31,6 @@ func BuildTypeString() string {
return "+interopnet" return "+interopnet"
case BuildButterflynet: case BuildButterflynet:
return "+butterflynet" return "+butterflynet"
case BuildWallabynet:
return "+wallabynet"
case BuildHyperspacenet:
return "+hyperspacenet"
default: default:
return "+huh?" 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 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 // event matches filter, so record it
cev := &CollectedEvent{ cev := &CollectedEvent{
Entries: ev.Entries, Entries: decodedEntries,
EmitterAddr: addr, EmitterAddr: addr,
EventIdx: evIdx, EventIdx: evIdx,
Reverted: revert, Reverted: revert,
@ -266,13 +275,13 @@ func (te *TipSetEvents) messages(ctx context.Context) ([]executedMessage, error)
} }
type executedMessage struct { type executedMessage struct {
msg *types.Message msg types.ChainMsg
rct *types.MessageReceipt rct *types.MessageReceipt
// events extracted from receipt // events extracted from receipt
evs []*types.Event evs []*types.Event
} }
func (e *executedMessage) Message() *types.Message { func (e *executedMessage) Message() types.ChainMsg {
return e.msg return e.msg
} }
@ -428,7 +437,7 @@ func (m *EventFilterManager) loadExecutedMessages(ctx context.Context, msgTs, rc
ems := make([]executedMessage, len(msgs)) ems := make([]executedMessage, len(msgs))
for i := 0; i < len(msgs); i++ { for i := 0; i < len(msgs); i++ {
ems[i].msg = msgs[i].VMMessage() ems[i].msg = msgs[i]
var rct types.MessageReceipt var rct types.MessageReceipt
found, err := arr.Get(uint64(i), &rct) 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 // This function swallows errors and returns the original array if it failed
// to decode. // to decode.
func decodeLogBytes(orig []byte) []byte { func decodeLogBytes(orig []byte) []byte {
if orig == nil { if len(orig) == 0 {
return orig return orig
} }
decoded, err := cbg.ReadByteArray(bytes.NewReader(orig), uint64(len(orig))) decoded, err := cbg.ReadByteArray(bytes.NewReader(orig), uint64(len(orig)))

View File

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

View File

@ -13,10 +13,13 @@ import (
"golang.org/x/xerrors" "golang.org/x/xerrors"
"github.com/filecoin-project/go-address" "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/api"
"github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/messagepool"
"github.com/filecoin-project/lotus/chain/types" "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" "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 // Sign the message with the nonce
msg.Nonce = 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() mb, err := msg.ToStorageBlock()
if err != nil { if err != nil {
return nil, xerrors.Errorf("serializing message: %w", err) 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, Type: api.MTChainMsg,
Extra: mb.RawData(), Extra: mb.RawData(),
}) })
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to sign message: %w, addr=%s", err, msg.From) 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 { func (ms *MessageSigner) dstoreKey(addr address.Address) datastore.Key {
return datastore.KeyWithNamespaces([]string{dsKeyActorNonce, addr.String()}) 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" "github.com/filecoin-project/lotus/chain/types"
) )
const TipsetkeyBackfillRange = 2 * build.Finality
func (cs *ChainStore) UnionStore() bstore.Blockstore { func (cs *ChainStore) UnionStore() bstore.Blockstore {
return bstore.Union(cs.stateBlockstore, cs.chainBlockstore) return bstore.Union(cs.stateBlockstore, cs.chainBlockstore)
} }
@ -113,6 +115,20 @@ func (cs *ChainStore) Import(ctx context.Context, r io.Reader) (*types.TipSet, e
return nil, xerrors.Errorf("failed to load root tipset from chainfile: %w", err) return nil, xerrors.Errorf("failed to load root tipset from chainfile: %w", err)
} }
ts := root
for i := 0; i < int(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 return root, nil
} }

View File

@ -384,7 +384,19 @@ func (cs *ChainStore) PutTipSet(ctx context.Context, ts *types.TipSet) error {
if err != nil { if err != nil {
return xerrors.Errorf("errored while expanding tipset: %w", err) 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 { if err := cs.MaybeTakeHeavierTipSet(ctx, expanded); err != nil {
return xerrors.Errorf("MaybeTakeHeavierTipSet failed in PutTipSet: %w", err) return xerrors.Errorf("MaybeTakeHeavierTipSet failed in PutTipSet: %w", err)
@ -1097,6 +1109,10 @@ func (cs *ChainStore) StateBlockstore() bstore.Blockstore {
return cs.stateBlockstore return cs.stateBlockstore
} }
func (cs *ChainStore) ChainLocalBlockstore() bstore.Blockstore {
return cs.chainLocalBlockstore
}
func ActorStore(ctx context.Context, bs bstore.Blockstore) adt.Store { func ActorStore(ctx context.Context, bs bstore.Blockstore) adt.Store {
return adt.WrapStore(ctx, cbor.NewCborStore(bs)) return adt.WrapStore(ctx, cbor.NewCborStore(bs))
} }

View File

@ -8,6 +8,7 @@ import (
"testing" "testing"
"github.com/ipfs/go-datastore" "github.com/ipfs/go-datastore"
"github.com/stretchr/testify/require"
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
"github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/crypto"
@ -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) { func TestChainExportImportFull(t *testing.T) {
//stm: @CHAIN_GEN_NEXT_TIPSET_001 //stm: @CHAIN_GEN_NEXT_TIPSET_001
//stm: @CHAIN_STORE_IMPORT_001, @CHAIN_STORE_EXPORT_001, @CHAIN_STORE_SET_HEAD_001 //stm: @CHAIN_STORE_IMPORT_001, @CHAIN_STORE_EXPORT_001, @CHAIN_STORE_SET_HEAD_001

View File

@ -231,6 +231,36 @@ func (tx *EthTxArgs) ToRlpUnsignedMsg() ([]byte, error) {
return append([]byte{0x02}, encoded...), nil return append([]byte{0x02}, encoded...), nil
} }
func (tx *EthTx) ToEthTxArgs() EthTxArgs {
return EthTxArgs{
ChainID: int(tx.ChainID),
Nonce: int(tx.Nonce),
To: tx.To,
Value: big.Int(tx.Value),
MaxFeePerGas: big.Int(tx.MaxFeePerGas),
MaxPriorityFeePerGas: big.Int(tx.MaxPriorityFeePerGas),
GasLimit: int(tx.Gas),
Input: tx.Input,
V: big.Int(tx.V),
R: big.Int(tx.R),
S: big.Int(tx.S),
}
}
func (tx *EthTx) TxHash() (EthHash, error) {
ethTxArgs := tx.ToEthTxArgs()
return (&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) { func (tx *EthTxArgs) ToRlpSignedMsg() ([]byte, error) {
packed1, err := tx.packTxFields() packed1, err := tx.packTxFields()
if err != nil { if err != nil {

View File

@ -36,10 +36,7 @@ var ErrInvalidAddress = errors.New("invalid Filecoin Eth address")
type EthUint64 uint64 type EthUint64 uint64
func (e EthUint64) MarshalJSON() ([]byte, error) { func (e EthUint64) MarshalJSON() ([]byte, error) {
if e == 0 { return json.Marshal(e.Hex())
return json.Marshal("0x0")
}
return json.Marshal(fmt.Sprintf("0x%x", e))
} }
func (e *EthUint64) UnmarshalJSON(b []byte) error { func (e *EthUint64) UnmarshalJSON(b []byte) error {
@ -64,6 +61,13 @@ func EthUint64FromHex(s string) (EthUint64, error) {
return EthUint64(parsedInt), nil 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". // EthBigInt represents a large integer whose zero value serializes to "0x0".
type EthBigInt big.Int type EthBigInt big.Int
@ -360,14 +364,7 @@ func (h *EthHash) UnmarshalJSON(b []byte) error {
} }
func decodeHexString(s string, expectedLen int) ([]byte, error) { func decodeHexString(s string, expectedLen int) ([]byte, error) {
// Strip the leading 0x or 0X prefix since hex.DecodeString does not support it. s = handleHexStringPrefix(s)
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
}
if len(s) != expectedLen*2 { if len(s) != expectedLen*2 {
return nil, xerrors.Errorf("expected hex string length sans prefix %d, got %d", expectedLen*2, len(s)) 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 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) { func EthHashFromCid(c cid.Cid) (EthHash, error) {
return ParseEthHash(c.Hash().HexString()[8:]) return ParseEthHash(c.Hash().HexString()[8:])
} }
@ -392,10 +410,21 @@ func ParseEthHash(s string) (EthHash, error) {
return h, nil return h, nil
} }
func EthHashFromTxBytes(b []byte) EthHash {
hasher := sha3.NewLegacyKeccak256()
hasher.Write(b)
hash := hasher.Sum(nil)
var ethHash EthHash
copy(ethHash[:], hash)
return ethHash
}
func (h EthHash) String() string { func (h EthHash) String() string {
return "0x" + hex.EncodeToString(h[:]) return "0x" + hex.EncodeToString(h[:])
} }
// Should ONLY be used for blocks and Filecoin messages. Eth transactions expect a different hashing scheme.
func (h EthHash) ToCid() cid.Cid { func (h EthHash) ToCid() cid.Cid {
// err is always nil // err is always nil
mh, _ := multihash.EncodeName(h[:], "blake2b-256") mh, _ := multihash.EncodeName(h[:], "blake2b-256")
@ -556,7 +585,7 @@ type EthLog struct {
// The index corresponds to the sequence of messages produced by ChainGetParentMessages // The index corresponds to the sequence of messages produced by ChainGetParentMessages
TransactionIndex EthUint64 `json:"transactionIndex"` TransactionIndex EthUint64 `json:"transactionIndex"`
// TransactionHash is the cid of the message that produced the event log. // TransactionHash is the hash of the RLP message that produced the event log.
TransactionHash EthHash `json:"transactionHash"` TransactionHash EthHash `json:"transactionHash"`
// BlockHash is the hash of the tipset containing the message that produced the log. // BlockHash is the hash of the tipset containing the message that produced the log.

View File

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

View File

@ -13,6 +13,7 @@ import (
"github.com/filecoin-project/lotus/chain/actors/builtin" "github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
) )
var sendCmd = &cli.Command{ var sendCmd = &cli.Command{
@ -24,6 +25,10 @@ var sendCmd = &cli.Command{
Name: "from", Name: "from",
Usage: "optionally specify the account to send funds 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{ &cli.StringFlag{
Name: "gas-premium", Name: "gas-premium",
Usage: "specify gas price to use in AttoFIL", Usage: "specify gas price to use in AttoFIL",
@ -98,6 +103,18 @@ var sendCmd = &cli.Command{
} }
params.From = addr 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") { 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("Nonce:\t\t%d\n", a.Nonce)
fmt.Printf("Code:\t\t%s (%s)\n", a.Code, strtype) fmt.Printf("Code:\t\t%s (%s)\n", a.Code, strtype)
fmt.Printf("Head:\t\t%s\n", a.Head) 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 return nil
}, },

View File

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

View File

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

View File

@ -293,53 +293,71 @@
#Tracing = false #Tracing = false
[ActorEvent] [Fevm]
# EnableRealTimeFilterAPI enables APIs that can create and query filters for actor events as they are emitted. # 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 # type: bool
# env var: LOTUS_ACTOREVENT_ENABLEREALTIMEFILTERAPI # env var: LOTUS_FEVM_ENABLEETHRPC
#EnableRealTimeFilterAPI = false #EnableEthRPC = false
# EnableHistoricFilterAPI enables APIs that can create and query filters for actor events that occurred in the past. # EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
# A queryable index of events will be maintained. # Set to 0 to keep all mappings
#
# 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.
# #
# type: int # type: int
# env var: LOTUS_ACTOREVENT_MAXFILTERS # env var: LOTUS_FEVM_ETHTXHASHMAPPINGLIFETIMEDAYS
#MaxFilters = 100 #EthTxHashMappingLifetimeDays = 0
# MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter. [Fevm.Events]
# # EnableEthRPC enables APIs that
# type: int # DisableRealTimeFilterAPI will disable the RealTimeFilterAPI that can create and query filters for actor events as they are emitted.
# env var: LOTUS_ACTOREVENT_MAXFILTERRESULTS # The API is enabled when EnableEthRPC is true, but can be disabled selectively with this flag.
#MaxFilterResults = 10000 #
# 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 # DisableHistoricFilterAPI will disable the HistoricFilterAPI that can create and query filters for actor events
# the entire chain) # 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: uint64 #
# env var: LOTUS_ACTOREVENT_MAXFILTERHEIGHTRANGE # type: bool
#MaxFilterHeightRange = 2880 # 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 # FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than
# support the historic filter APIs. If the database does not exist it will be created. The directory containing # this time become eligible for automatic deletion.
# 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: Duration
# # env var: LOTUS_FEVM_EVENTS_FILTERTTL
# type: string #FilterTTL = "24h0m0s"
# env var: LOTUS_ACTOREVENT_ACTOREVENTDATABASEPATH
#ActorEventDatabasePath = "" # 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) dh := kit.NewDealHarness(t, client, miner, miner)
ctx := context.Background() 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 // Create a random file, would originally be a 256-byte sector
res, inFile := client.CreateImportFile(ctx, 1, 200) res, inFile := client.CreateImportFile(ctx, 1, 200)

View File

@ -52,7 +52,7 @@ func TestFirstDealEnablesMining(t *testing.T) {
providerMined := make(chan struct{}) providerMined := make(chan struct{})
go func() { go func() {
_ = client.WaitTillChain(ctx, kit.BlockMinedBy(provider.ActorAddr)) _ = client.WaitTillChain(ctx, kit.BlocksMinedByAll(provider.ActorAddr))
close(providerMined) 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"
"github.com/filecoin-project/lotus/chain/types/ethtypes" "github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/itests/kit"
"github.com/filecoin-project/lotus/node/config"
) )
// TestDeployment smoke tests the deployment of a contract via the // TestDeployment smoke tests the deployment of a contract via the
@ -36,12 +35,7 @@ func TestDeployment(t *testing.T) {
client, _, ens := kit.EnsembleMinimal( client, _, ens := kit.EnsembleMinimal(
t, t,
kit.MockProofs(), kit.MockProofs(),
kit.ThroughRPC(), kit.ThroughRPC())
kit.WithCfgOpt(func(cfg *config.FullNode) error {
cfg.ActorEvent.EnableRealTimeFilterAPI = true
return nil
}),
)
ens.InterconnectAll().BeginMining(blockTime) ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
@ -99,6 +93,7 @@ func TestDeployment(t *testing.T) {
mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash) mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash)
require.NoError(t, err) require.NoError(t, err)
require.NotNil(t, mpoolTx)
// require that the hashes are identical // require that the hashes are identical
require.Equal(t, hash, mpoolTx.Hash) 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/go-address"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/itests/kit" "github.com/filecoin-project/lotus/itests/kit"
) )
@ -45,22 +46,22 @@ func TestFEVMEvents(t *testing.T) {
require.NoError(err) require.NoError(err)
t.Logf("actor ID address is %s", idAddr) t.Logf("actor ID address is %s", idAddr)
// var ( var (
// earliest = "earliest" earliest = "earliest"
// latest = "latest" latest = "latest"
// ) )
//
// // Install a filter. // Install a filter.
// filter, err := client.EthNewFilter(ctx, &api.EthFilterSpec{ filter, err := client.EthNewFilter(ctx, &ethtypes.EthFilterSpec{
// FromBlock: &earliest, FromBlock: &earliest,
// ToBlock: &latest, ToBlock: &latest,
// }) })
// require.NoError(err) require.NoError(err)
//
// // No logs yet. // No logs yet.
// res, err := client.EthGetFilterLogs(ctx, filter) res, err := client.EthGetFilterLogs(ctx, filter)
// require.NoError(err) require.NoError(err)
// require.Empty(res.NewLogs) require.Empty(res.Results)
// log a zero topic event with data // log a zero topic event with data
ret := client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x00}, nil) ret := client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x00}, nil)

View File

@ -1,67 +1,64 @@
package itests package itests
import ( import (
"bytes"
"context" "context"
"encoding/hex" "encoding/hex"
"os"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
cbg "github.com/whyrusleeping/cbor-gen"
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
builtintypes "github.com/filecoin-project/go-state-types/builtin" builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/go-state-types/manifest"
"github.com/filecoin-project/lotus/chain/types" "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/itests/kit"
) )
// TestFEVMBasic does a basic fevm contract installation and invocation // convert a simple byte array into input data which is a left padded 32 byte array
func TestFEVMBasic(t *testing.T) { func inputDataFromArray(input []byte) []byte {
// TODO the contract installation and invocation can be lifted into utility methods inputData := make([]byte, 32)
// He who writes the second test, shall do that. copy(inputData[32-len(input):], input[:])
kit.QuietMiningLogs() 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 blockTime := 100 * time.Millisecond
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC()) client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
ens.InterconnectAll().BeginMining(blockTime) ens.InterconnectAll().BeginMining(blockTime)
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 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() defer cancel()
filename := "contracts/SimpleCoin.hex"
// install contract // install contract
contractHex, err := os.ReadFile("contracts/SimpleCoin.hex") fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
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)
// invoke the contract with owner // invoke the contract with owner
{ {
entryPoint, err := hex.DecodeString("f8b2cb4f") inputData := inputDataFromFrom(ctx, t, client, fromAddr)
require.NoError(t, err) result := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData)
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)
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000002710") expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000002710")
require.NoError(t, err) require.NoError(t, err)
@ -70,34 +67,19 @@ func TestFEVMBasic(t *testing.T) {
// invoke the contract with non owner // invoke the contract with non owner
{ {
entryPoint, err := hex.DecodeString("f8b2cb4f") inputData := inputDataFromFrom(ctx, t, client, fromAddr)
require.NoError(t, err) 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)
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)
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000") expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, result, expectedResult) require.Equal(t, result, expectedResult)
} }
} }
// TestFEVMETH0 tests that the ETH0 actor is in genesis // TestFEVMETH0 tests that the ETH0 actor is in genesis
func TestFEVMETH0(t *testing.T) { func TestFEVMETH0(t *testing.T) {
kit.QuietMiningLogs() ctx, cancel, client := setupFEVMTest(t)
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)
defer cancel() defer cancel()
eth0id, err := address.NewIDAddress(1001) eth0id, err := address.NewIDAddress(1001)
@ -112,3 +94,48 @@ func TestFEVMETH0(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, *act.Address, eth0Addr) 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" "bytes"
"context" "context"
"encoding/binary" "encoding/binary"
"encoding/hex"
"fmt" "fmt"
"os"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
"github.com/multiformats/go-varint" "github.com/multiformats/go-varint"
@ -77,6 +79,26 @@ func (e *EVM) DeployContract(ctx context.Context, sender address.Address, byteco
return result 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 { func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte) *api.MsgLookup {
require := require.New(e.t) 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:]) 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. // TODO: cleanup and put somewhere reusable.
type apiIpldStore struct { type apiIpldStore struct {
ctx context.Context ctx context.Context

View File

@ -1,6 +1,9 @@
package kit package kit
import ( import (
"io"
"log"
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
"github.com/filecoin-project/lotus/lib/lotuslog" "github.com/filecoin-project/lotus/lib/lotuslog"
@ -20,3 +23,13 @@ func QuietMiningLogs() {
_ = logging.SetLogLevel("rpc", "ERROR") _ = logging.SetLogLevel("rpc", "ERROR")
_ = logging.SetLogLevel("dht/RtRefreshManager", "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 // BlocksMinedByAll returns a ChainPredicate that is satisfied when we observe a
// first block mined by the specified miner. // tipset including blocks from all the specified miners, in no particular order.
func BlockMinedBy(miner address.Address) ChainPredicate { func BlocksMinedByAll(miner ...address.Address) ChainPredicate {
return func(ts *types.TipSet) bool { return func(ts *types.TipSet) bool {
seen := make([]bool, len(miner))
var done int
for _, b := range ts.Blocks() { for _, b := range ts.Blocks() {
if b.Miner == miner { for i, m := range miner {
return true if b.Miner != m || seen[i] {
continue
}
seen[i] = true
if done++; done == len(miner) {
return true
}
} }
} }
return false return false

View File

@ -58,6 +58,15 @@ var DefaultNodeOpts = nodeOpts{
sectors: DefaultPresealsPerBootstrapMiner, sectors: DefaultPresealsPerBootstrapMiner,
sectorSize: abi.SectorSize(2 << 10), // 2KiB. 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}, workerTasks: []sealtasks.TaskType{sealtasks.TTFetch, sealtasks.TTCommit1, sealtasks.TTFinalize, sealtasks.TTFinalizeUnsealed},
workerStorageOpt: func(store paths.Store) paths.Store { return store }, 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 { return WithCfgOpt(func(cfg *config.FullNode) error {
cfg.ActorEvent.EnableRealTimeFilterAPI = true cfg.Fevm.EnableEthRPC = true
return nil return nil
}) })
} }
func HistoricFilterAPI(dbpath string) NodeOpt { func DisableEthRPC() NodeOpt {
return WithCfgOpt(func(cfg *config.FullNode) error { return WithCfgOpt(func(cfg *config.FullNode) error {
cfg.ActorEvent.EnableRealTimeFilterAPI = true cfg.Fevm.EnableEthRPC = false
cfg.ActorEvent.EnableHistoricFilterAPI = true
cfg.ActorEvent.ActorEventDatabasePath = dbpath
return nil 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 { func ipldExists(ctx context.Context, t *testing.T, c cid.Cid, n *kit.TestFullNode) bool {
_, err := n.ChainReadObj(ctx, c) found, err := n.ChainHasObj(ctx, c)
if ipld.IsNotFound(err) { if err != nil {
return false t.Fatalf("ChainHasObj failure: %s", err)
} else if err != nil {
t.Fatalf("ChainReadObj failure on existence check: %s", err)
} }
return true return found
} }
// Create on chain unreachable garbage for a network to exercise splitstore // 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 return false
} else if err != nil { } else if err != nil {
g.t.Fatalf("ChainReadObj failure on existence check: %s", err) g.t.Fatalf("ChainReadObj failure on existence check: %s", err)
return false // unreachable
} else { } else {
return true return true
} }
g.t.Fatal("unreachable")
return false
} }
func (g *Garbager) newPeerID(ctx context.Context) abi.ChainEpoch { 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 { 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 return nil

View File

@ -161,7 +161,6 @@ var ChainNode = Options(
Override(new(messagepool.Provider), messagepool.NewProvider), Override(new(messagepool.Provider), messagepool.NewProvider),
Override(new(messagepool.MpoolNonceAPI), From(new(*messagepool.MessagePool))), Override(new(messagepool.MpoolNonceAPI), From(new(*messagepool.MessagePool))),
Override(new(full.ChainModuleAPI), From(new(full.ChainModule))), Override(new(full.ChainModuleAPI), From(new(full.ChainModule))),
Override(new(full.EthModuleAPI), From(new(full.EthModule))),
Override(new(full.GasModuleAPI), From(new(full.GasModule))), Override(new(full.GasModuleAPI), From(new(full.GasModule))),
Override(new(full.MpoolModuleAPI), From(new(full.MpoolModule))), Override(new(full.MpoolModuleAPI), From(new(full.MpoolModule))),
Override(new(full.StateModuleAPI), From(new(full.StateModule))), Override(new(full.StateModuleAPI), From(new(full.StateModule))),
@ -260,7 +259,10 @@ func ConfigFullNode(c interface{}) Option {
// Actor event filtering support // Actor event filtering support
Override(new(events.EventAPI), From(new(modules.EventAPI))), Override(new(events.EventAPI), From(new(modules.EventAPI))),
// in lite-mode Eth event api is provided by gateway // in lite-mode Eth event api is provided by gateway
ApplyIf(isFullNode, Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.ActorEvent))), ApplyIf(isFullNode, Override(new(full.EthEventAPI), modules.EthEventAPI(cfg.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(), Cluster: *DefaultUserRaftConfig(),
ActorEvent: ActorEventConfig{ Fevm: FevmConfig{
EnableRealTimeFilterAPI: false, EnableEthRPC: false,
EnableHistoricFilterAPI: false, EthTxHashMappingLifetimeDays: 0,
FilterTTL: Duration(time.Hour * 24), Events: Events{
MaxFilters: 100, DisableRealTimeFilterAPI: false,
MaxFilterResults: 10000, DisableHistoricFilterAPI: false,
MaxFilterHeightRange: 2880, // conservative limit of one day 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: ``, 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{ "Backup": []DocField{
{ {
Name: "DisableMetadataLog", Name: "DisableMetadataLog",
@ -391,6 +341,59 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
Comment: ``, 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{ "FeeConfig": []DocField{
{ {
Name: "DefaultMaxFee", Name: "DefaultMaxFee",
@ -399,6 +402,28 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
Comment: ``, 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{ "FullNode": []DocField{
{ {
Name: "Client", Name: "Client",
@ -431,8 +456,8 @@ see https://lotus.filecoin.io/storage-providers/advanced-configurations/market/#
Comment: ``, Comment: ``,
}, },
{ {
Name: "ActorEvent", Name: "Fevm",
Type: "ActorEventConfig", Type: "FevmConfig",
Comment: ``, Comment: ``,
}, },

View File

@ -27,7 +27,7 @@ type FullNode struct {
Fees FeeConfig Fees FeeConfig
Chainstore Chainstore Chainstore Chainstore
Cluster UserRaftConfig Cluster UserRaftConfig
ActorEvent ActorEventConfig Fevm FevmConfig
} }
// // Common // // Common
@ -659,13 +659,28 @@ type UserRaftConfig struct {
Tracing bool Tracing bool
} }
type ActorEventConfig struct { type FevmConfig struct {
// EnableRealTimeFilterAPI enables APIs that can create and query filters for actor events as they are emitted. // EnableEthRPC enables eth_ rpc, and enables storing a mapping of eth transaction hashes to filecoin message Cids.
EnableRealTimeFilterAPI bool // 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. // EthTxHashMappingLifetimeDays the transaction hash lookup database will delete mappings that have been stored for more than x days
// A queryable index of events will be maintained. // Set to 0 to keep all mappings
EnableHistoricFilterAPI bool 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 // 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. // this time become eligible for automatic deletion.
@ -681,11 +696,11 @@ type ActorEventConfig struct {
// the entire chain) // the entire chain)
MaxFilterHeightRange uint64 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 // 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 // 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). // relative to the CWD (current working directory).
ActorEventDatabasePath string DatabasePath string
// Others, not implemented yet: // Others, not implemented yet:
// Set a limit on the number of active websocket subscriptions (may be zero) // Set a limit on the number of active websocket subscriptions (may be zero)

View File

@ -4,106 +4,118 @@ import (
"context" "context"
"errors" "errors"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain/types/ethtypes" "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{} 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { func (e *EthModuleDummy) NetVersion(ctx context.Context) (string, error) {
return "", ErrImplementMe return "", ErrModuleDisabled
} }
func (e *EthModuleDummy) NetListening(ctx context.Context) (bool, error) { 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) { 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) { 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) { 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) { 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) { 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) { 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" builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/filecoin-project/go-state-types/builtin/v10/eam" "github.com/filecoin-project/go-state-types/builtin/v10/eam"
"github.com/filecoin-project/go-state-types/builtin/v10/evm" "github.com/filecoin-project/go-state-types/builtin/v10/evm"
"github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/actors" "github.com/filecoin-project/lotus/chain/actors"
builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin" builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin"
"github.com/filecoin-project/lotus/chain/ethhashlookup"
"github.com/filecoin-project/lotus/chain/events/filter" "github.com/filecoin-project/lotus/chain/events/filter"
"github.com/filecoin-project/lotus/chain/messagepool" "github.com/filecoin-project/lotus/chain/messagepool"
"github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/stmgr"
@ -43,6 +45,8 @@ type EthModuleAPI interface {
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error)
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error)
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error)
EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error)
EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error)
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error)
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error)
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error)
@ -107,11 +111,10 @@ var (
// accepts as the best parent tipset, based on the blocks it is accumulating // accepts as the best parent tipset, based on the blocks it is accumulating
// within the HEAD tipset. // within the HEAD tipset.
type EthModule struct { type EthModule struct {
fx.In Chain *store.ChainStore
Mpool *messagepool.MessagePool
Chain *store.ChainStore StateManager *stmgr.StateManager
Mpool *messagepool.MessagePool EthTxHashManager *EthTxHashManager
StateManager *stmgr.StateManager
ChainAPI ChainAPI
MpoolAPI MpoolAPI
@ -254,10 +257,18 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
return nil, nil 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 // first, try to get the cid from mined transactions
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, cid, api.LookbackNoLimit, true) msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, c, api.LookbackNoLimit, true)
if err == nil { if err == nil {
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI) tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI)
if err == nil { if err == nil {
@ -274,8 +285,8 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
} }
for _, p := range pending { for _, p := range pending {
if p.Cid() == cid { if p.Cid() == c {
tx, err := newEthTxFromFilecoinMessage(ctx, p, a.StateAPI) tx, err := NewEthTxFromFilecoinMessage(ctx, p, a.StateAPI)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not convert Filecoin message into tx: %s", err) return nil, fmt.Errorf("could not convert Filecoin message into tx: %s", err)
} }
@ -286,6 +297,53 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
return nil, nil return nil, nil
} }
func (a *EthModule) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) {
// Ethereum's behavior is to return null when the txHash is invalid, so we use nil to check if txHash is valid
if txHash == nil {
return nil, nil
}
c, err := a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(*txHash)
// We fall out of the first condition and continue
if errors.Is(err, ethhashlookup.ErrNotFound) {
log.Debug("could not find transaction hash %s in lookup table", txHash.String())
} else if err != nil {
return nil, xerrors.Errorf("database error: %w", err)
} else {
return &c, nil
}
// This isn't an eth transaction we have the mapping for, so let's try looking it up as a filecoin message
if c == cid.Undef {
c = txHash.ToCid()
}
_, err = a.StateAPI.Chain.GetSignedMessage(ctx, c)
if err == nil {
// This is an Eth Tx, Secp message, Or BLS message in the mpool
return &c, nil
}
_, err = a.StateAPI.Chain.GetMessage(ctx, c)
if err == nil {
// This is a BLS message
return &c, nil
}
// Ethereum clients expect an empty response when the message was not found
return nil, nil
}
func (a *EthModule) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) {
hash, err := EthTxHashFromFilecoinMessageCid(ctx, cid, a.StateAPI)
if hash == ethtypes.EmptyEthHash {
// not found
return nil, nil
}
return &hash, err
}
func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam string) (ethtypes.EthUint64, error) { func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkParam string) (ethtypes.EthUint64, error) {
addr, err := sender.ToFilecoinAddress() addr, err := sender.ToFilecoinAddress()
if err != nil { if err != nil {
@ -305,10 +363,18 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.
} }
func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) { func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*api.EthTxReceipt, error) {
cid := txHash.ToCid() c, err := a.EthTxHashManager.TransactionHashLookup.GetCidFromHash(txHash)
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, cid, api.LookbackNoLimit, true)
if err != nil { 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 return nil, nil
} }
@ -317,7 +383,7 @@ func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtype
return nil, nil return nil, nil
} }
replay, err := a.StateAPI.StateReplay(ctx, types.EmptyTSK, cid) replay, err := a.StateAPI.StateReplay(ctx, types.EmptyTSK, c)
if err != nil { if err != nil {
return nil, nil return nil, nil
} }
@ -640,11 +706,12 @@ func (a *EthModule) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.Et
smsg.Message.Method = builtinactors.MethodSend smsg.Message.Method = builtinactors.MethodSend
} }
cid, err := a.MpoolAPI.MpoolPush(ctx, smsg) _, err = a.MpoolAPI.MpoolPush(ctx, smsg)
if err != nil { if err != nil {
return ethtypes.EmptyEthHash, err return ethtypes.EmptyEthHash, err
} }
return ethtypes.EthHashFromCid(cid)
return ethtypes.EthHashFromTxBytes(rawTx), nil
} }
func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.EthCall) (*types.Message, error) { func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.EthCall) (*types.Message, error) {
@ -791,7 +858,7 @@ func (e *EthEvent) EthGetLogs(ctx context.Context, filterSpec *ethtypes.EthFilte
_ = e.uninstallFilter(ctx, f) _ = e.uninstallFilter(ctx, f)
return ethFilterResultFromEvents(ces) return ethFilterResultFromEvents(ces, e.SubManager.StateAPI)
} }
func (e *EthEvent) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) { func (e *EthEvent) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {
@ -806,11 +873,11 @@ func (e *EthEvent) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilte
switch fc := f.(type) { switch fc := f.(type) {
case filterEventCollector: case filterEventCollector:
return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx)) return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx), e.SubManager.StateAPI)
case filterTipSetCollector: case filterTipSetCollector:
return ethFilterResultFromTipSets(fc.TakeCollectedTipSets(ctx)) return ethFilterResultFromTipSets(fc.TakeCollectedTipSets(ctx))
case filterMessageCollector: case filterMessageCollector:
return ethFilterResultFromMessages(fc.TakeCollectedMessages(ctx)) return ethFilterResultFromMessages(fc.TakeCollectedMessages(ctx), e.SubManager.StateAPI)
} }
return nil, xerrors.Errorf("unknown filter type") return nil, xerrors.Errorf("unknown filter type")
@ -828,7 +895,7 @@ func (e *EthEvent) EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID
switch fc := f.(type) { switch fc := f.(type) {
case filterEventCollector: case filterEventCollector:
return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx)) return ethFilterResultFromEvents(fc.TakeCollectedEvents(ctx), e.SubManager.StateAPI)
} }
return nil, xerrors.Errorf("wrong filter type") return nil, xerrors.Errorf("wrong filter type")
@ -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 // Here the client is looking for events between the head and some future height
ts := e.Chain.GetHeaviestTipSet() ts := e.Chain.GetHeaviestTipSet()
if maxHeight-ts.Height() > e.MaxFilterHeightRange { 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 { } else if minHeight >= 0 && maxHeight == -1 {
// Here the client is looking for events between some time in the past and the current head // Here the client is looking for events between some time in the past and the current head
ts := e.Chain.GetHeaviestTipSet() ts := e.Chain.GetHeaviestTipSet()
if ts.Height()-minHeight > e.MaxFilterHeightRange { 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 { } else if minHeight >= 0 && maxHeight >= 0 {
if minHeight > maxHeight || maxHeight-minHeight > e.MaxFilterHeightRange { if minHeight > maxHeight {
return nil, xerrors.Errorf("invalid epoch range") 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 { for idx, vals := range filterSpec.Topics {
if len(vals) == 0 {
continue
}
// Ethereum topics are emitted using `LOG{0..4}` opcodes resulting in topics1..4 // Ethereum topics are emitted using `LOG{0..4}` opcodes resulting in topics1..4
key := fmt.Sprintf("topic%d", idx+1) key := fmt.Sprintf("topic%d", idx+1)
keyvals := make([][]byte, len(vals)) for _, v := range vals {
for i, v := range vals { buf := make([]byte, len(v[:]))
keyvals[i] = v[:] copy(buf, v[:])
keys[key] = append(keys[key], buf)
} }
keys[key] = keyvals
} }
return e.EventFilterManager.Install(ctx, minHeight, maxHeight, tipsetCid, addresses, keys) return e.EventFilterManager.Install(ctx, minHeight, maxHeight, tipsetCid, addresses, keys)
@ -1141,14 +1213,14 @@ type filterEventCollector interface {
} }
type filterMessageCollector interface { type filterMessageCollector interface {
TakeCollectedMessages(context.Context) []cid.Cid TakeCollectedMessages(context.Context) []*types.SignedMessage
} }
type filterTipSetCollector interface { type filterTipSetCollector interface {
TakeCollectedTipSets(context.Context) []types.TipSetKey TakeCollectedTipSets(context.Context) []types.TipSetKey
} }
func ethFilterResultFromEvents(evs []*filter.CollectedEvent) (*ethtypes.EthFilterResult, error) { func ethFilterResultFromEvents(evs []*filter.CollectedEvent, sa StateAPI) (*ethtypes.EthFilterResult, error) {
res := &ethtypes.EthFilterResult{} res := &ethtypes.EthFilterResult{}
for _, ev := range evs { for _, ev := range evs {
log := ethtypes.EthLog{ log := ethtypes.EthLog{
@ -1161,7 +1233,7 @@ func ethFilterResultFromEvents(evs []*filter.CollectedEvent) (*ethtypes.EthFilte
var err error var err error
for _, entry := range ev.Entries { 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 { if entry.Key == ethtypes.EthTopic1 || entry.Key == ethtypes.EthTopic2 || entry.Key == ethtypes.EthTopic3 || entry.Key == ethtypes.EthTopic4 {
log.Topics = append(log.Topics, value) log.Topics = append(log.Topics, value)
} else { } else {
@ -1174,11 +1246,10 @@ func ethFilterResultFromEvents(evs []*filter.CollectedEvent) (*ethtypes.EthFilte
return nil, err return nil, err
} }
log.TransactionHash, err = ethtypes.EthHashFromCid(ev.MsgCid) log.TransactionHash, err = EthTxHashFromFilecoinMessageCid(context.TODO(), ev.MsgCid, sa)
if err != nil { if err != nil {
return nil, err return nil, err
} }
c, err := ev.TipSetKey.Cid() c, err := ev.TipSetKey.Cid()
if err != nil { if err != nil {
return nil, err return nil, err
@ -1213,11 +1284,11 @@ func ethFilterResultFromTipSets(tsks []types.TipSetKey) (*ethtypes.EthFilterResu
return res, nil return res, nil
} }
func ethFilterResultFromMessages(cs []cid.Cid) (*ethtypes.EthFilterResult, error) { func ethFilterResultFromMessages(cs []*types.SignedMessage, sa StateAPI) (*ethtypes.EthFilterResult, error) {
res := &ethtypes.EthFilterResult{} res := &ethtypes.EthFilterResult{}
for _, c := range cs { for _, c := range cs {
hash, err := ethtypes.EthHashFromCid(c) hash, err := EthTxHashFromSignedFilecoinMessage(context.TODO(), c, sa)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1316,7 +1387,7 @@ func (e *ethSubscription) start(ctx context.Context) {
var err error var err error
switch vt := v.(type) { switch vt := v.(type) {
case *filter.CollectedEvent: case *filter.CollectedEvent:
resp.Result, err = ethFilterResultFromEvents([]*filter.CollectedEvent{vt}) resp.Result, err = ethFilterResultFromEvents([]*filter.CollectedEvent{vt}, e.StateAPI)
case *types.TipSet: case *types.TipSet:
eb, err := newEthBlockFromFilecoinTipSet(ctx, vt, true, e.Chain, e.ChainAPI, e.StateAPI) eb, err := newEthBlockFromFilecoinTipSet(ctx, vt, true, e.Chain, e.ChainAPI, e.StateAPI)
if err != nil { if err != nil {
@ -1391,18 +1462,15 @@ func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTx
} }
gasUsed += msgLookup.Receipt.GasUsed gasUsed += msgLookup.Receipt.GasUsed
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, txIdx, cs, sa)
if err != nil {
return ethtypes.EthBlock{}, nil
}
if fullTxInfo { if fullTxInfo {
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, txIdx, cs, sa)
if err != nil {
return ethtypes.EthBlock{}, nil
}
block.Transactions = append(block.Transactions, tx) block.Transactions = append(block.Transactions, tx)
} else { } else {
hash, err := ethtypes.EthHashFromCid(msg.Cid()) block.Transactions = append(block.Transactions, tx.Hash.String())
if err != nil {
return ethtypes.EthBlock{}, err
}
block.Transactions = append(block.Transactions, hash.String())
} }
} }
@ -1454,19 +1522,42 @@ func lookupEthAddress(ctx context.Context, addr address.Address, sa StateAPI) (e
return ethtypes.EthAddressFromFilecoinAddress(idAddr) return ethtypes.EthAddressFromFilecoinAddress(idAddr)
} }
func newEthTxFromFilecoinMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthTx, error) { func EthTxHashFromFilecoinMessageCid(ctx context.Context, c cid.Cid, sa StateAPI) (ethtypes.EthHash, error) {
fromEthAddr, err := lookupEthAddress(ctx, smsg.Message.From, sa) smsg, err := sa.Chain.GetSignedMessage(ctx, c)
if err != nil { if err == nil {
return ethtypes.EthTx{}, err // This is an Eth Tx, Secp message, Or BLS message in the mpool
return EthTxHashFromSignedFilecoinMessage(ctx, smsg, sa)
} }
toEthAddr, err := lookupEthAddress(ctx, smsg.Message.To, sa) _, err = sa.Chain.GetMessage(ctx, c)
if err != nil { if err == nil {
return ethtypes.EthTx{}, err // This is a BLS message
return ethtypes.EthHashFromCid(c)
} }
return ethtypes.EmptyEthHash, nil
}
func EthTxHashFromSignedFilecoinMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthHash, error) {
if smsg.Signature.Type == crypto.SigTypeDelegated {
ethTx, err := NewEthTxFromFilecoinMessage(ctx, smsg, sa)
if err != nil {
return ethtypes.EmptyEthHash, err
}
return ethTx.Hash, nil
}
return ethtypes.EthHashFromCid(smsg.Cid())
}
func NewEthTxFromFilecoinMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthTx, error) {
// Ignore errors here so we can still parse non-eth messages
fromEthAddr, _ := lookupEthAddress(ctx, smsg.Message.From, sa)
toEthAddr, _ := lookupEthAddress(ctx, smsg.Message.To, sa)
toAddr := &toEthAddr toAddr := &toEthAddr
input := smsg.Message.Params input := smsg.Message.Params
var err error
// Check to see if we need to decode as contract deployment. // Check to see if we need to decode as contract deployment.
// We don't need to resolve the to address, because there's only one form (an ID). // We don't need to resolve the to address, because there's only one form (an ID).
if smsg.Message.To == builtintypes.EthereumAddressManagerActorAddr { if smsg.Message.To == builtintypes.EthereumAddressManagerActorAddr {
@ -1505,26 +1596,38 @@ func newEthTxFromFilecoinMessage(ctx context.Context, smsg *types.SignedMessage,
r, s, v = ethtypes.EthBigIntZero, ethtypes.EthBigIntZero, ethtypes.EthBigIntZero r, s, v = ethtypes.EthBigIntZero, ethtypes.EthBigIntZero, ethtypes.EthBigIntZero
} }
hash, err := ethtypes.EthHashFromCid(smsg.Cid())
if err != nil {
return ethtypes.EthTx{}, err
}
tx := ethtypes.EthTx{ tx := ethtypes.EthTx{
Hash: hash,
Nonce: ethtypes.EthUint64(smsg.Message.Nonce), Nonce: ethtypes.EthUint64(smsg.Message.Nonce),
ChainID: ethtypes.EthUint64(build.Eip155ChainId), ChainID: ethtypes.EthUint64(build.Eip155ChainId),
From: fromEthAddr, From: fromEthAddr,
To: toAddr, To: toAddr,
Value: ethtypes.EthBigInt(smsg.Message.Value), Value: ethtypes.EthBigInt(smsg.Message.Value),
Type: ethtypes.EthUint64(2), Type: ethtypes.EthUint64(2),
Input: input,
Gas: ethtypes.EthUint64(smsg.Message.GasLimit), Gas: ethtypes.EthUint64(smsg.Message.GasLimit),
MaxFeePerGas: ethtypes.EthBigInt(smsg.Message.GasFeeCap), MaxFeePerGas: ethtypes.EthBigInt(smsg.Message.GasFeeCap),
MaxPriorityFeePerGas: ethtypes.EthBigInt(smsg.Message.GasPremium), MaxPriorityFeePerGas: ethtypes.EthBigInt(smsg.Message.GasPremium),
V: v, V: v,
R: r, R: r,
S: s, S: s,
Input: input, }
// This is an eth tx
if smsg.Signature.Type == crypto.SigTypeDelegated {
tx.Hash, err = tx.TxHash()
if err != nil {
return tx, err
}
} else if smsg.Signature.Type == crypto.SigTypeUnknown { // BLS Filecoin message
tx.Hash, err = ethtypes.EthHashFromCid(smsg.Message.Cid())
if err != nil {
return tx, err
}
} else { // Secp Filecoin Message
tx.Hash, err = ethtypes.EthHashFromCid(smsg.Cid())
if err != nil {
return tx, err
}
} }
return tx, nil return tx, nil
@ -1537,11 +1640,6 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
if msgLookup == nil { if msgLookup == nil {
return ethtypes.EthTx{}, fmt.Errorf("msg does not exist") return ethtypes.EthTx{}, fmt.Errorf("msg does not exist")
} }
cid := msgLookup.Message
txHash, err := ethtypes.EthHashFromCid(cid)
if err != nil {
return ethtypes.EthTx{}, err
}
ts, err := cs.LoadTipSet(ctx, msgLookup.TipSet) ts, err := cs.LoadTipSet(ctx, msgLookup.TipSet)
if err != nil { if err != nil {
@ -1583,10 +1681,21 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
smsg, err := cs.GetSignedMessage(ctx, msgLookup.Message) smsg, err := cs.GetSignedMessage(ctx, msgLookup.Message)
if err != nil { if err != nil {
return ethtypes.EthTx{}, err // We couldn't find the signed message, it might be a BLS message, so search for a regular message.
msg, err := cs.GetMessage(ctx, msgLookup.Message)
if err != nil {
return ethtypes.EthTx{}, err
}
smsg = &types.SignedMessage{
Message: *msg,
Signature: crypto.Signature{
Type: crypto.SigTypeUnknown,
Data: nil,
},
}
} }
tx, err := newEthTxFromFilecoinMessage(ctx, smsg, sa) tx, err := NewEthTxFromFilecoinMessage(ctx, smsg, sa)
if err != nil { if err != nil {
return ethtypes.EthTx{}, err return ethtypes.EthTx{}, err
} }
@ -1597,7 +1706,6 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
) )
tx.ChainID = ethtypes.EthUint64(build.Eip155ChainId) tx.ChainID = ethtypes.EthUint64(build.Eip155ChainId)
tx.Hash = txHash
tx.BlockHash = &blkHash tx.BlockHash = &blkHash
tx.BlockNumber = &bn tx.BlockNumber = &bn
tx.TransactionIndex = &ti tx.TransactionIndex = &ti
@ -1668,7 +1776,7 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook
} }
for _, entry := range evt.Entries { 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 { if entry.Key == ethtypes.EthTopic1 || entry.Key == ethtypes.EthTopic2 || entry.Key == ethtypes.EthTopic3 || entry.Key == ethtypes.EthTopic4 {
l.Topics = append(l.Topics, value) l.Topics = append(l.Topics, value)
} else { } else {
@ -1701,19 +1809,82 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook
return receipt, nil return receipt, nil
} }
// decodeLogBytes decodes a CBOR-serialized array into its original form. func (m *EthTxHashManager) Apply(ctx context.Context, from, to *types.TipSet) error {
// for _, blk := range to.Blocks() {
// This function swallows errors and returns the original array if it failed _, smsgs, err := m.StateAPI.Chain.MessagesForBlock(ctx, blk)
// to decode. if err != nil {
func decodeLogBytes(orig []byte) []byte { return err
if orig == nil { }
return orig
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 nil
return orig }
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 // 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/go-state-types/crypto"
"github.com/filecoin-project/lotus/api" "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/stmgr"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/chain/wallet/key"
"github.com/filecoin-project/lotus/lib/sigs" "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) 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() mb, err := msg.ToStorageBlock()
if err != nil { if err != nil {
return nil, xerrors.Errorf("serializing message: %w", err) 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, Type: api.MTChainMsg,
Extra: mb.RawData(), Extra: mb.RawData(),
}) })

View File

@ -2,6 +2,7 @@ package modules
import ( import (
"context" "context"
"path/filepath"
"time" "time"
"github.com/multiformats/go-varint" "github.com/multiformats/go-varint"
@ -20,6 +21,7 @@ import (
"github.com/filecoin-project/lotus/node/config" "github.com/filecoin-project/lotus/node/config"
"github.com/filecoin-project/lotus/node/impl/full" "github.com/filecoin-project/lotus/node/impl/full"
"github.com/filecoin-project/lotus/node/modules/helpers" "github.com/filecoin-project/lotus/node/modules/helpers"
"github.com/filecoin-project/lotus/node/repo"
) )
type EventAPI struct { type EventAPI struct {
@ -31,16 +33,16 @@ type EventAPI struct {
var _ events.EventAPI = &EventAPI{} 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) { 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, lc fx.Lifecycle, cs *store.ChainStore, sm *stmgr.StateManager, evapi EventAPI, mp *messagepool.MessagePool, stateapi full.StateAPI, chainapi 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) ctx := helpers.LifecycleCtx(mctx, lc)
ee := &full.EthEvent{ ee := &full.EthEvent{
Chain: cs, 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 // all event functionality is disabled
// the historic filter API relies on the real time one // the historic filter API relies on the real time one
return ee, nil return ee, nil
@ -51,21 +53,32 @@ func EthEventAPI(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecy
StateAPI: stateapi, StateAPI: stateapi,
ChainAPI: chainapi, ChainAPI: chainapi,
} }
ee.FilterStore = filter.NewMemFilterStore(cfg.MaxFilters) ee.FilterStore = filter.NewMemFilterStore(cfg.Events.MaxFilters)
// Start garbage collection for filters // Start garbage collection for filters
lc.Append(fx.Hook{ lc.Append(fx.Hook{
OnStart: func(context.Context) error { OnStart: func(context.Context) error {
go ee.GC(ctx, time.Duration(cfg.FilterTTL)) go ee.GC(ctx, time.Duration(cfg.Events.FilterTTL))
return nil return nil
}, },
}) })
// Enable indexing of actor events // Enable indexing of actor events
var eventIndex *filter.EventIndex 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 var err error
eventIndex, err = filter.NewEventIndex(cfg.ActorEventDatabasePath) eventIndex, err = filter.NewEventIndex(dbPath)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -103,13 +116,13 @@ func EthEventAPI(cfg config.ActorEventConfig) func(helpers.MetricsCtx, fx.Lifecy
return *actor.Address, true return *actor.Address, true
}, },
MaxFilterResults: cfg.MaxFilterResults, MaxFilterResults: cfg.Events.MaxFilterResults,
} }
ee.TipSetFilterManager = &filter.TipSetFilterManager{ ee.TipSetFilterManager = &filter.TipSetFilterManager{
MaxFilterResults: cfg.MaxFilterResults, MaxFilterResults: cfg.Events.MaxFilterResults,
} }
ee.MemPoolFilterManager = &filter.MemPoolFilterManager{ ee.MemPoolFilterManager = &filter.MemPoolFilterManager{
MaxFilterResults: cfg.MaxFilterResults, MaxFilterResults: cfg.Events.MaxFilterResults,
} }
const ChainHeadConfidence = 1 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" fsDatastore = "datastore"
fsLock = "repo.lock" fsLock = "repo.lock"
fsKeystore = "keystore" fsKeystore = "keystore"
fsSqlite = "sqlite"
) )
func NewRepoTypeFromString(t string) RepoType { func NewRepoTypeFromString(t string) RepoType {
@ -411,6 +412,10 @@ type fsLockedRepo struct {
ssErr error ssErr error
ssOnce sync.Once ssOnce sync.Once
sqlPath string
sqlErr error
sqlOnce sync.Once
storageLk sync.Mutex storageLk sync.Mutex
configLk sync.Mutex configLk sync.Mutex
} }
@ -515,6 +520,21 @@ func (fsr *fsLockedRepo) SplitstorePath() (string, error) {
return fsr.ssPath, fsr.ssErr return fsr.ssPath, fsr.ssErr
} }
func (fsr *fsLockedRepo) SqlitePath() (string, error) {
fsr.sqlOnce.Do(func() {
path := fsr.join(fsSqlite)
if err := os.MkdirAll(path, 0755); err != nil {
fsr.sqlErr = err
return
}
fsr.sqlPath = path
})
return fsr.sqlPath, fsr.sqlErr
}
// join joins path elements with fsr.path // join joins path elements with fsr.path
func (fsr *fsLockedRepo) join(paths ...string) string { func (fsr *fsLockedRepo) join(paths ...string) string {
return filepath.Join(append([]string{fsr.path}, paths...)...) return filepath.Join(append([]string{fsr.path}, paths...)...)

View File

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

View File

@ -277,6 +277,14 @@ func (lmem *lockedMemRepo) SplitstorePath() (string, error) {
return splitstorePath, nil return splitstorePath, nil
} }
func (lmem *lockedMemRepo) SqlitePath() (string, error) {
sqlitePath := filepath.Join(lmem.Path(), "sqlite")
if err := os.MkdirAll(sqlitePath, 0755); err != nil {
return "", err
}
return sqlitePath, nil
}
func (lmem *lockedMemRepo) ListDatastores(ns string) ([]int64, error) { func (lmem *lockedMemRepo) ListDatastores(ns string) ([]int64, error) {
return nil, nil return nil, nil
} }

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