Merge branch 'release/v1.20.0' into asr/merge-release-into-master
This commit is contained in:
commit
4f199ada40
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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 / [[.]])"
|
||||||
|
6
Makefile
6
Makefile
@ -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
|
||||||
|
@ -778,6 +778,8 @@ type FullNode interface {
|
|||||||
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
|
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
|
||||||
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
|
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
|
||||||
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read
|
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read
|
||||||
|
EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) //perm:read
|
||||||
|
EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) //perm:read
|
||||||
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) //perm:read
|
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) //perm:read
|
||||||
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read
|
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read
|
||||||
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read
|
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read
|
||||||
|
@ -1177,6 +1177,21 @@ func (mr *MockFullNodeMockRecorder) EthGetLogs(arg0, arg1 interface{}) *gomock.C
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetLogs", reflect.TypeOf((*MockFullNode)(nil).EthGetLogs), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetLogs", reflect.TypeOf((*MockFullNode)(nil).EthGetLogs), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EthGetMessageCidByTransactionHash mocks base method.
|
||||||
|
func (m *MockFullNode) EthGetMessageCidByTransactionHash(arg0 context.Context, arg1 *ethtypes.EthHash) (*cid.Cid, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "EthGetMessageCidByTransactionHash", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(*cid.Cid)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// EthGetMessageCidByTransactionHash indicates an expected call of EthGetMessageCidByTransactionHash.
|
||||||
|
func (mr *MockFullNodeMockRecorder) EthGetMessageCidByTransactionHash(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetMessageCidByTransactionHash", reflect.TypeOf((*MockFullNode)(nil).EthGetMessageCidByTransactionHash), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// EthGetStorageAt mocks base method.
|
// EthGetStorageAt mocks base method.
|
||||||
func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 string) (ethtypes.EthBytes, error) {
|
func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 string) (ethtypes.EthBytes, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@ -1252,6 +1267,21 @@ func (mr *MockFullNodeMockRecorder) EthGetTransactionCount(arg0, arg1, arg2 inte
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionCount", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionCount), arg0, arg1, arg2)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionCount", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionCount), arg0, arg1, arg2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EthGetTransactionHashByCid mocks base method.
|
||||||
|
func (m *MockFullNode) EthGetTransactionHashByCid(arg0 context.Context, arg1 cid.Cid) (*ethtypes.EthHash, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "EthGetTransactionHashByCid", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(*ethtypes.EthHash)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// EthGetTransactionHashByCid indicates an expected call of EthGetTransactionHashByCid.
|
||||||
|
func (mr *MockFullNodeMockRecorder) EthGetTransactionHashByCid(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionHashByCid", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionHashByCid), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// EthGetTransactionReceipt mocks base method.
|
// EthGetTransactionReceipt mocks base method.
|
||||||
func (m *MockFullNode) EthGetTransactionReceipt(arg0 context.Context, arg1 ethtypes.EthHash) (*api.EthTxReceipt, error) {
|
func (m *MockFullNode) EthGetTransactionReceipt(arg0 context.Context, arg1 ethtypes.EthHash) (*api.EthTxReceipt, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -253,6 +253,8 @@ type FullNodeStruct struct {
|
|||||||
|
|
||||||
EthGetLogs func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) `perm:"read"`
|
EthGetLogs func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) `perm:"read"`
|
||||||
|
|
||||||
|
EthGetMessageCidByTransactionHash func(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) `perm:"read"`
|
||||||
|
|
||||||
EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) `perm:"read"`
|
EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) `perm:"read"`
|
||||||
|
|
||||||
EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `perm:"read"`
|
EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `perm:"read"`
|
||||||
@ -263,6 +265,8 @@ type FullNodeStruct struct {
|
|||||||
|
|
||||||
EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `perm:"read"`
|
EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `perm:"read"`
|
||||||
|
|
||||||
|
EthGetTransactionHashByCid func(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) `perm:"read"`
|
||||||
|
|
||||||
EthGetTransactionReceipt func(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) `perm:"read"`
|
EthGetTransactionReceipt func(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) `perm:"read"`
|
||||||
|
|
||||||
EthMaxPriorityFeePerGas func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"`
|
EthMaxPriorityFeePerGas func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"`
|
||||||
@ -2117,6 +2121,17 @@ func (s *FullNodeStub) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec
|
|||||||
return nil, ErrNotSupported
|
return nil, ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStruct) EthGetMessageCidByTransactionHash(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) {
|
||||||
|
if s.Internal.EthGetMessageCidByTransactionHash == nil {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
return s.Internal.EthGetMessageCidByTransactionHash(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStub) EthGetMessageCidByTransactionHash(p0 context.Context, p1 *ethtypes.EthHash) (*cid.Cid, error) {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) {
|
func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) {
|
||||||
if s.Internal.EthGetStorageAt == nil {
|
if s.Internal.EthGetStorageAt == nil {
|
||||||
return *new(ethtypes.EthBytes), ErrNotSupported
|
return *new(ethtypes.EthBytes), ErrNotSupported
|
||||||
@ -2172,6 +2187,17 @@ func (s *FullNodeStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.Et
|
|||||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStruct) EthGetTransactionHashByCid(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) {
|
||||||
|
if s.Internal.EthGetTransactionHashByCid == nil {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
return s.Internal.EthGetTransactionHashByCid(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStub) EthGetTransactionHashByCid(p0 context.Context, p1 cid.Cid) (*ethtypes.EthHash, error) {
|
||||||
|
return nil, ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FullNodeStruct) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) {
|
func (s *FullNodeStruct) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) {
|
||||||
if s.Internal.EthGetTransactionReceipt == nil {
|
if s.Internal.EthGetTransactionReceipt == nil {
|
||||||
return nil, ErrNotSupported
|
return nil, ErrNotSupported
|
||||||
|
@ -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.
@ -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
|
|
@ -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.
@ -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
|
|
@ -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
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
|
@ -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?"
|
||||||
}
|
}
|
||||||
|
163
chain/ethhashlookup/eth_transaction_hash_lookup.go
Normal file
163
chain/ethhashlookup/eth_transaction_hash_lookup.go
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
package ethhashlookup
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/ipfs/go-cid"
|
||||||
|
_ "github.com/mattn/go-sqlite3"
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrNotFound = errors.New("not found")
|
||||||
|
|
||||||
|
var pragmas = []string{
|
||||||
|
"PRAGMA synchronous = normal",
|
||||||
|
"PRAGMA temp_store = memory",
|
||||||
|
"PRAGMA mmap_size = 30000000000",
|
||||||
|
"PRAGMA page_size = 32768",
|
||||||
|
"PRAGMA auto_vacuum = NONE",
|
||||||
|
"PRAGMA automatic_index = OFF",
|
||||||
|
"PRAGMA journal_mode = WAL",
|
||||||
|
"PRAGMA read_uncommitted = ON",
|
||||||
|
}
|
||||||
|
|
||||||
|
var ddls = []string{
|
||||||
|
`CREATE TABLE IF NOT EXISTS eth_tx_hashes (
|
||||||
|
hash TEXT PRIMARY KEY NOT NULL,
|
||||||
|
cid TEXT NOT NULL UNIQUE,
|
||||||
|
insertion_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||||
|
)`,
|
||||||
|
|
||||||
|
`CREATE INDEX IF NOT EXISTS insertion_time_index ON eth_tx_hashes (insertion_time)`,
|
||||||
|
|
||||||
|
// metadata containing version of schema
|
||||||
|
`CREATE TABLE IF NOT EXISTS _meta (
|
||||||
|
version UINT64 NOT NULL UNIQUE
|
||||||
|
)`,
|
||||||
|
|
||||||
|
// version 1.
|
||||||
|
`INSERT OR IGNORE INTO _meta (version) VALUES (1)`,
|
||||||
|
}
|
||||||
|
|
||||||
|
const schemaVersion = 1
|
||||||
|
|
||||||
|
const (
|
||||||
|
insertTxHash = `INSERT INTO eth_tx_hashes
|
||||||
|
(hash, cid)
|
||||||
|
VALUES(?, ?)
|
||||||
|
ON CONFLICT (hash) DO UPDATE SET insertion_time = CURRENT_TIMESTAMP`
|
||||||
|
)
|
||||||
|
|
||||||
|
type EthTxHashLookup struct {
|
||||||
|
db *sql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ei *EthTxHashLookup) UpsertHash(txHash ethtypes.EthHash, c cid.Cid) error {
|
||||||
|
hashEntry, err := ei.db.Prepare(insertTxHash)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("prepare insert event: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = hashEntry.Exec(txHash.String(), c.String())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ei *EthTxHashLookup) GetCidFromHash(txHash ethtypes.EthHash) (cid.Cid, error) {
|
||||||
|
q, err := ei.db.Query("SELECT cid FROM eth_tx_hashes WHERE hash = :hash;", sql.Named("hash", txHash.String()))
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var c string
|
||||||
|
if !q.Next() {
|
||||||
|
return cid.Undef, ErrNotFound
|
||||||
|
}
|
||||||
|
err = q.Scan(&c)
|
||||||
|
if err != nil {
|
||||||
|
return cid.Undef, err
|
||||||
|
}
|
||||||
|
return cid.Decode(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ei *EthTxHashLookup) GetHashFromCid(c cid.Cid) (ethtypes.EthHash, error) {
|
||||||
|
q, err := ei.db.Query("SELECT hash FROM eth_tx_hashes WHERE cid = :cid;", sql.Named("cid", c.String()))
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EmptyEthHash, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var hashString string
|
||||||
|
if !q.Next() {
|
||||||
|
return ethtypes.EmptyEthHash, ErrNotFound
|
||||||
|
}
|
||||||
|
err = q.Scan(&hashString)
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EmptyEthHash, err
|
||||||
|
}
|
||||||
|
return ethtypes.ParseEthHash(hashString)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ei *EthTxHashLookup) DeleteEntriesOlderThan(days int) (int64, error) {
|
||||||
|
res, err := ei.db.Exec("DELETE FROM eth_tx_hashes WHERE insertion_time < datetime('now', ?);", "-"+strconv.Itoa(days)+" day")
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.RowsAffected()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTransactionHashLookup(path string) (*EthTxHashLookup, error) {
|
||||||
|
db, err := sql.Open("sqlite3", path+"?mode=rwc")
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("open sqlite3 database: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, pragma := range pragmas {
|
||||||
|
if _, err := db.Exec(pragma); err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, xerrors.Errorf("exec pragma %q: %w", pragma, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
q, err := db.Query("SELECT name FROM sqlite_master WHERE type='table' AND name='_meta';")
|
||||||
|
if err == sql.ErrNoRows || !q.Next() {
|
||||||
|
// empty database, create the schema
|
||||||
|
for _, ddl := range ddls {
|
||||||
|
if _, err := db.Exec(ddl); err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, xerrors.Errorf("exec ddl %q: %w", ddl, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, xerrors.Errorf("looking for _meta table: %w", err)
|
||||||
|
} else {
|
||||||
|
// Ensure we don't open a database from a different schema version
|
||||||
|
|
||||||
|
row := db.QueryRow("SELECT max(version) FROM _meta")
|
||||||
|
var version int
|
||||||
|
err := row.Scan(&version)
|
||||||
|
if err != nil {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, xerrors.Errorf("invalid database version: no version found")
|
||||||
|
}
|
||||||
|
if version != schemaVersion {
|
||||||
|
_ = db.Close()
|
||||||
|
return nil, xerrors.Errorf("invalid database version: got %d, expected %d", version, schemaVersion)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EthTxHashLookup{
|
||||||
|
db: db,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ei *EthTxHashLookup) Close() error {
|
||||||
|
if ei.db == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return ei.db.Close()
|
||||||
|
}
|
@ -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)
|
||||||
|
@ -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)))
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -231,6 +231,36 @@ func (tx *EthTxArgs) ToRlpUnsignedMsg() ([]byte, error) {
|
|||||||
return append([]byte{0x02}, encoded...), nil
|
return append([]byte{0x02}, encoded...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tx *EthTx) ToEthTxArgs() EthTxArgs {
|
||||||
|
return EthTxArgs{
|
||||||
|
ChainID: int(tx.ChainID),
|
||||||
|
Nonce: int(tx.Nonce),
|
||||||
|
To: tx.To,
|
||||||
|
Value: big.Int(tx.Value),
|
||||||
|
MaxFeePerGas: big.Int(tx.MaxFeePerGas),
|
||||||
|
MaxPriorityFeePerGas: big.Int(tx.MaxPriorityFeePerGas),
|
||||||
|
GasLimit: int(tx.Gas),
|
||||||
|
Input: tx.Input,
|
||||||
|
V: big.Int(tx.V),
|
||||||
|
R: big.Int(tx.R),
|
||||||
|
S: big.Int(tx.S),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *EthTx) TxHash() (EthHash, error) {
|
||||||
|
ethTxArgs := tx.ToEthTxArgs()
|
||||||
|
return (ðTxArgs).TxHash()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tx *EthTxArgs) TxHash() (EthHash, error) {
|
||||||
|
rlp, err := tx.ToRlpSignedMsg()
|
||||||
|
if err != nil {
|
||||||
|
return EmptyEthHash, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return EthHashFromTxBytes(rlp), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (tx *EthTxArgs) ToRlpSignedMsg() ([]byte, error) {
|
func (tx *EthTxArgs) ToRlpSignedMsg() ([]byte, error) {
|
||||||
packed1, err := tx.packTxFields()
|
packed1, err := tx.packTxFields()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -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.
|
||||||
|
68
cli/evm.go
68
cli/evm.go
@ -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,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
cli/send.go
17
cli/send.go
@ -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") {
|
||||||
|
@ -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
|
||||||
},
|
},
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -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 = ""
|
||||||
|
|
||||||
|
|
||||||
|
1
itests/contracts/DelegatecallActor.hex
Normal file
1
itests/contracts/DelegatecallActor.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b5061018c806100206000396000f3fe6080604052600436106100345760003560e01c806361bc221a146100395780636466414b146100645780638ada066e14610080575b600080fd5b34801561004557600080fd5b5061004e6100ab565b60405161005b91906100dd565b60405180910390f35b61007e60048036038101906100799190610129565b6100b1565b005b34801561008c57600080fd5b506100956100bb565b6040516100a291906100dd565b60405180910390f35b60005481565b8060008190555050565b60008054905090565b6000819050919050565b6100d7816100c4565b82525050565b60006020820190506100f260008301846100ce565b92915050565b600080fd5b610106816100c4565b811461011157600080fd5b50565b600081359050610123816100fd565b92915050565b60006020828403121561013f5761013e6100f8565b5b600061014d84828501610114565b9150509291505056fea2646970667358221220cf4567855a30be48cde5cdbff495bdaa4052e2c4540678b97284af53a4e5dbd164736f6c63430008110033
|
13
itests/contracts/DelegatecallActor.sol
Normal file
13
itests/contracts/DelegatecallActor.sol
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
1
itests/contracts/DelegatecallStorage.hex
Normal file
1
itests/contracts/DelegatecallStorage.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b50610477806100206000396000f3fe6080604052600436106100345760003560e01c806361bc221a146100395780638ada066e14610064578063d1e0f3081461008f575b600080fd5b34801561004557600080fd5b5061004e6100bf565b60405161005b919061022c565b60405180910390f35b34801561007057600080fd5b506100796100c5565b604051610086919061022c565b60405180910390f35b6100a960048036038101906100a491906102d6565b6100ce565b6040516100b6919061022c565b60405180910390f35b60005481565b60008054905090565b6000808373ffffffffffffffffffffffffffffffffffffffff16836040516024016100f9919061022c565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516101839190610387565b600060405180830381855af49150503d80600081146101be576040519150601f19603f3d011682016040523d82523d6000602084013e6101c3565b606091505b5050905080610207576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101fe90610421565b60405180910390fd5b60005491505092915050565b6000819050919050565b61022681610213565b82525050565b6000602082019050610241600083018461021d565b92915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102778261024c565b9050919050565b6102878161026c565b811461029257600080fd5b50565b6000813590506102a48161027e565b92915050565b6102b381610213565b81146102be57600080fd5b50565b6000813590506102d0816102aa565b92915050565b600080604083850312156102ed576102ec610247565b5b60006102fb85828601610295565b925050602061030c858286016102c1565b9150509250929050565b600081519050919050565b600081905092915050565b60005b8381101561034a57808201518184015260208101905061032f565b60008484015250505050565b600061036182610316565b61036b8185610321565b935061037b81856020860161032c565b80840191505092915050565b60006103938284610356565b915081905092915050565b600082825260208201905092915050565b7f4572726f72206d6573736167653a2044656c656761746563616c6c206661696c60008201527f6564000000000000000000000000000000000000000000000000000000000000602082015250565b600061040b60228361039e565b9150610416826103af565b604082019050919050565b6000602082019050818103600083015261043a816103fe565b905091905056fea26469706673582212203663909b8221e9b87047be99420c00339af1430c085260df209b909ed8e0f05164736f6c63430008110033
|
17
itests/contracts/DelegatecallStorage.sol
Normal file
17
itests/contracts/DelegatecallStorage.sol
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
1
itests/contracts/EventMatrix.hex
Normal file
1
itests/contracts/EventMatrix.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b506105eb806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a95760003560e01c8063c755553811610071578063c755553814610198578063cbfc3b58146101c6578063cc6f8faf14610212578063cd5b6c3d14610254578063e2a614731461028c578063fb62b28b146102d8576100a9565b80630919b8be146100ae5780636199074d146100e657806366eef3461461012857806375091b1f14610132578063a63ae81a1461016a575b600080fd5b6100e4600480360360408110156100c457600080fd5b81019080803590602001909291908035906020019092919050505061031a565b005b610126600480360360608110156100fc57600080fd5b8101908080359060200190929190803590602001909291908035906020019092919050505061035d565b005b610130610391565b005b6101686004803603604081101561014857600080fd5b8101908080359060200190929190803590602001909291905050506103bf565b005b6101966004803603602081101561018057600080fd5b81019080803590602001909291905050506103fb565b005b6101c4600480360360208110156101ae57600080fd5b8101908080359060200190929190505050610435565b005b610210600480360360808110156101dc57600080fd5b8101908080359060200190929190803590602001909291908035906020019092919080359060200190929190505050610465565b005b6102526004803603606081101561022857600080fd5b810190808035906020019092919080359060200190929190803590602001909291905050506104ba565b005b61028a6004803603604081101561026a57600080fd5b8101908080359060200190929190803590602001909291905050506104f8565b005b6102d6600480360360808110156102a257600080fd5b810190808035906020019092919080359060200190929190803590602001909291908035906020019092919050505061052a565b005b610318600480360360608110156102ee57600080fd5b8101908080359060200190929190803590602001909291908035906020019092919050505061056a565b005b7f5469c6b769315f5668523937f05ca07d4cc87849432bc5f5907f1d90fa73b9f98282604051808381526020018281526020019250505060405180910390a15050565b8082847fb89dabcdb7ff41f1794c0da92f65ece6c19b6b0caeac5407b2a721efe27c080460405160405180910390a4505050565b7fc3f6f1c76bd4e74ee5782052b0b4f8bd5c50b86c3c5a2f52638e03066e50a91b60405160405180910390a1565b817f6709824ebe5f6e620ca3f4b02a3428e8ce2dc97c550816eaeeb3a342b214bd85826040518082815260200191505060405180910390a25050565b7fc804e53d6048af1b3e6a352e246d5f3864fea9d635ace499e023a58c383b3a88816040518082815260200191505060405180910390a150565b807f44a227a31429ab5eb00daf6611c6422f10571619f2267e0e149e9ebe6d2a5d0560405160405180910390a250565b7f28d45631a87b2a52a9625f8520fa37ff8c4d926cdf17042e241985da5cb7b850848484846040518085815260200184815260200183815260200182815260200194505050505060405180910390a150505050565b81837fcd5fe5fbc1d27b90036997224cea7aa565e3779622867265081f636b3a5ccb08836040518082815260200191505060405180910390a3505050565b80827f232f09cef3babc26e58d1cc1346c0a8bc626ffe600c9605b5d747783eda484a760405160405180910390a35050565b8183857f812e73dbcf7e267f27ecb1383bfc902a6650b41b6e7d03ac265108c369673d95846040518082815260200191505060405180910390a450505050565b7fd4d143faaf60340ad98e1f2c96fc26f5695834c21b5200edad339ee7e9a372cc83838360405180848152602001838152602001828152602001935050505060405180910390a150505056fea265627a7a72315820954561fde80ab925299e0a9f3356b01f64fb1976dd335ac2ebd9367441e29f0564736f6c63430005110032
|
51
itests/contracts/EventMatrix.sol
Normal file
51
itests/contracts/EventMatrix.sol
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
608060405234801561001057600080fd5b506127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061051c806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637bd703e81461004657806390b98a1114610076578063f8b2cb4f146100a6575b600080fd5b610060600480360381019061005b919061030a565b6100d6565b60405161006d9190610350565b60405180910390f35b610090600480360381019061008b9190610397565b6100f4565b60405161009d91906103f2565b60405180910390f35b6100c060048036038101906100bb919061030a565b61025f565b6040516100cd9190610350565b60405180910390f35b600060026100e38361025f565b6100ed919061043c565b9050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101455760009050610259565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610193919061047e565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101e891906104b2565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161024c9190610350565b60405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d7826102ac565b9050919050565b6102e7816102cc565b81146102f257600080fd5b50565b600081359050610304816102de565b92915050565b6000602082840312156103205761031f6102a7565b5b600061032e848285016102f5565b91505092915050565b6000819050919050565b61034a81610337565b82525050565b60006020820190506103656000830184610341565b92915050565b61037481610337565b811461037f57600080fd5b50565b6000813590506103918161036b565b92915050565b600080604083850312156103ae576103ad6102a7565b5b60006103bc858286016102f5565b92505060206103cd85828601610382565b9150509250929050565b60008115159050919050565b6103ec816103d7565b82525050565b600060208201905061040760008301846103e3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061044782610337565b915061045283610337565b925082820261046081610337565b915082820484148315176104775761047661040d565b5b5092915050565b600061048982610337565b915061049483610337565b92508282039050818111156104ac576104ab61040d565b5b92915050565b60006104bd82610337565b91506104c883610337565b92508282019050808211156104e0576104df61040d565b5b9291505056fea26469706673582212205ede41ff9072784ccc19ac18de0781558d305a8139361fa85dc51a8614e47d8c64736f6c63430008110033
|
608060405234801561001057600080fd5b506127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000208190555061051c806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637bd703e81461004657806390b98a1114610076578063f8b2cb4f146100a6575b600080fd5b610060600480360381019061005b919061030a565b6100d6565b60405161006d9190610350565b60405180910390f35b610090600480360381019061008b9190610397565b6100f4565b60405161009d91906103f2565b60405180910390f35b6100c060048036038101906100bb919061030a565b61025f565b6040516100cd9190610350565b60405180910390f35b600060026100e38361025f565b6100ed919061043c565b9050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101455760009050610259565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828254610193919061047e565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101e891906104b2565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161024c9190610350565b60405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d7826102ac565b9050919050565b6102e7816102cc565b81146102f257600080fd5b50565b600081359050610304816102de565b92915050565b6000602082840312156103205761031f6102a7565b5b600061032e848285016102f5565b91505092915050565b6000819050919050565b61034a81610337565b82525050565b60006020820190506103656000830184610341565b92915050565b61037481610337565b811461037f57600080fd5b50565b6000813590506103918161036b565b92915050565b600080604083850312156103ae576103ad6102a7565b5b60006103bc858286016102f5565b92505060206103cd85828601610382565b9150509250929050565b60008115159050919050565b6103ec816103d7565b82525050565b600060208201905061040760008301846103e3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061044782610337565b915061045283610337565b925082820261046081610337565b915082820484148315176104775761047661040d565b5b5092915050565b600061048982610337565b915061049483610337565b92508282039050818111156104ac576104ab61040d565b5b92915050565b60006104bd82610337565b91506104c883610337565b92508282019050808211156104e0576104df61040d565b5b9291505056fea2646970667358221220050cdcfbe2911d041d2e6c355dbb6a0ca8ca70b500865bf33d9a2e5f4ac5a4e164736f6c63430008110033
|
6
itests/contracts/compile.sh
Executable file
6
itests/contracts/compile.sh
Executable 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/)'
|
47
itests/contracts/events.asm
Normal file
47
itests/contracts/events.asm
Normal 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
|
@ -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)
|
||||||
|
@ -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)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
65
itests/eth_block_hash_test.go
Normal file
65
itests/eth_block_hash_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
@ -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
510
itests/eth_hash_lookup_test.go
Normal file
510
itests/eth_hash_lookup_test.go
Normal 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: ðAddr,
|
||||||
|
Data: contract,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// now deploy a contract from the embryo, and validate it went well
|
||||||
|
tx := ethtypes.EthTxArgs{
|
||||||
|
ChainID: build.Eip155ChainId,
|
||||||
|
Value: big.Zero(),
|
||||||
|
Nonce: 0,
|
||||||
|
MaxFeePerGas: types.NanoFil,
|
||||||
|
MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas),
|
||||||
|
GasLimit: int(gaslimit),
|
||||||
|
Input: contract,
|
||||||
|
V: big.Zero(),
|
||||||
|
R: big.Zero(),
|
||||||
|
S: big.Zero(),
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EVM().SignTransaction(&tx, key.PrivateKey)
|
||||||
|
|
||||||
|
rawTxHash, err := tx.TxHash()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
hash := client.EVM().SubmitTransaction(ctx, &tx)
|
||||||
|
require.Equal(t, rawTxHash, hash)
|
||||||
|
|
||||||
|
mpoolTx, err := client.EthGetTransactionByHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, hash, mpoolTx.Hash)
|
||||||
|
|
||||||
|
// Wait for message to land on chain
|
||||||
|
var receipt *api.EthTxReceipt
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
receipt, err = client.EthGetTransactionReceipt(ctx, hash)
|
||||||
|
if err != nil || receipt == nil {
|
||||||
|
time.Sleep(blocktime)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, receipt)
|
||||||
|
|
||||||
|
// Verify that the chain transaction now has new fields set.
|
||||||
|
chainTx, err := client.EthGetTransactionByHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, hash, chainTx.Hash)
|
||||||
|
|
||||||
|
// require that the hashes are identical
|
||||||
|
require.Equal(t, hash, chainTx.Hash)
|
||||||
|
require.NotNil(t, chainTx.BlockNumber)
|
||||||
|
require.Greater(t, uint64(*chainTx.BlockNumber), uint64(0))
|
||||||
|
require.NotNil(t, chainTx.BlockHash)
|
||||||
|
require.NotEmpty(t, *chainTx.BlockHash)
|
||||||
|
require.NotNil(t, chainTx.TransactionIndex)
|
||||||
|
require.Equal(t, uint64(*chainTx.TransactionIndex), uint64(0)) // only transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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: ðAddr,
|
||||||
|
Data: contract,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
maxPriorityFeePerGas, err := client.EthMaxPriorityFeePerGas(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// now deploy a contract from the embryo, and validate it went well
|
||||||
|
tx := ethtypes.EthTxArgs{
|
||||||
|
ChainID: build.Eip155ChainId,
|
||||||
|
Value: big.Zero(),
|
||||||
|
Nonce: 0,
|
||||||
|
MaxFeePerGas: types.NanoFil,
|
||||||
|
MaxPriorityFeePerGas: big.Int(maxPriorityFeePerGas),
|
||||||
|
GasLimit: int(gaslimit),
|
||||||
|
Input: contract,
|
||||||
|
V: big.Zero(),
|
||||||
|
R: big.Zero(),
|
||||||
|
S: big.Zero(),
|
||||||
|
}
|
||||||
|
|
||||||
|
client.EVM().SignTransaction(&tx, key.PrivateKey)
|
||||||
|
|
||||||
|
sender, err := tx.Sender()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
unsignedMessage, err := tx.ToUnsignedMessage(sender)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
rawTxHash, err := tx.TxHash()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
hash := client.EVM().SubmitTransaction(ctx, &tx)
|
||||||
|
require.Equal(t, rawTxHash, hash)
|
||||||
|
|
||||||
|
mpoolCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, mpoolCid)
|
||||||
|
|
||||||
|
mpoolTx, err := client.ChainGetMessage(ctx, *mpoolCid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, mpoolTx)
|
||||||
|
require.Equal(t, *unsignedMessage, *mpoolTx)
|
||||||
|
|
||||||
|
// Wait for message to land on chain
|
||||||
|
var receipt *api.EthTxReceipt
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
receipt, err = client.EthGetTransactionReceipt(ctx, hash)
|
||||||
|
if err != nil || receipt == nil {
|
||||||
|
time.Sleep(blocktime)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, receipt)
|
||||||
|
|
||||||
|
chainCid, err := client.EthGetMessageCidByTransactionHash(ctx, &hash)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, chainCid)
|
||||||
|
|
||||||
|
chainTx, err := client.ChainGetMessage(ctx, *mpoolCid)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, chainTx)
|
||||||
|
require.Equal(t, *unsignedMessage, *chainTx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEthGetMessageCidByTransactionHashSecp(t *testing.T) {
|
||||||
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
|
blocktime := 1 * time.Second
|
||||||
|
client, _, ens := kit.EnsembleMinimal(
|
||||||
|
t,
|
||||||
|
kit.MockProofs(),
|
||||||
|
kit.ThroughRPC(),
|
||||||
|
)
|
||||||
|
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)
|
||||||
|
}
|
@ -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, ðtypes.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)
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
@ -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{})),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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: ``,
|
||||||
},
|
},
|
||||||
|
@ -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)
|
||||||
|
@ -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{}
|
||||||
|
@ -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 := ðtypes.EthFilterResult{}
|
res := ðtypes.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 := ðtypes.EthFilterResult{}
|
res := ðtypes.EthFilterResult{}
|
||||||
|
|
||||||
for _, c := range cs {
|
for _, c := range cs {
|
||||||
hash, err := ethtypes.EthHashFromCid(c)
|
hash, err := EthTxHashFromSignedFilecoinMessage(context.TODO(), c, sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -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
|
||||||
|
@ -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(),
|
||||||
})
|
})
|
||||||
|
@ -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
79
node/modules/ethmodule.go
Normal 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(ðTxHashManager)
|
||||||
|
|
||||||
|
ch, err := mp.Updates(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
go full.WaitForMpoolUpdates(ctx, ch, ðTxHashManager)
|
||||||
|
go full.EthTxHashGC(ctx, cfg.EthTxHashMappingLifetimeDays, ðTxHashManager)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return &full.EthModule{
|
||||||
|
Chain: cs,
|
||||||
|
Mpool: mp,
|
||||||
|
StateManager: sm,
|
||||||
|
|
||||||
|
ChainAPI: chainapi,
|
||||||
|
MpoolAPI: mpoolapi,
|
||||||
|
StateAPI: stateapi,
|
||||||
|
|
||||||
|
EthTxHashManager: ðTxHashManager,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
@ -37,6 +37,7 @@ const (
|
|||||||
fsDatastore = "datastore"
|
fsDatastore = "datastore"
|
||||||
fsLock = "repo.lock"
|
fsLock = "repo.lock"
|
||||||
fsKeystore = "keystore"
|
fsKeystore = "keystore"
|
||||||
|
fsSqlite = "sqlite"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewRepoTypeFromString(t string) RepoType {
|
func NewRepoTypeFromString(t string) RepoType {
|
||||||
@ -411,6 +412,10 @@ type fsLockedRepo struct {
|
|||||||
ssErr error
|
ssErr error
|
||||||
ssOnce sync.Once
|
ssOnce sync.Once
|
||||||
|
|
||||||
|
sqlPath string
|
||||||
|
sqlErr error
|
||||||
|
sqlOnce sync.Once
|
||||||
|
|
||||||
storageLk sync.Mutex
|
storageLk sync.Mutex
|
||||||
configLk sync.Mutex
|
configLk sync.Mutex
|
||||||
}
|
}
|
||||||
@ -515,6 +520,21 @@ func (fsr *fsLockedRepo) SplitstorePath() (string, error) {
|
|||||||
return fsr.ssPath, fsr.ssErr
|
return fsr.ssPath, fsr.ssErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fsr *fsLockedRepo) SqlitePath() (string, error) {
|
||||||
|
fsr.sqlOnce.Do(func() {
|
||||||
|
path := fsr.join(fsSqlite)
|
||||||
|
|
||||||
|
if err := os.MkdirAll(path, 0755); err != nil {
|
||||||
|
fsr.sqlErr = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fsr.sqlPath = path
|
||||||
|
})
|
||||||
|
|
||||||
|
return fsr.sqlPath, fsr.sqlErr
|
||||||
|
}
|
||||||
|
|
||||||
// join joins path elements with fsr.path
|
// join joins path elements with fsr.path
|
||||||
func (fsr *fsLockedRepo) join(paths ...string) string {
|
func (fsr *fsLockedRepo) join(paths ...string) string {
|
||||||
return filepath.Join(append([]string{fsr.path}, paths...)...)
|
return filepath.Join(append([]string{fsr.path}, paths...)...)
|
||||||
|
@ -69,6 +69,9 @@ type LockedRepo interface {
|
|||||||
// SplitstorePath returns the path for the SplitStore
|
// SplitstorePath returns the path for the SplitStore
|
||||||
SplitstorePath() (string, error)
|
SplitstorePath() (string, error)
|
||||||
|
|
||||||
|
// SqlitePath returns the path for the Sqlite database
|
||||||
|
SqlitePath() (string, error)
|
||||||
|
|
||||||
// Returns config in this repo
|
// Returns config in this repo
|
||||||
Config() (interface{}, error)
|
Config() (interface{}, error)
|
||||||
SetConfig(func(interface{})) error
|
SetConfig(func(interface{})) error
|
||||||
|
@ -277,6 +277,14 @@ func (lmem *lockedMemRepo) SplitstorePath() (string, error) {
|
|||||||
return splitstorePath, nil
|
return splitstorePath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (lmem *lockedMemRepo) SqlitePath() (string, error) {
|
||||||
|
sqlitePath := filepath.Join(lmem.Path(), "sqlite")
|
||||||
|
if err := os.MkdirAll(sqlitePath, 0755); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return sqlitePath, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (lmem *lockedMemRepo) ListDatastores(ns string) ([]int64, error) {
|
func (lmem *lockedMemRepo) ListDatastores(ns string) ([]int64, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
Loading…
Reference in New Issue
Block a user