Merge remote-tracking branch 'origin/release/v1.20.0' into iand/eth-openrpc-validate
This commit is contained in:
commit
d29a244064
@ -426,6 +426,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- setup_remote_docker
|
- setup_remote_docker
|
||||||
- checkout
|
- checkout
|
||||||
|
- git_fetch_all_tags
|
||||||
|
- run: git submodule sync
|
||||||
|
- run: git submodule update --init
|
||||||
|
|
||||||
- docker/check:
|
- docker/check:
|
||||||
docker-username: DOCKERHUB_USERNAME
|
docker-username: DOCKERHUB_USERNAME
|
||||||
docker-password: DOCKERHUB_PASSWORD
|
docker-password: DOCKERHUB_PASSWORD
|
||||||
|
@ -426,6 +426,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- setup_remote_docker
|
- setup_remote_docker
|
||||||
- checkout
|
- checkout
|
||||||
|
- git_fetch_all_tags
|
||||||
|
- run: git submodule sync
|
||||||
|
- run: git submodule update --init
|
||||||
|
|
||||||
- docker/check:
|
- docker/check:
|
||||||
docker-username: DOCKERHUB_USERNAME
|
docker-username: DOCKERHUB_USERNAME
|
||||||
docker-password: DOCKERHUB_PASSWORD
|
docker-password: DOCKERHUB_PASSWORD
|
||||||
|
20
.github/workflows/codeql-analysis.yml
vendored
20
.github/workflows/codeql-analysis.yml
vendored
@ -13,10 +13,14 @@ name: "CodeQL"
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches:
|
||||||
|
- master
|
||||||
|
- 'release/*'
|
||||||
pull_request:
|
pull_request:
|
||||||
# The branches below must be a subset of the branches above
|
# The branches below must be a subset of the branches above
|
||||||
branches: [ master ]
|
branches:
|
||||||
|
- master
|
||||||
|
- 'release/*'
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
analyze:
|
analyze:
|
||||||
@ -33,17 +37,17 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: actions/setup-go@v1
|
- uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.18.8'
|
go-version: '1.18.8'
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v1
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: go
|
||||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
# By default, queries listed here will override any specified in a config file.
|
# By default, queries listed here will override any specified in a config file.
|
||||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
@ -52,7 +56,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v1
|
uses: github/codeql-action/autobuild@v2
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 https://git.io/JvXDl
|
# 📚 https://git.io/JvXDl
|
||||||
@ -66,4 +70,4 @@ jobs:
|
|||||||
# make release
|
# make release
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v1
|
uses: github/codeql-action/analyze@v2
|
||||||
|
8
.gitignore
vendored
8
.gitignore
vendored
@ -1,6 +1,3 @@
|
|||||||
/AppDir
|
|
||||||
/appimage-builder-cache
|
|
||||||
*.AppImage
|
|
||||||
/lotus
|
/lotus
|
||||||
/lotus-miner
|
/lotus-miner
|
||||||
/lotus-worker
|
/lotus-worker
|
||||||
@ -50,3 +47,8 @@ build/builtin-actors/v*
|
|||||||
build/builtin-actors/*.car
|
build/builtin-actors/*.car
|
||||||
|
|
||||||
dist/
|
dist/
|
||||||
|
|
||||||
|
|
||||||
|
# The following files are checked into git and result
|
||||||
|
# in dirty git state if removed from the docker context
|
||||||
|
!extern/filecoin-ffi/rust/filecoin.pc
|
||||||
|
@ -1 +0,0 @@
|
|||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" viewBox="0 0 127 127" xml:space="preserve" enable-background="new 0 0 127 127"><style type="text/css">.st0{fill:#00d2d6}.st1{fill:#fff}</style><g><path class="st0" d="M63.5,127C28.5,127.1-0.2,98.4,0,63.2C0.2,28.3,28.6-0.2,63.9,0c34.8,0.2,63.3,28.7,63.1,64 C126.7,98.7,98.5,127.1,63.5,127z M71.4,57.6c5.5,0.8,11,1.5,16.5,2.3c0.5-1.7,0.9-3.1,1.3-4.7c-5.7-0.8-11.2-1.7-17.1-2.5 c2-7,3.7-13.7,5.8-20.2c0.7-2.2,2.3-4.2,3.9-5.9c2.1-2.2,5-1.7,6.8,0.7c0.7,1,1.4,2.1,2.3,2.9c1.1,1.1,2.8,1.6,4,0.6 c0.8-0.7,0.7-2.4,0.8-3.6c0-0.5-0.6-1.1-1-1.6c-2-2.3-4.7-3.1-7.5-3.2c-6.3-0.3-10.9,3-14.5,7.8c-3.5,4.8-5.1,10.5-6.8,16.2 c-0.5,1.6-0.9,3.3-1.4,5.1c-6.2-0.9-12.1-1.7-18.2-2.6c-0.2,1.6-0.4,3.2-0.6,4.8c6,0.9,11.8,1.8,17.8,2.7c-0.8,3.4-1.5,6.5-2.3,9.7 c-5.8-0.8-11.4-1.6-17-2.4c-0.2,1.8-0.4,3.2-0.6,4.8c5.6,0.9,11,1.7,16.5,2.5c0,0.6,0.1,1,0,1.3c-1.7,7.4-3.4,14.8-5.3,22.2 c-0.9,3.5-2.4,6.9-5.3,9.3c-2.4,2-5,1.7-6.8-0.8c-0.8-1.1-1.5-2.5-2.6-3.3c-0.8-0.6-2.5-0.9-3.1-0.5c-0.9,0.7-1.5,2.2-1.4,3.3 c0.1,1,1,2.2,1.9,2.8c3,2.3,6.5,2.6,10,1.9c5.9-1.2,10.1-4.9,12.7-10.1c2-4.1,3.6-8.5,5-12.9c1.3-4,2.2-8,3.3-12.2 c5.8,0.8,11.5,1.7,17.3,2.5c0.5-1.7,0.9-3.2,1.4-4.8c-6.1-0.9-11.9-1.7-17.7-2.6C70.1,64,70.7,60.9,71.4,57.6z"/><path class="st1" d="M71.4,57.6c-0.7,3.3-1.3,6.4-2,9.8c5.9,0.9,11.7,1.7,17.7,2.6c-0.5,1.6-0.9,3.1-1.4,4.8 c-5.8-0.8-11.5-1.7-17.3-2.5c-1.1,4.2-2,8.3-3.3,12.2c-1.4,4.4-3,8.7-5,12.9c-2.6,5.2-6.8,8.9-12.7,10.1c-3.5,0.7-7,0.4-10-1.9 c-0.9-0.7-1.8-1.8-1.9-2.8c-0.1-1.1,0.5-2.7,1.4-3.3c0.6-0.5,2.3-0.1,3.1,0.5c1.1,0.8,1.8,2.1,2.6,3.3c1.8,2.5,4.4,2.9,6.8,0.8 c2.9-2.5,4.4-5.8,5.3-9.3c1.9-7.3,3.6-14.8,5.3-22.2c0.1-0.3,0-0.7,0-1.3c-5.4-0.8-10.8-1.7-16.5-2.5c0.2-1.6,0.4-3,0.6-4.8 c5.6,0.8,11.1,1.6,17,2.4c0.8-3.2,1.5-6.4,2.3-9.7c-6-0.9-11.7-1.8-17.8-2.7c0.2-1.6,0.4-3.2,0.6-4.8c6.1,0.9,12,1.7,18.2,2.6 c0.5-1.8,0.9-3.5,1.4-5.1c1.7-5.6,3.2-11.3,6.8-16.2c3.6-4.9,8.1-8.1,14.5-7.8c2.8,0.1,5.5,0.9,7.5,3.2c0.4,0.5,1,1.1,1,1.6 c-0.1,1.2,0,2.9-0.8,3.6c-1.1,1.1-2.8,0.5-4-0.6c-0.9-0.9-1.6-1.9-2.3-2.9c-1.8-2.4-4.7-2.9-6.8-0.7c-1.6,1.7-3.2,3.7-3.9,5.9 C75.7,39.4,74,46,72,53c5.9,0.9,11.4,1.7,17.1,2.5c-0.5,1.6-0.9,3.1-1.3,4.7C82.3,59.1,76.9,58.3,71.4,57.6z"/></g></svg>
|
|
Before Width: | Height: | Size: 2.2 KiB |
@ -1,71 +0,0 @@
|
|||||||
version: 1
|
|
||||||
AppDir:
|
|
||||||
path: ./AppDir
|
|
||||||
app_info:
|
|
||||||
id: io.filecoin.lotus
|
|
||||||
name: Lotus
|
|
||||||
icon: icon
|
|
||||||
version: latest
|
|
||||||
exec: usr/bin/lotus
|
|
||||||
exec_args: $@
|
|
||||||
apt:
|
|
||||||
arch: amd64
|
|
||||||
allow_unauthenticated: true
|
|
||||||
sources:
|
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal main restricted
|
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-updates main restricted
|
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal universe
|
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-updates universe
|
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal multiverse
|
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-updates multiverse
|
|
||||||
- sourceline: deb http://archive.ubuntu.com/ubuntu/ focal-backports main restricted
|
|
||||||
universe multiverse
|
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security main restricted
|
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security universe
|
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu focal-security multiverse
|
|
||||||
- sourceline: deb https://cli-assets.heroku.com/apt ./
|
|
||||||
- sourceline: deb http://ppa.launchpad.net/openjdk-r/ppa/ubuntu focal main
|
|
||||||
- sourceline: deb http://ppa.launchpad.net/git-core/ppa/ubuntu focal main
|
|
||||||
- sourceline: deb http://archive.canonical.com/ubuntu focal partner
|
|
||||||
include:
|
|
||||||
- ocl-icd-libopencl1
|
|
||||||
- libhwloc15
|
|
||||||
exclude: []
|
|
||||||
files:
|
|
||||||
include:
|
|
||||||
- /usr/lib/x86_64-linux-gnu/libgcc_s.so.1
|
|
||||||
- /usr/lib/x86_64-linux-gnu/libpthread-2.31.so
|
|
||||||
- /usr/lib/x86_64-linux-gnu/libm-2.31.so
|
|
||||||
- /usr/lib/x86_64-linux-gnu/libdl-2.31.so
|
|
||||||
- /usr/lib/x86_64-linux-gnu/libc-2.31.so
|
|
||||||
- /usr/lib/x86_64-linux-gnu/libudev.so.1.6.17
|
|
||||||
exclude:
|
|
||||||
- usr/share/man
|
|
||||||
- usr/share/doc/*/README.*
|
|
||||||
- usr/share/doc/*/changelog.*
|
|
||||||
- usr/share/doc/*/NEWS.*
|
|
||||||
- usr/share/doc/*/TODO.*
|
|
||||||
test:
|
|
||||||
fedora:
|
|
||||||
image: appimagecrafters/tests-env:fedora-30
|
|
||||||
command: ./AppRun
|
|
||||||
use_host_x: false
|
|
||||||
debian:
|
|
||||||
image: appimagecrafters/tests-env:debian-stable
|
|
||||||
command: ./AppRun
|
|
||||||
use_host_x: false
|
|
||||||
arch:
|
|
||||||
image: appimagecrafters/tests-env:archlinux-latest
|
|
||||||
command: ./AppRun
|
|
||||||
use_host_x: false
|
|
||||||
centos:
|
|
||||||
image: appimagecrafters/tests-env:centos-7
|
|
||||||
command: ./AppRun
|
|
||||||
use_host_x: false
|
|
||||||
ubuntu:
|
|
||||||
image: appimagecrafters/tests-env:ubuntu-xenial
|
|
||||||
command: ./AppRun
|
|
||||||
use_host_x: false
|
|
||||||
AppImage:
|
|
||||||
arch: x86_64
|
|
||||||
|
|
@ -33,6 +33,8 @@ RUN set -eux; \
|
|||||||
COPY ./ /opt/filecoin
|
COPY ./ /opt/filecoin
|
||||||
WORKDIR /opt/filecoin
|
WORKDIR /opt/filecoin
|
||||||
|
|
||||||
|
RUN scripts/docker-git-state-check.sh
|
||||||
|
|
||||||
### make configurable filecoin-ffi build
|
### make configurable filecoin-ffi build
|
||||||
ARG FFI_BUILD_FROM_SOURCE=0
|
ARG FFI_BUILD_FROM_SOURCE=0
|
||||||
ENV FFI_BUILD_FROM_SOURCE=${FFI_BUILD_FROM_SOURCE}
|
ENV FFI_BUILD_FROM_SOURCE=${FFI_BUILD_FROM_SOURCE}
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||||
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
"github.com/filecoin-project/go-state-types/builtin/v8/paych"
|
"github.com/filecoin-project/go-state-types/builtin/v8/paych"
|
||||||
@ -831,7 +832,7 @@ type FullNode interface {
|
|||||||
// - logs: notify new event logs that match a criteria
|
// - logs: notify new event logs that match a criteria
|
||||||
// params contains additional parameters used with the log event type
|
// params contains additional parameters used with the log event type
|
||||||
// The client will receive a stream of EthSubscriptionResponse values until EthUnsubscribe is called.
|
// The client will receive a stream of EthSubscriptionResponse values until EthUnsubscribe is called.
|
||||||
EthSubscribe(ctx context.Context, eventType string, params *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) //perm:write
|
EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) //perm:write
|
||||||
|
|
||||||
// Unsubscribe from a websocket subscription
|
// Unsubscribe from a websocket subscription
|
||||||
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) //perm:write
|
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) //perm:write
|
||||||
@ -849,6 +850,12 @@ type FullNode interface {
|
|||||||
RaftLeader(ctx context.Context) (peer.ID, error) //perm:read
|
RaftLeader(ctx context.Context) (peer.ID, error) //perm:read
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// reverse interface to the client, called after EthSubscribe
|
||||||
|
type EthSubscriber interface {
|
||||||
|
// note: the parameter is ethtypes.EthSubscriptionResponse serialized as json object
|
||||||
|
EthSubscription(ctx context.Context, r jsonrpc.RawParams) error //rpc_method:eth_subscription notify:true
|
||||||
|
}
|
||||||
|
|
||||||
type StorageAsk struct {
|
type StorageAsk struct {
|
||||||
Response *storagemarket.StorageAsk
|
Response *storagemarket.StorageAsk
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/builtin/v9/miner"
|
"github.com/filecoin-project/go-state-types/builtin/v9/miner"
|
||||||
"github.com/filecoin-project/go-state-types/dline"
|
"github.com/filecoin-project/go-state-types/dline"
|
||||||
@ -102,6 +103,6 @@ type Gateway interface {
|
|||||||
EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error)
|
EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error)
|
||||||
EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error)
|
EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error)
|
||||||
EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error)
|
EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error)
|
||||||
EthSubscribe(ctx context.Context, eventType string, params *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error)
|
EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error)
|
||||||
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error)
|
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error)
|
||||||
}
|
}
|
||||||
|
@ -35,10 +35,10 @@ func NewFullNodeRPCV0(ctx context.Context, addr string, requestHeader http.Heade
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewFullNodeRPCV1 creates a new http jsonrpc client.
|
// NewFullNodeRPCV1 creates a new http jsonrpc client.
|
||||||
func NewFullNodeRPCV1(ctx context.Context, addr string, requestHeader http.Header) (api.FullNode, jsonrpc.ClientCloser, error) {
|
func NewFullNodeRPCV1(ctx context.Context, addr string, requestHeader http.Header, opts ...jsonrpc.Option) (api.FullNode, jsonrpc.ClientCloser, error) {
|
||||||
var res v1api.FullNodeStruct
|
var res v1api.FullNodeStruct
|
||||||
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
|
closer, err := jsonrpc.NewMergeClient(ctx, addr, "Filecoin",
|
||||||
api.GetInternalStructs(&res), requestHeader, jsonrpc.WithErrors(api.RPCErrors))
|
api.GetInternalStructs(&res), requestHeader, append([]jsonrpc.Option{jsonrpc.WithErrors(api.RPCErrors)}, opts...)...)
|
||||||
|
|
||||||
return &res, closer, err
|
return &res, closer, err
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
bitfield "github.com/filecoin-project/go-bitfield"
|
bitfield "github.com/filecoin-project/go-bitfield"
|
||||||
datatransfer "github.com/filecoin-project/go-data-transfer"
|
datatransfer "github.com/filecoin-project/go-data-transfer"
|
||||||
retrievalmarket "github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
retrievalmarket "github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||||
|
jsonrpc "github.com/filecoin-project/go-jsonrpc"
|
||||||
auth "github.com/filecoin-project/go-jsonrpc/auth"
|
auth "github.com/filecoin-project/go-jsonrpc/auth"
|
||||||
abi "github.com/filecoin-project/go-state-types/abi"
|
abi "github.com/filecoin-project/go-state-types/abi"
|
||||||
big "github.com/filecoin-project/go-state-types/big"
|
big "github.com/filecoin-project/go-state-types/big"
|
||||||
@ -1388,18 +1389,18 @@ func (mr *MockFullNodeMockRecorder) EthSendRawTransaction(arg0, arg1 interface{}
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EthSubscribe mocks base method.
|
// EthSubscribe mocks base method.
|
||||||
func (m *MockFullNode) EthSubscribe(arg0 context.Context, arg1 string, arg2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) {
|
func (m *MockFullNode) EthSubscribe(arg0 context.Context, arg1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "EthSubscribe", arg0, arg1, arg2)
|
ret := m.ctrl.Call(m, "EthSubscribe", arg0, arg1)
|
||||||
ret0, _ := ret[0].(<-chan ethtypes.EthSubscriptionResponse)
|
ret0, _ := ret[0].(ethtypes.EthSubscriptionID)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthSubscribe indicates an expected call of EthSubscribe.
|
// EthSubscribe indicates an expected call of EthSubscribe.
|
||||||
func (mr *MockFullNodeMockRecorder) EthSubscribe(arg0, arg1, arg2 interface{}) *gomock.Call {
|
func (mr *MockFullNodeMockRecorder) EthSubscribe(arg0, arg1 interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthSubscribe", reflect.TypeOf((*MockFullNode)(nil).EthSubscribe), arg0, arg1, arg2)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthSubscribe", reflect.TypeOf((*MockFullNode)(nil).EthSubscribe), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthUninstallFilter mocks base method.
|
// EthUninstallFilter mocks base method.
|
||||||
|
108
api/proxy_gen.go
108
api/proxy_gen.go
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/filecoin-project/go-fil-markets/piecestore"
|
"github.com/filecoin-project/go-fil-markets/piecestore"
|
||||||
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
"github.com/filecoin-project/go-fil-markets/retrievalmarket"
|
||||||
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
"github.com/filecoin-project/go-fil-markets/storagemarket"
|
||||||
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
"github.com/filecoin-project/go-jsonrpc/auth"
|
"github.com/filecoin-project/go-jsonrpc/auth"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/builtin/v8/paych"
|
"github.com/filecoin-project/go-state-types/builtin/v8/paych"
|
||||||
@ -49,20 +50,25 @@ import (
|
|||||||
var ErrNotSupported = xerrors.New("method not supported")
|
var ErrNotSupported = xerrors.New("method not supported")
|
||||||
|
|
||||||
type ChainIOStruct struct {
|
type ChainIOStruct struct {
|
||||||
Internal struct {
|
Internal ChainIOMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
type ChainIOMethods struct {
|
||||||
ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) ``
|
ChainHasObj func(p0 context.Context, p1 cid.Cid) (bool, error) ``
|
||||||
|
|
||||||
ChainPutObj func(p0 context.Context, p1 blocks.Block) error ``
|
ChainPutObj func(p0 context.Context, p1 blocks.Block) error ``
|
||||||
|
|
||||||
ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) ``
|
ChainReadObj func(p0 context.Context, p1 cid.Cid) ([]byte, error) ``
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChainIOStub struct {
|
type ChainIOStub struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommonStruct struct {
|
type CommonStruct struct {
|
||||||
Internal struct {
|
Internal CommonMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
type CommonMethods struct {
|
||||||
AuthNew func(p0 context.Context, p1 []auth.Permission) ([]byte, error) `perm:"admin"`
|
AuthNew func(p0 context.Context, p1 []auth.Permission) ([]byte, error) `perm:"admin"`
|
||||||
|
|
||||||
AuthVerify func(p0 context.Context, p1 string) ([]auth.Permission, error) `perm:"read"`
|
AuthVerify func(p0 context.Context, p1 string) ([]auth.Permission, error) `perm:"read"`
|
||||||
@ -84,7 +90,6 @@ type CommonStruct struct {
|
|||||||
StartTime func(p0 context.Context) (time.Time, error) `perm:"read"`
|
StartTime func(p0 context.Context) (time.Time, error) `perm:"read"`
|
||||||
|
|
||||||
Version func(p0 context.Context) (APIVersion, error) `perm:"read"`
|
Version func(p0 context.Context) (APIVersion, error) `perm:"read"`
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommonStub struct {
|
type CommonStub struct {
|
||||||
@ -95,8 +100,10 @@ type CommonNetStruct struct {
|
|||||||
|
|
||||||
NetStruct
|
NetStruct
|
||||||
|
|
||||||
Internal struct {
|
Internal CommonNetMethods
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CommonNetMethods struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommonNetStub struct {
|
type CommonNetStub struct {
|
||||||
@ -105,12 +112,26 @@ type CommonNetStub struct {
|
|||||||
NetStub
|
NetStub
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EthSubscriberStruct struct {
|
||||||
|
Internal EthSubscriberMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
type EthSubscriberMethods struct {
|
||||||
|
EthSubscription func(p0 context.Context, p1 jsonrpc.RawParams) error `notify:"true"rpc_method:"eth_subscription"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type EthSubscriberStub struct {
|
||||||
|
}
|
||||||
|
|
||||||
type FullNodeStruct struct {
|
type FullNodeStruct struct {
|
||||||
CommonStruct
|
CommonStruct
|
||||||
|
|
||||||
NetStruct
|
NetStruct
|
||||||
|
|
||||||
Internal struct {
|
Internal FullNodeMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
type FullNodeMethods struct {
|
||||||
ChainBlockstoreInfo func(p0 context.Context) (map[string]interface{}, error) `perm:"read"`
|
ChainBlockstoreInfo func(p0 context.Context) (map[string]interface{}, error) `perm:"read"`
|
||||||
|
|
||||||
ChainCheckBlockstore func(p0 context.Context) error `perm:"admin"`
|
ChainCheckBlockstore func(p0 context.Context) error `perm:"admin"`
|
||||||
@ -281,7 +302,7 @@ type FullNodeStruct struct {
|
|||||||
|
|
||||||
EthSendRawTransaction func(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) `perm:"read"`
|
EthSendRawTransaction func(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) `perm:"read"`
|
||||||
|
|
||||||
EthSubscribe func(p0 context.Context, p1 string, p2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) `perm:"write"`
|
EthSubscribe func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) `perm:"write"`
|
||||||
|
|
||||||
EthUninstallFilter func(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) `perm:"write"`
|
EthUninstallFilter func(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) `perm:"write"`
|
||||||
|
|
||||||
@ -584,7 +605,6 @@ type FullNodeStruct struct {
|
|||||||
WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"`
|
WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"`
|
||||||
|
|
||||||
Web3ClientVersion func(p0 context.Context) (string, error) `perm:"read"`
|
Web3ClientVersion func(p0 context.Context) (string, error) `perm:"read"`
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type FullNodeStub struct {
|
type FullNodeStub struct {
|
||||||
@ -594,7 +614,10 @@ type FullNodeStub struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GatewayStruct struct {
|
type GatewayStruct struct {
|
||||||
Internal struct {
|
Internal GatewayMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
type GatewayMethods struct {
|
||||||
ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) ``
|
ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) ``
|
||||||
|
|
||||||
ChainGetGenesis func(p0 context.Context) (*types.TipSet, error) ``
|
ChainGetGenesis func(p0 context.Context) (*types.TipSet, error) ``
|
||||||
@ -681,7 +704,7 @@ type GatewayStruct struct {
|
|||||||
|
|
||||||
EthSendRawTransaction func(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) ``
|
EthSendRawTransaction func(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) ``
|
||||||
|
|
||||||
EthSubscribe func(p0 context.Context, p1 string, p2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) ``
|
EthSubscribe func(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) ``
|
||||||
|
|
||||||
EthUninstallFilter func(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) ``
|
EthUninstallFilter func(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) ``
|
||||||
|
|
||||||
@ -738,14 +761,16 @@ type GatewayStruct struct {
|
|||||||
Version func(p0 context.Context) (APIVersion, error) ``
|
Version func(p0 context.Context) (APIVersion, error) ``
|
||||||
|
|
||||||
WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) ``
|
WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) ``
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type GatewayStub struct {
|
type GatewayStub struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type NetStruct struct {
|
type NetStruct struct {
|
||||||
Internal struct {
|
Internal NetMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetMethods struct {
|
||||||
ID func(p0 context.Context) (peer.ID, error) `perm:"read"`
|
ID func(p0 context.Context) (peer.ID, error) `perm:"read"`
|
||||||
|
|
||||||
NetAddrsListen func(p0 context.Context) (peer.AddrInfo, error) `perm:"read"`
|
NetAddrsListen func(p0 context.Context) (peer.AddrInfo, error) `perm:"read"`
|
||||||
@ -793,16 +818,17 @@ type NetStruct struct {
|
|||||||
NetSetLimit func(p0 context.Context, p1 string, p2 NetLimit) error `perm:"admin"`
|
NetSetLimit func(p0 context.Context, p1 string, p2 NetLimit) error `perm:"admin"`
|
||||||
|
|
||||||
NetStat func(p0 context.Context, p1 string) (NetStat, error) `perm:"read"`
|
NetStat func(p0 context.Context, p1 string) (NetStat, error) `perm:"read"`
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type NetStub struct {
|
type NetStub struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SignableStruct struct {
|
type SignableStruct struct {
|
||||||
Internal struct {
|
Internal SignableMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignableMethods struct {
|
||||||
Sign func(p0 context.Context, p1 SignFunc) error ``
|
Sign func(p0 context.Context, p1 SignFunc) error ``
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type SignableStub struct {
|
type SignableStub struct {
|
||||||
@ -813,7 +839,10 @@ type StorageMinerStruct struct {
|
|||||||
|
|
||||||
NetStruct
|
NetStruct
|
||||||
|
|
||||||
Internal struct {
|
Internal StorageMinerMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
type StorageMinerMethods struct {
|
||||||
ActorAddress func(p0 context.Context) (address.Address, error) `perm:"read"`
|
ActorAddress func(p0 context.Context) (address.Address, error) `perm:"read"`
|
||||||
|
|
||||||
ActorAddressConfig func(p0 context.Context) (AddressConfig, error) `perm:"read"`
|
ActorAddressConfig func(p0 context.Context) (AddressConfig, error) `perm:"read"`
|
||||||
@ -1077,7 +1106,6 @@ type StorageMinerStruct struct {
|
|||||||
WorkerJobs func(p0 context.Context) (map[uuid.UUID][]storiface.WorkerJob, error) `perm:"admin"`
|
WorkerJobs func(p0 context.Context) (map[uuid.UUID][]storiface.WorkerJob, error) `perm:"admin"`
|
||||||
|
|
||||||
WorkerStats func(p0 context.Context) (map[uuid.UUID]storiface.WorkerStats, error) `perm:"admin"`
|
WorkerStats func(p0 context.Context) (map[uuid.UUID]storiface.WorkerStats, error) `perm:"admin"`
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type StorageMinerStub struct {
|
type StorageMinerStub struct {
|
||||||
@ -1087,7 +1115,10 @@ type StorageMinerStub struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WalletStruct struct {
|
type WalletStruct struct {
|
||||||
Internal struct {
|
Internal WalletMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
type WalletMethods struct {
|
||||||
WalletDelete func(p0 context.Context, p1 address.Address) error `perm:"admin"`
|
WalletDelete func(p0 context.Context, p1 address.Address) error `perm:"admin"`
|
||||||
|
|
||||||
WalletExport func(p0 context.Context, p1 address.Address) (*types.KeyInfo, error) `perm:"admin"`
|
WalletExport func(p0 context.Context, p1 address.Address) (*types.KeyInfo, error) `perm:"admin"`
|
||||||
@ -1101,14 +1132,16 @@ type WalletStruct struct {
|
|||||||
WalletNew func(p0 context.Context, p1 types.KeyType) (address.Address, error) `perm:"admin"`
|
WalletNew func(p0 context.Context, p1 types.KeyType) (address.Address, error) `perm:"admin"`
|
||||||
|
|
||||||
WalletSign func(p0 context.Context, p1 address.Address, p2 []byte, p3 MsgMeta) (*crypto.Signature, error) `perm:"admin"`
|
WalletSign func(p0 context.Context, p1 address.Address, p2 []byte, p3 MsgMeta) (*crypto.Signature, error) `perm:"admin"`
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type WalletStub struct {
|
type WalletStub struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkerStruct struct {
|
type WorkerStruct struct {
|
||||||
Internal struct {
|
Internal WorkerMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
type WorkerMethods struct {
|
||||||
AddPiece func(p0 context.Context, p1 storiface.SectorRef, p2 []abi.UnpaddedPieceSize, p3 abi.UnpaddedPieceSize, p4 storiface.Data) (storiface.CallID, error) `perm:"admin"`
|
AddPiece func(p0 context.Context, p1 storiface.SectorRef, p2 []abi.UnpaddedPieceSize, p3 abi.UnpaddedPieceSize, p4 storiface.Data) (storiface.CallID, error) `perm:"admin"`
|
||||||
|
|
||||||
DataCid func(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storiface.Data) (storiface.CallID, error) `perm:"admin"`
|
DataCid func(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storiface.Data) (storiface.CallID, error) `perm:"admin"`
|
||||||
@ -1182,7 +1215,6 @@ type WorkerStruct struct {
|
|||||||
Version func(p0 context.Context) (Version, error) `perm:"admin"`
|
Version func(p0 context.Context) (Version, error) `perm:"admin"`
|
||||||
|
|
||||||
WaitQuiet func(p0 context.Context) error `perm:"admin"`
|
WaitQuiet func(p0 context.Context) error `perm:"admin"`
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type WorkerStub struct {
|
type WorkerStub struct {
|
||||||
@ -1342,6 +1374,17 @@ func (s *CommonStub) Version(p0 context.Context) (APIVersion, error) {
|
|||||||
return *new(APIVersion), ErrNotSupported
|
return *new(APIVersion), ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *EthSubscriberStruct) EthSubscription(p0 context.Context, p1 jsonrpc.RawParams) error {
|
||||||
|
if s.Internal.EthSubscription == nil {
|
||||||
|
return ErrNotSupported
|
||||||
|
}
|
||||||
|
return s.Internal.EthSubscription(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *EthSubscriberStub) EthSubscription(p0 context.Context, p1 jsonrpc.RawParams) error {
|
||||||
|
return ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FullNodeStruct) ChainBlockstoreInfo(p0 context.Context) (map[string]interface{}, error) {
|
func (s *FullNodeStruct) ChainBlockstoreInfo(p0 context.Context) (map[string]interface{}, error) {
|
||||||
if s.Internal.ChainBlockstoreInfo == nil {
|
if s.Internal.ChainBlockstoreInfo == nil {
|
||||||
return *new(map[string]interface{}), ErrNotSupported
|
return *new(map[string]interface{}), ErrNotSupported
|
||||||
@ -2277,15 +2320,15 @@ func (s *FullNodeStub) EthSendRawTransaction(p0 context.Context, p1 ethtypes.Eth
|
|||||||
return *new(ethtypes.EthHash), ErrNotSupported
|
return *new(ethtypes.EthHash), ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FullNodeStruct) EthSubscribe(p0 context.Context, p1 string, p2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) {
|
func (s *FullNodeStruct) EthSubscribe(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {
|
||||||
if s.Internal.EthSubscribe == nil {
|
if s.Internal.EthSubscribe == nil {
|
||||||
return nil, ErrNotSupported
|
return *new(ethtypes.EthSubscriptionID), ErrNotSupported
|
||||||
}
|
}
|
||||||
return s.Internal.EthSubscribe(p0, p1, p2)
|
return s.Internal.EthSubscribe(p0, p1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FullNodeStub) EthSubscribe(p0 context.Context, p1 string, p2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) {
|
func (s *FullNodeStub) EthSubscribe(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {
|
||||||
return nil, ErrNotSupported
|
return *new(ethtypes.EthSubscriptionID), ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *FullNodeStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) {
|
func (s *FullNodeStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) {
|
||||||
@ -4422,15 +4465,15 @@ func (s *GatewayStub) EthSendRawTransaction(p0 context.Context, p1 ethtypes.EthB
|
|||||||
return *new(ethtypes.EthHash), ErrNotSupported
|
return *new(ethtypes.EthHash), ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GatewayStruct) EthSubscribe(p0 context.Context, p1 string, p2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) {
|
func (s *GatewayStruct) EthSubscribe(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {
|
||||||
if s.Internal.EthSubscribe == nil {
|
if s.Internal.EthSubscribe == nil {
|
||||||
return nil, ErrNotSupported
|
return *new(ethtypes.EthSubscriptionID), ErrNotSupported
|
||||||
}
|
}
|
||||||
return s.Internal.EthSubscribe(p0, p1, p2)
|
return s.Internal.EthSubscribe(p0, p1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GatewayStub) EthSubscribe(p0 context.Context, p1 string, p2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) {
|
func (s *GatewayStub) EthSubscribe(p0 context.Context, p1 jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {
|
||||||
return nil, ErrNotSupported
|
return *new(ethtypes.EthSubscriptionID), ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *GatewayStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) {
|
func (s *GatewayStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) {
|
||||||
@ -6955,6 +6998,7 @@ func (s *WorkerStub) WaitQuiet(p0 context.Context) error {
|
|||||||
var _ ChainIO = new(ChainIOStruct)
|
var _ ChainIO = new(ChainIOStruct)
|
||||||
var _ Common = new(CommonStruct)
|
var _ Common = new(CommonStruct)
|
||||||
var _ CommonNet = new(CommonNetStruct)
|
var _ CommonNet = new(CommonNetStruct)
|
||||||
|
var _ EthSubscriber = new(EthSubscriberStruct)
|
||||||
var _ FullNode = new(FullNodeStruct)
|
var _ FullNode = new(FullNodeStruct)
|
||||||
var _ Gateway = new(GatewayStruct)
|
var _ Gateway = new(GatewayStruct)
|
||||||
var _ Net = new(NetStruct)
|
var _ Net = new(NetStruct)
|
||||||
|
@ -39,7 +39,10 @@ type FullNodeStruct struct {
|
|||||||
|
|
||||||
NetStruct
|
NetStruct
|
||||||
|
|
||||||
Internal struct {
|
Internal FullNodeMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
type FullNodeMethods struct {
|
||||||
BeaconGetEntry func(p0 context.Context, p1 abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"`
|
BeaconGetEntry func(p0 context.Context, p1 abi.ChainEpoch) (*types.BeaconEntry, error) `perm:"read"`
|
||||||
|
|
||||||
ChainDeleteObj func(p0 context.Context, p1 cid.Cid) error `perm:"admin"`
|
ChainDeleteObj func(p0 context.Context, p1 cid.Cid) error `perm:"admin"`
|
||||||
@ -415,7 +418,6 @@ type FullNodeStruct struct {
|
|||||||
WalletValidateAddress func(p0 context.Context, p1 string) (address.Address, error) `perm:"read"`
|
WalletValidateAddress func(p0 context.Context, p1 string) (address.Address, error) `perm:"read"`
|
||||||
|
|
||||||
WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"`
|
WalletVerify func(p0 context.Context, p1 address.Address, p2 []byte, p3 *crypto.Signature) (bool, error) `perm:"read"`
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type FullNodeStub struct {
|
type FullNodeStub struct {
|
||||||
@ -425,7 +427,10 @@ type FullNodeStub struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GatewayStruct struct {
|
type GatewayStruct struct {
|
||||||
Internal struct {
|
Internal GatewayMethods
|
||||||
|
}
|
||||||
|
|
||||||
|
type GatewayMethods struct {
|
||||||
ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*api.BlockMessages, error) ``
|
ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*api.BlockMessages, error) ``
|
||||||
|
|
||||||
ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) ``
|
ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) ``
|
||||||
@ -489,7 +494,6 @@ type GatewayStruct struct {
|
|||||||
Version func(p0 context.Context) (api.APIVersion, error) ``
|
Version func(p0 context.Context) (api.APIVersion, error) ``
|
||||||
|
|
||||||
WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) ``
|
WalletBalance func(p0 context.Context, p1 address.Address) (types.BigInt, error) ``
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type GatewayStub struct {
|
type GatewayStub struct {
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -23,7 +23,7 @@ var NetworkBundle = "devnet"
|
|||||||
var BundleOverrides map[actorstypes.Version]string
|
var BundleOverrides map[actorstypes.Version]string
|
||||||
var ActorDebugging = true
|
var ActorDebugging = true
|
||||||
|
|
||||||
const GenesisNetworkVersion = network.Version18
|
const GenesisNetworkVersion = network.Version17
|
||||||
|
|
||||||
var UpgradeBreezeHeight = abi.ChainEpoch(-1)
|
var UpgradeBreezeHeight = abi.ChainEpoch(-1)
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ var UpgradeSkyrHeight = abi.ChainEpoch(-19)
|
|||||||
|
|
||||||
var UpgradeSharkHeight = abi.ChainEpoch(-20)
|
var UpgradeSharkHeight = abi.ChainEpoch(-20)
|
||||||
|
|
||||||
var UpgradeHyggeHeight = abi.ChainEpoch(-21)
|
var UpgradeHyggeHeight = abi.ChainEpoch(30)
|
||||||
|
|
||||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||||
0: DrandMainnet,
|
0: DrandMainnet,
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
var SystemActorAddr = builtin.SystemActorAddr
|
var SystemActorAddr = builtin.SystemActorAddr
|
||||||
var BurntFundsActorAddr = builtin.BurntFundsActorAddr
|
var BurntFundsActorAddr = builtin.BurntFundsActorAddr
|
||||||
var CronActorAddr = builtin.CronActorAddr
|
var CronActorAddr = builtin.CronActorAddr
|
||||||
|
var EthereumAddressManagerActorAddr = builtin.EthereumAddressManagerActorAddr
|
||||||
var SaftAddress = makeAddress("t0122")
|
var SaftAddress = makeAddress("t0122")
|
||||||
var ReserveAddress = makeAddress("t090")
|
var ReserveAddress = makeAddress("t090")
|
||||||
var RootVerifierAddress = makeAddress("t080")
|
var RootVerifierAddress = makeAddress("t080")
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
var SystemActorAddr = builtin.SystemActorAddr
|
var SystemActorAddr = builtin.SystemActorAddr
|
||||||
var BurntFundsActorAddr = builtin.BurntFundsActorAddr
|
var BurntFundsActorAddr = builtin.BurntFundsActorAddr
|
||||||
var CronActorAddr = builtin.CronActorAddr
|
var CronActorAddr = builtin.CronActorAddr
|
||||||
|
var EthereumAddressManagerActorAddr = builtin.EthereumAddressManagerActorAddr
|
||||||
var SaftAddress = makeAddress("t0122")
|
var SaftAddress = makeAddress("t0122")
|
||||||
var ReserveAddress = makeAddress("t090")
|
var ReserveAddress = makeAddress("t090")
|
||||||
var RootVerifierAddress = makeAddress("t080")
|
var RootVerifierAddress = makeAddress("t080")
|
||||||
|
@ -67,34 +67,28 @@ func (ei *EthTxHashLookup) UpsertHash(txHash ethtypes.EthHash, c cid.Cid) error
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ei *EthTxHashLookup) GetCidFromHash(txHash ethtypes.EthHash) (cid.Cid, error) {
|
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()))
|
row := ei.db.QueryRow("SELECT cid FROM eth_tx_hashes WHERE hash = :hash;", sql.Named("hash", txHash.String()))
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var c string
|
var c string
|
||||||
if !q.Next() {
|
err := row.Scan(&c)
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
return cid.Undef, ErrNotFound
|
return cid.Undef, ErrNotFound
|
||||||
}
|
}
|
||||||
err = q.Scan(&c)
|
|
||||||
if err != nil {
|
|
||||||
return cid.Undef, err
|
return cid.Undef, err
|
||||||
}
|
}
|
||||||
return cid.Decode(c)
|
return cid.Decode(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ei *EthTxHashLookup) GetHashFromCid(c cid.Cid) (ethtypes.EthHash, error) {
|
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()))
|
row := ei.db.QueryRow("SELECT hash FROM eth_tx_hashes WHERE cid = :cid;", sql.Named("cid", c.String()))
|
||||||
if err != nil {
|
|
||||||
return ethtypes.EmptyEthHash, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var hashString string
|
var hashString string
|
||||||
if !q.Next() {
|
err := row.Scan(&c)
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
return ethtypes.EmptyEthHash, ErrNotFound
|
return ethtypes.EmptyEthHash, ErrNotFound
|
||||||
}
|
}
|
||||||
err = q.Scan(&hashString)
|
|
||||||
if err != nil {
|
|
||||||
return ethtypes.EmptyEthHash, err
|
return ethtypes.EmptyEthHash, err
|
||||||
}
|
}
|
||||||
return ethtypes.ParseEthHash(hashString)
|
return ethtypes.ParseEthHash(hashString)
|
||||||
|
@ -202,7 +202,7 @@ func (ms *MessageSigner) dstoreKey(addr address.Address) datastore.Key {
|
|||||||
|
|
||||||
func SigningBytes(msg *types.Message, sigType crypto.SigType) ([]byte, error) {
|
func SigningBytes(msg *types.Message, sigType crypto.SigType) ([]byte, error) {
|
||||||
if sigType == crypto.SigTypeDelegated {
|
if sigType == crypto.SigTypeDelegated {
|
||||||
txArgs, err := ethtypes.EthTxArgsFromMessage(msg)
|
txArgs, err := ethtypes.EthTxArgsFromUnsignedEthMessage(msg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to reconstruct eth transaction: %w", err)
|
return nil, xerrors.Errorf("failed to reconstruct eth transaction: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ func AuthenticateMessage(msg *types.SignedMessage, signer address.Address) error
|
|||||||
typ := msg.Signature.Type
|
typ := msg.Signature.Type
|
||||||
switch typ {
|
switch typ {
|
||||||
case crypto.SigTypeDelegated:
|
case crypto.SigTypeDelegated:
|
||||||
txArgs, err := ethtypes.EthTxArgsFromMessage(&msg.Message)
|
txArgs, err := ethtypes.EthTxArgsFromUnsignedEthMessage(&msg.Message)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to reconstruct eth transaction: %w", err)
|
return xerrors.Errorf("failed to reconstruct eth transaction: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -403,7 +403,8 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha
|
|||||||
a == builtin.CronActorAddr ||
|
a == builtin.CronActorAddr ||
|
||||||
a == builtin.BurntFundsActorAddr ||
|
a == builtin.BurntFundsActorAddr ||
|
||||||
a == builtin.SaftAddress ||
|
a == builtin.SaftAddress ||
|
||||||
a == builtin.ReserveAddress:
|
a == builtin.ReserveAddress ||
|
||||||
|
a == builtin.EthereumAddressManagerActorAddr:
|
||||||
|
|
||||||
unCirc = big.Add(unCirc, actor.Balance)
|
unCirc = big.Add(unCirc, actor.Balance)
|
||||||
|
|
||||||
@ -421,7 +422,12 @@ func (sm *StateManager) GetCirculatingSupply(ctx context.Context, height abi.Cha
|
|||||||
circ = big.Add(circ, big.Sub(actor.Balance, lb))
|
circ = big.Add(circ, big.Sub(actor.Balance, lb))
|
||||||
unCirc = big.Add(unCirc, lb)
|
unCirc = big.Add(unCirc, lb)
|
||||||
|
|
||||||
case builtin.IsAccountActor(actor.Code) || builtin.IsPaymentChannelActor(actor.Code):
|
case builtin.IsAccountActor(actor.Code) ||
|
||||||
|
builtin.IsPaymentChannelActor(actor.Code) ||
|
||||||
|
builtin.IsEthAccountActor(actor.Code) ||
|
||||||
|
builtin.IsEvmActor(actor.Code) ||
|
||||||
|
builtin.IsPlaceholderActor(actor.Code):
|
||||||
|
|
||||||
circ = big.Add(circ, actor.Balance)
|
circ = big.Add(circ, actor.Balance)
|
||||||
|
|
||||||
case builtin.IsStorageMinerActor(actor.Code):
|
case builtin.IsStorageMinerActor(actor.Code):
|
||||||
|
@ -56,7 +56,44 @@ type EthTxArgs struct {
|
|||||||
S big.Int `json:"s"`
|
S big.Int `json:"s"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func EthTxArgsFromMessage(msg *types.Message) (EthTxArgs, error) {
|
// EthTxFromSignedEthMessage does NOT populate:
|
||||||
|
// - BlockHash
|
||||||
|
// - BlockNumber
|
||||||
|
// - TransactionIndex
|
||||||
|
// - From
|
||||||
|
// - Hash
|
||||||
|
func EthTxFromSignedEthMessage(smsg *types.SignedMessage) (EthTx, error) {
|
||||||
|
if smsg.Signature.Type != typescrypto.SigTypeDelegated {
|
||||||
|
return EthTx{}, xerrors.Errorf("signature is not delegated type, is type: %d", smsg.Signature.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
txArgs, err := EthTxArgsFromUnsignedEthMessage(&smsg.Message)
|
||||||
|
if err != nil {
|
||||||
|
return EthTx{}, xerrors.Errorf("failed to convert the unsigned message: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
r, s, v, err := RecoverSignature(smsg.Signature)
|
||||||
|
if err != nil {
|
||||||
|
return EthTx{}, xerrors.Errorf("failed to recover signature: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return EthTx{
|
||||||
|
Nonce: EthUint64(txArgs.Nonce),
|
||||||
|
ChainID: EthUint64(txArgs.ChainID),
|
||||||
|
To: txArgs.To,
|
||||||
|
Value: EthBigInt(txArgs.Value),
|
||||||
|
Type: Eip1559TxType,
|
||||||
|
Gas: EthUint64(txArgs.GasLimit),
|
||||||
|
MaxFeePerGas: EthBigInt(txArgs.MaxFeePerGas),
|
||||||
|
MaxPriorityFeePerGas: EthBigInt(txArgs.MaxPriorityFeePerGas),
|
||||||
|
V: v,
|
||||||
|
R: r,
|
||||||
|
S: s,
|
||||||
|
Input: txArgs.Input,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func EthTxArgsFromUnsignedEthMessage(msg *types.Message) (EthTxArgs, error) {
|
||||||
var (
|
var (
|
||||||
to *EthAddress
|
to *EthAddress
|
||||||
params []byte
|
params []byte
|
||||||
|
@ -363,6 +363,18 @@ func (h *EthHash) UnmarshalJSON(b []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h EthHash) String() string {
|
||||||
|
return "0x" + hex.EncodeToString(h[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should ONLY be used for blocks and Filecoin messages. Eth transactions expect a different hashing scheme.
|
||||||
|
func (h EthHash) ToCid() cid.Cid {
|
||||||
|
// err is always nil
|
||||||
|
mh, _ := multihash.EncodeName(h[:], "blake2b-256")
|
||||||
|
|
||||||
|
return cid.NewCidV1(cid.DagCBOR, mh)
|
||||||
|
}
|
||||||
|
|
||||||
func decodeHexString(s string, expectedLen int) ([]byte, error) {
|
func decodeHexString(s string, expectedLen int) ([]byte, error) {
|
||||||
s = handleHexStringPrefix(s)
|
s = handleHexStringPrefix(s)
|
||||||
if len(s) != expectedLen*2 {
|
if len(s) != expectedLen*2 {
|
||||||
@ -420,18 +432,6 @@ func EthHashFromTxBytes(b []byte) EthHash {
|
|||||||
return ethHash
|
return ethHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h EthHash) String() string {
|
|
||||||
return "0x" + hex.EncodeToString(h[:])
|
|
||||||
}
|
|
||||||
|
|
||||||
// Should ONLY be used for blocks and Filecoin messages. Eth transactions expect a different hashing scheme.
|
|
||||||
func (h EthHash) ToCid() cid.Cid {
|
|
||||||
// err is always nil
|
|
||||||
mh, _ := multihash.EncodeName(h[:], "blake2b-256")
|
|
||||||
|
|
||||||
return cid.NewCidV1(cid.DagCBOR, mh)
|
|
||||||
}
|
|
||||||
|
|
||||||
type EthFeeHistory struct {
|
type EthFeeHistory struct {
|
||||||
OldestBlock EthUint64 `json:"oldestBlock"`
|
OldestBlock EthUint64 `json:"oldestBlock"`
|
||||||
BaseFeePerGas []EthBigInt `json:"baseFeePerGas"`
|
BaseFeePerGas []EthBigInt `json:"baseFeePerGas"`
|
||||||
@ -441,49 +441,31 @@ type EthFeeHistory struct {
|
|||||||
|
|
||||||
type EthFilterID EthHash
|
type EthFilterID EthHash
|
||||||
|
|
||||||
func (id EthFilterID) String() string {
|
func (h EthFilterID) MarshalJSON() ([]byte, error) {
|
||||||
return "0x" + hex.EncodeToString(id[:])
|
return (EthHash)(h).MarshalJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (id EthFilterID) MarshalJSON() ([]byte, error) {
|
func (h *EthFilterID) UnmarshalJSON(b []byte) error {
|
||||||
return json.Marshal(id.String())
|
return (*EthHash)(h).UnmarshalJSON(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (id *EthFilterID) UnmarshalJSON(b []byte) error {
|
func (h EthFilterID) String() string {
|
||||||
var s string
|
return (EthHash)(h).String()
|
||||||
if err := json.Unmarshal(b, &s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hash, err := ParseEthHash(s)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
copy(id[:], hash[:])
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// An opaque identifier generated by the Lotus node to refer to an active subscription.
|
// An opaque identifier generated by the Lotus node to refer to an active subscription.
|
||||||
type EthSubscriptionID EthHash
|
type EthSubscriptionID EthHash
|
||||||
|
|
||||||
func (id EthSubscriptionID) String() string {
|
func (h EthSubscriptionID) MarshalJSON() ([]byte, error) {
|
||||||
return "0x" + hex.EncodeToString(id[:])
|
return (EthHash)(h).MarshalJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (id EthSubscriptionID) MarshalJSON() ([]byte, error) {
|
func (h *EthSubscriptionID) UnmarshalJSON(b []byte) error {
|
||||||
return json.Marshal(id.String())
|
return (*EthHash)(h).UnmarshalJSON(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (id *EthSubscriptionID) UnmarshalJSON(b []byte) error {
|
func (h EthSubscriptionID) String() string {
|
||||||
var s string
|
return (EthHash)(h).String()
|
||||||
if err := json.Unmarshal(b, &s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hash, err := ParseEthHash(s)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
copy(id[:], hash[:])
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type EthFilterSpec struct {
|
type EthFilterSpec struct {
|
||||||
@ -637,6 +619,43 @@ type EthLog struct {
|
|||||||
BlockNumber EthUint64 `json:"blockNumber"`
|
BlockNumber EthUint64 `json:"blockNumber"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EthSubscribeParams handles raw jsonrpc params for eth_subscribe
|
||||||
|
type EthSubscribeParams struct {
|
||||||
|
EventType string
|
||||||
|
Params *EthSubscriptionParams
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EthSubscribeParams) UnmarshalJSON(b []byte) error {
|
||||||
|
var params []json.RawMessage
|
||||||
|
err := json.Unmarshal(b, ¶ms)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch len(params) {
|
||||||
|
case 2:
|
||||||
|
err = json.Unmarshal(params[1], &e.Params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fallthrough
|
||||||
|
case 1:
|
||||||
|
err = json.Unmarshal(params[0], &e.EventType)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return xerrors.Errorf("expected 1 or 2 params, got %d", len(params))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EthSubscribeParams) MarshalJSON() ([]byte, error) {
|
||||||
|
if e.Params != nil {
|
||||||
|
return json.Marshal([]interface{}{e.EventType, e.Params})
|
||||||
|
}
|
||||||
|
return json.Marshal([]interface{}{e.EventType})
|
||||||
|
}
|
||||||
|
|
||||||
type EthSubscriptionParams struct {
|
type EthSubscriptionParams struct {
|
||||||
// List of topics to be matched.
|
// List of topics to be matched.
|
||||||
// Optional, default: empty list
|
// Optional, default: empty list
|
||||||
|
@ -93,6 +93,48 @@ func TestEthHash(t *testing.T) {
|
|||||||
h1, err := EthHashFromCid(c)
|
h1, err := EthHashFromCid(c)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
require.Equal(t, h, h1)
|
require.Equal(t, h, h1)
|
||||||
|
|
||||||
|
jm, err := json.Marshal(h)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, hash, string(jm))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEthFilterID(t *testing.T) {
|
||||||
|
testcases := []string{
|
||||||
|
`"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"`,
|
||||||
|
`"0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"`,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, hash := range testcases {
|
||||||
|
var h EthFilterID
|
||||||
|
err := h.UnmarshalJSON([]byte(hash))
|
||||||
|
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, h.String(), strings.Replace(hash, `"`, "", -1))
|
||||||
|
|
||||||
|
jm, err := json.Marshal(h)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, hash, string(jm))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEthSubscriptionID(t *testing.T) {
|
||||||
|
testcases := []string{
|
||||||
|
`"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"`,
|
||||||
|
`"0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"`,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, hash := range testcases {
|
||||||
|
var h EthSubscriptionID
|
||||||
|
err := h.UnmarshalJSON([]byte(hash))
|
||||||
|
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.Equal(t, h.String(), strings.Replace(hash, `"`, "", -1))
|
||||||
|
|
||||||
|
jm, err := json.Marshal(h)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, hash, string(jm))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -319,11 +319,33 @@ func GetFullNodeAPIV1Single(ctx *cli.Context) (v1api.FullNode, jsonrpc.ClientClo
|
|||||||
return v1API, closer, nil
|
return v1API, closer, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetFullNodeAPIV1(ctx *cli.Context) (v1api.FullNode, jsonrpc.ClientCloser, error) {
|
type GetFullNodeOptions struct {
|
||||||
|
ethSubHandler api.EthSubscriber
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetFullNodeOption func(*GetFullNodeOptions)
|
||||||
|
|
||||||
|
func FullNodeWithEthSubscribtionHandler(sh api.EthSubscriber) GetFullNodeOption {
|
||||||
|
return func(opts *GetFullNodeOptions) {
|
||||||
|
opts.ethSubHandler = sh
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFullNodeAPIV1(ctx *cli.Context, opts ...GetFullNodeOption) (v1api.FullNode, jsonrpc.ClientCloser, error) {
|
||||||
if tn, ok := ctx.App.Metadata["testnode-full"]; ok {
|
if tn, ok := ctx.App.Metadata["testnode-full"]; ok {
|
||||||
return tn.(v1api.FullNode), func() {}, nil
|
return tn.(v1api.FullNode), func() {}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var options GetFullNodeOptions
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(&options)
|
||||||
|
}
|
||||||
|
|
||||||
|
var rpcOpts []jsonrpc.Option
|
||||||
|
if options.ethSubHandler != nil {
|
||||||
|
rpcOpts = append(rpcOpts, jsonrpc.WithClientHandler("Filecoin", options.ethSubHandler), jsonrpc.WithClientHandlerAlias("eth_subscription", "Filecoin.EthSubscription"))
|
||||||
|
}
|
||||||
|
|
||||||
heads, err := GetRawAPIMulti(ctx, repo.FullNode, "v1")
|
heads, err := GetRawAPIMulti(ctx, repo.FullNode, "v1")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@ -337,7 +359,7 @@ func GetFullNodeAPIV1(ctx *cli.Context) (v1api.FullNode, jsonrpc.ClientCloser, e
|
|||||||
var closers []jsonrpc.ClientCloser
|
var closers []jsonrpc.ClientCloser
|
||||||
|
|
||||||
for _, head := range heads {
|
for _, head := range heads {
|
||||||
v1api, closer, err := client.NewFullNodeRPCV1(ctx.Context, head.addr, head.header)
|
v1api, closer, err := client.NewFullNodeRPCV1(ctx.Context, head.addr, head.header, rpcOpts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("Not able to establish connection to node with addr: ", head.addr)
|
log.Warnf("Not able to establish connection to node with addr: ", head.addr)
|
||||||
continue
|
continue
|
||||||
|
@ -162,7 +162,9 @@ var runCmd = &cli.Command{
|
|||||||
log.Fatalf("Cannot register the view: %v", err)
|
log.Fatalf("Cannot register the view: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
api, closer, err := lcli.GetFullNodeAPIV1(cctx)
|
subHnd := gateway.NewEthSubHandler()
|
||||||
|
|
||||||
|
api, closer, err := lcli.GetFullNodeAPIV1(cctx, cliutil.FullNodeWithEthSubscribtionHandler(subHnd))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -195,7 +197,7 @@ var runCmd = &cli.Command{
|
|||||||
return xerrors.Errorf("failed to convert endpoint address to multiaddr: %w", err)
|
return xerrors.Errorf("failed to convert endpoint address to multiaddr: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gwapi := gateway.NewNode(api, lookbackCap, waitLookback, rateLimit, rateLimitTimeout)
|
gwapi := gateway.NewNode(api, subHnd, lookbackCap, waitLookback, rateLimit, rateLimitTimeout)
|
||||||
h, err := gateway.Handler(gwapi, api, perConnRateLimit, connPerMinute, serverOptions...)
|
h, err := gateway.Handler(gwapi, api, perConnRateLimit, connPerMinute, serverOptions...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to set up gateway HTTP handler")
|
return xerrors.Errorf("failed to set up gateway HTTP handler")
|
||||||
|
@ -2342,7 +2342,7 @@ Inputs:
|
|||||||
Response:
|
Response:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"oldestBlock": "0x5",
|
"oldestBlock": 42,
|
||||||
"baseFeePerGas": [
|
"baseFeePerGas": [
|
||||||
"0x0"
|
"0x0"
|
||||||
],
|
],
|
||||||
@ -2407,7 +2407,7 @@ Response:
|
|||||||
"gasLimit": "0x5",
|
"gasLimit": "0x5",
|
||||||
"gasUsed": "0x5",
|
"gasUsed": "0x5",
|
||||||
"timestamp": "0x5",
|
"timestamp": "0x5",
|
||||||
"extraData": "0x07",
|
"extraData": "Ynl0ZSBhcnJheQ==",
|
||||||
"mixHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
"mixHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
||||||
"nonce": "0x0707070707070707",
|
"nonce": "0x0707070707070707",
|
||||||
"baseFeePerGas": "0x0",
|
"baseFeePerGas": "0x0",
|
||||||
@ -2451,7 +2451,7 @@ Response:
|
|||||||
"gasLimit": "0x5",
|
"gasLimit": "0x5",
|
||||||
"gasUsed": "0x5",
|
"gasUsed": "0x5",
|
||||||
"timestamp": "0x5",
|
"timestamp": "0x5",
|
||||||
"extraData": "0x07",
|
"extraData": "Ynl0ZSBhcnJheQ==",
|
||||||
"mixHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
"mixHash": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
||||||
"nonce": "0x0707070707070707",
|
"nonce": "0x0707070707070707",
|
||||||
"baseFeePerGas": "0x0",
|
"baseFeePerGas": "0x0",
|
||||||
@ -2886,24 +2886,11 @@ Perms: write
|
|||||||
Inputs:
|
Inputs:
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
"string value",
|
"Bw=="
|
||||||
{
|
|
||||||
"topics": [
|
|
||||||
[
|
|
||||||
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
Response:
|
Response: `"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"`
|
||||||
```json
|
|
||||||
{
|
|
||||||
"subscription": "0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e",
|
|
||||||
"result": {}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### EthUninstallFilter
|
### EthUninstallFilter
|
||||||
Uninstalls a filter with given id.
|
Uninstalls a filter with given id.
|
||||||
|
71
gateway/eth_sub.go
Normal file
71
gateway/eth_sub.go
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
package gateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EthSubHandler struct {
|
||||||
|
queued map[ethtypes.EthSubscriptionID][]ethtypes.EthSubscriptionResponse
|
||||||
|
sinks map[ethtypes.EthSubscriptionID]func(context.Context, *ethtypes.EthSubscriptionResponse) error
|
||||||
|
|
||||||
|
lk sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEthSubHandler() *EthSubHandler {
|
||||||
|
return &EthSubHandler{
|
||||||
|
queued: make(map[ethtypes.EthSubscriptionID][]ethtypes.EthSubscriptionResponse),
|
||||||
|
sinks: make(map[ethtypes.EthSubscriptionID]func(context.Context, *ethtypes.EthSubscriptionResponse) error),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EthSubHandler) AddSub(ctx context.Context, id ethtypes.EthSubscriptionID, sink func(context.Context, *ethtypes.EthSubscriptionResponse) error) error {
|
||||||
|
e.lk.Lock()
|
||||||
|
defer e.lk.Unlock()
|
||||||
|
|
||||||
|
for _, p := range e.queued[id] {
|
||||||
|
p := p // copy
|
||||||
|
if err := sink(ctx, &p); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(e.queued, id)
|
||||||
|
e.sinks[id] = sink
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EthSubHandler) RemoveSub(id ethtypes.EthSubscriptionID) {
|
||||||
|
e.lk.Lock()
|
||||||
|
defer e.lk.Unlock()
|
||||||
|
|
||||||
|
delete(e.sinks, id)
|
||||||
|
delete(e.queued, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EthSubHandler) EthSubscription(ctx context.Context, r jsonrpc.RawParams) error {
|
||||||
|
p, err := jsonrpc.DecodeParams[ethtypes.EthSubscriptionResponse](r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
e.lk.Lock()
|
||||||
|
|
||||||
|
sink := e.sinks[p.SubscriptionID]
|
||||||
|
|
||||||
|
if sink == nil {
|
||||||
|
e.queued[p.SubscriptionID] = append(e.queued[p.SubscriptionID], p)
|
||||||
|
e.lk.Unlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
e.lk.Unlock()
|
||||||
|
|
||||||
|
return sink(ctx, &p) // todo track errors and auto-unsubscribe on rpc conn close?
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ api.EthSubscriber = (*EthSubHandler)(nil)
|
@ -27,14 +27,14 @@ const perConnLimiterKey perConnLimiterKeyType = "limiter"
|
|||||||
|
|
||||||
type filterTrackerKeyType string
|
type filterTrackerKeyType string
|
||||||
|
|
||||||
const filterTrackerKey filterTrackerKeyType = "filterTracker"
|
const statefulCallTrackerKey filterTrackerKeyType = "statefulCallTracker"
|
||||||
|
|
||||||
// Handler returns a gateway http.Handler, to be mounted as-is on the server.
|
// Handler returns a gateway http.Handler, to be mounted as-is on the server.
|
||||||
func Handler(gwapi lapi.Gateway, api lapi.FullNode, rateLimit int64, connPerMinute int64, opts ...jsonrpc.ServerOption) (http.Handler, error) {
|
func Handler(gwapi lapi.Gateway, api lapi.FullNode, rateLimit int64, connPerMinute int64, opts ...jsonrpc.ServerOption) (http.Handler, error) {
|
||||||
m := mux.NewRouter()
|
m := mux.NewRouter()
|
||||||
|
|
||||||
serveRpc := func(path string, hnd interface{}) {
|
serveRpc := func(path string, hnd interface{}) {
|
||||||
rpcServer := jsonrpc.NewServer(append(opts, jsonrpc.WithServerErrors(lapi.RPCErrors))...)
|
rpcServer := jsonrpc.NewServer(append(opts, jsonrpc.WithReverseClient[lapi.EthSubscriberMethods]("Filecoin"), jsonrpc.WithServerErrors(lapi.RPCErrors))...)
|
||||||
rpcServer.Register("Filecoin", hnd)
|
rpcServer.Register("Filecoin", hnd)
|
||||||
rpcServer.AliasMethod("rpc.discover", "Filecoin.Discover")
|
rpcServer.AliasMethod("rpc.discover", "Filecoin.Discover")
|
||||||
|
|
||||||
@ -90,7 +90,7 @@ func (h RateLimiterHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
r = r.WithContext(context.WithValue(r.Context(), perConnLimiterKey, h.limiter))
|
r = r.WithContext(context.WithValue(r.Context(), perConnLimiterKey, h.limiter))
|
||||||
|
|
||||||
// also add a filter tracker to the context
|
// also add a filter tracker to the context
|
||||||
r = r.WithContext(context.WithValue(r.Context(), filterTrackerKey, newFilterTracker()))
|
r = r.WithContext(context.WithValue(r.Context(), statefulCallTrackerKey, newStatefulCallTracker()))
|
||||||
|
|
||||||
h.handler.ServeHTTP(w, r)
|
h.handler.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-bitfield"
|
"github.com/filecoin-project/go-bitfield"
|
||||||
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/dline"
|
"github.com/filecoin-project/go-state-types/dline"
|
||||||
"github.com/filecoin-project/go-state-types/network"
|
"github.com/filecoin-project/go-state-types/network"
|
||||||
@ -117,7 +118,7 @@ type TargetAPI interface {
|
|||||||
EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error)
|
EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error)
|
||||||
EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error)
|
EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error)
|
||||||
EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error)
|
EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error)
|
||||||
EthSubscribe(ctx context.Context, eventType string, params *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error)
|
EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error)
|
||||||
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error)
|
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,6 +126,7 @@ var _ TargetAPI = *new(api.FullNode) // gateway depends on latest
|
|||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
target TargetAPI
|
target TargetAPI
|
||||||
|
subHnd *EthSubHandler
|
||||||
lookbackCap time.Duration
|
lookbackCap time.Duration
|
||||||
stateWaitLookbackLimit abi.ChainEpoch
|
stateWaitLookbackLimit abi.ChainEpoch
|
||||||
rateLimiter *rate.Limiter
|
rateLimiter *rate.Limiter
|
||||||
@ -141,7 +143,7 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// NewNode creates a new gateway node.
|
// NewNode creates a new gateway node.
|
||||||
func NewNode(api TargetAPI, lookbackCap time.Duration, stateWaitLookbackLimit abi.ChainEpoch, rateLimit int64, rateLimitTimeout time.Duration) *Node {
|
func NewNode(api TargetAPI, sHnd *EthSubHandler, lookbackCap time.Duration, stateWaitLookbackLimit abi.ChainEpoch, rateLimit int64, rateLimitTimeout time.Duration) *Node {
|
||||||
var limit rate.Limit
|
var limit rate.Limit
|
||||||
if rateLimit == 0 {
|
if rateLimit == 0 {
|
||||||
limit = rate.Inf
|
limit = rate.Inf
|
||||||
@ -150,6 +152,7 @@ func NewNode(api TargetAPI, lookbackCap time.Duration, stateWaitLookbackLimit ab
|
|||||||
}
|
}
|
||||||
return &Node{
|
return &Node{
|
||||||
target: api,
|
target: api,
|
||||||
|
subHnd: sHnd,
|
||||||
lookbackCap: lookbackCap,
|
lookbackCap: lookbackCap,
|
||||||
stateWaitLookbackLimit: stateWaitLookbackLimit,
|
stateWaitLookbackLimit: stateWaitLookbackLimit,
|
||||||
rateLimiter: rate.NewLimiter(limit, stateRateLimitTokens),
|
rateLimiter: rate.NewLimiter(limit, stateRateLimitTokens),
|
||||||
|
@ -89,7 +89,7 @@ func TestGatewayAPIChainGetTipSetByHeight(t *testing.T) {
|
|||||||
tt := tt
|
tt := tt
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
mock := &mockGatewayDepsAPI{}
|
mock := &mockGatewayDepsAPI{}
|
||||||
a := NewNode(mock, DefaultLookbackCap, DefaultStateWaitLookbackLimit, 0, time.Minute)
|
a := NewNode(mock, nil, DefaultLookbackCap, DefaultStateWaitLookbackLimit, 0, time.Minute)
|
||||||
|
|
||||||
// Create tipsets from genesis up to tskh and return the highest
|
// Create tipsets from genesis up to tskh and return the highest
|
||||||
ts := mock.createTipSets(tt.args.tskh, tt.args.genesisTS)
|
ts := mock.createTipSets(tt.args.tskh, tt.args.genesisTS)
|
||||||
@ -245,7 +245,7 @@ func TestGatewayVersion(t *testing.T) {
|
|||||||
//stm: @GATEWAY_NODE_GET_VERSION_001
|
//stm: @GATEWAY_NODE_GET_VERSION_001
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
mock := &mockGatewayDepsAPI{}
|
mock := &mockGatewayDepsAPI{}
|
||||||
a := NewNode(mock, DefaultLookbackCap, DefaultStateWaitLookbackLimit, 0, time.Minute)
|
a := NewNode(mock, nil, DefaultLookbackCap, DefaultStateWaitLookbackLimit, 0, time.Minute)
|
||||||
|
|
||||||
v, err := a.Version(ctx)
|
v, err := a.Version(ctx)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -256,7 +256,7 @@ func TestGatewayLimitTokensAvailable(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
mock := &mockGatewayDepsAPI{}
|
mock := &mockGatewayDepsAPI{}
|
||||||
tokens := 3
|
tokens := 3
|
||||||
a := NewNode(mock, DefaultLookbackCap, DefaultStateWaitLookbackLimit, int64(tokens), time.Minute)
|
a := NewNode(mock, nil, DefaultLookbackCap, DefaultStateWaitLookbackLimit, int64(tokens), time.Minute)
|
||||||
require.NoError(t, a.limit(ctx, tokens), "requests should not be limited when there are enough tokens available")
|
require.NoError(t, a.limit(ctx, tokens), "requests should not be limited when there are enough tokens available")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,7 +264,7 @@ func TestGatewayLimitTokensNotAvailable(t *testing.T) {
|
|||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
mock := &mockGatewayDepsAPI{}
|
mock := &mockGatewayDepsAPI{}
|
||||||
tokens := 3
|
tokens := 3
|
||||||
a := NewNode(mock, DefaultLookbackCap, DefaultStateWaitLookbackLimit, int64(1), time.Millisecond)
|
a := NewNode(mock, nil, DefaultLookbackCap, DefaultStateWaitLookbackLimit, int64(1), time.Millisecond)
|
||||||
var err error
|
var err error
|
||||||
// try to be rate limited
|
// try to be rate limited
|
||||||
for i := 0; i <= 1000; i++ {
|
for i := 0; i <= 1000; i++ {
|
||||||
|
@ -3,12 +3,14 @@ package gateway
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
|
||||||
@ -352,7 +354,7 @@ func (gw *Node) EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ft := filterTrackerFromContext(ctx)
|
ft := statefulCallFromContext(ctx)
|
||||||
ft.lk.Lock()
|
ft.lk.Lock()
|
||||||
_, ok := ft.userFilters[id]
|
_, ok := ft.userFilters[id]
|
||||||
ft.lk.Unlock()
|
ft.lk.Unlock()
|
||||||
@ -369,7 +371,7 @@ func (gw *Node) EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
ft := filterTrackerFromContext(ctx)
|
ft := statefulCallFromContext(ctx)
|
||||||
ft.lk.Lock()
|
ft.lk.Lock()
|
||||||
_, ok := ft.userFilters[id]
|
_, ok := ft.userFilters[id]
|
||||||
ft.lk.Unlock()
|
ft.lk.Unlock()
|
||||||
@ -417,7 +419,7 @@ func (gw *Node) EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check if the filter belongs to this connection
|
// check if the filter belongs to this connection
|
||||||
ft := filterTrackerFromContext(ctx)
|
ft := statefulCallFromContext(ctx)
|
||||||
ft.lk.Lock()
|
ft.lk.Lock()
|
||||||
defer ft.lk.Unlock()
|
defer ft.lk.Unlock()
|
||||||
|
|
||||||
@ -434,18 +436,88 @@ func (gw *Node) EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID)
|
|||||||
return ok, nil
|
return ok, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gw *Node) EthSubscribe(ctx context.Context, eventType string, params *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) {
|
func (gw *Node) EthSubscribe(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {
|
||||||
return nil, xerrors.Errorf("not implemented")
|
// validate params
|
||||||
|
_, err := jsonrpc.DecodeParams[ethtypes.EthSubscribeParams](p)
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EthSubscriptionID{}, xerrors.Errorf("decoding params: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
|
||||||
|
return ethtypes.EthSubscriptionID{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if gw.subHnd == nil {
|
||||||
|
return ethtypes.EthSubscriptionID{}, xerrors.New("subscription support not enabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
ethCb, ok := jsonrpc.ExtractReverseClient[api.EthSubscriberMethods](ctx)
|
||||||
|
if !ok {
|
||||||
|
return ethtypes.EthSubscriptionID{}, xerrors.Errorf("connection doesn't support callbacks")
|
||||||
|
}
|
||||||
|
|
||||||
|
ft := statefulCallFromContext(ctx)
|
||||||
|
ft.lk.Lock()
|
||||||
|
defer ft.lk.Unlock()
|
||||||
|
|
||||||
|
if len(ft.userSubscriptions) >= EthMaxFiltersPerConn {
|
||||||
|
return ethtypes.EthSubscriptionID{}, fmt.Errorf("too many subscriptions")
|
||||||
|
}
|
||||||
|
|
||||||
|
sub, err := gw.target.EthSubscribe(ctx, p)
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EthSubscriptionID{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = gw.subHnd.AddSub(ctx, sub, func(ctx context.Context, response *ethtypes.EthSubscriptionResponse) error {
|
||||||
|
outParam, err := json.Marshal(response)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return ethCb.EthSubscription(ctx, outParam)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EthSubscriptionID{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ft.userSubscriptions[sub] = time.Now()
|
||||||
|
|
||||||
|
return sub, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gw *Node) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) {
|
func (gw *Node) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) {
|
||||||
return false, xerrors.Errorf("not implemented")
|
if err := gw.limit(ctx, stateRateLimitTokens); err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the filter belongs to this connection
|
||||||
|
ft := statefulCallFromContext(ctx)
|
||||||
|
ft.lk.Lock()
|
||||||
|
defer ft.lk.Unlock()
|
||||||
|
|
||||||
|
if _, ok := ft.userSubscriptions[id]; !ok {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ok, err := gw.target.EthUnsubscribe(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(ft.userSubscriptions, id)
|
||||||
|
|
||||||
|
if gw.subHnd != nil {
|
||||||
|
gw.subHnd.RemoveSub(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ok, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var EthMaxFiltersPerConn = 16 // todo make this configurable
|
var EthMaxFiltersPerConn = 16 // todo make this configurable
|
||||||
|
|
||||||
func addUserFilterLimited(ctx context.Context, cb func() (ethtypes.EthFilterID, error)) (ethtypes.EthFilterID, error) {
|
func addUserFilterLimited(ctx context.Context, cb func() (ethtypes.EthFilterID, error)) (ethtypes.EthFilterID, error) {
|
||||||
ft := filterTrackerFromContext(ctx)
|
ft := statefulCallFromContext(ctx)
|
||||||
ft.lk.Lock()
|
ft.lk.Lock()
|
||||||
defer ft.lk.Unlock()
|
defer ft.lk.Unlock()
|
||||||
|
|
||||||
@ -463,19 +535,21 @@ func addUserFilterLimited(ctx context.Context, cb func() (ethtypes.EthFilterID,
|
|||||||
return id, nil
|
return id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterTrackerFromContext(ctx context.Context) *filterTracker {
|
func statefulCallFromContext(ctx context.Context) *statefulCallTracker {
|
||||||
return ctx.Value(filterTrackerKey).(*filterTracker)
|
return ctx.Value(statefulCallTrackerKey).(*statefulCallTracker)
|
||||||
}
|
}
|
||||||
|
|
||||||
type filterTracker struct {
|
type statefulCallTracker struct {
|
||||||
lk sync.Mutex
|
lk sync.Mutex
|
||||||
|
|
||||||
userFilters map[ethtypes.EthFilterID]time.Time
|
userFilters map[ethtypes.EthFilterID]time.Time
|
||||||
|
userSubscriptions map[ethtypes.EthSubscriptionID]time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// called per request (ws connection)
|
// called per request (ws connection)
|
||||||
func newFilterTracker() *filterTracker {
|
func newStatefulCallTracker() *statefulCallTracker {
|
||||||
return &filterTracker{
|
return &statefulCallTracker{
|
||||||
userFilters: make(map[ethtypes.EthFilterID]time.Time),
|
userFilters: make(map[ethtypes.EthFilterID]time.Time),
|
||||||
|
userSubscriptions: make(map[ethtypes.EthSubscriptionID]time.Time),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,7 @@ func generate(path, pkg, outpkg, outfile string) error {
|
|||||||
if len(tf) != 2 {
|
if len(tf) != 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if tf[0] != "perm" { // todo: allow more tag types
|
if tf[0] != "perm" && tf[0] != "rpc_method" && tf[0] != "notify" { // todo: allow more tag types
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
info.Methods[mname].Tags[tf[0]] = tf
|
info.Methods[mname].Tags[tf[0]] = tf
|
||||||
@ -302,12 +302,14 @@ type {{.Num}}Struct struct {
|
|||||||
{{range .Include}}
|
{{range .Include}}
|
||||||
{{.}}Struct
|
{{.}}Struct
|
||||||
{{end}}
|
{{end}}
|
||||||
Internal struct {
|
Internal {{.Num}}Methods
|
||||||
|
}
|
||||||
|
|
||||||
|
type {{.Num}}Methods struct {
|
||||||
{{range .Methods}}
|
{{range .Methods}}
|
||||||
{{.Num}} func({{.NamedParams}}) ({{.Results}}) `+"`"+`{{range .Tags}}{{index . 0}}:"{{index . 1}}"{{end}}`+"`"+`
|
{{.Num}} func({{.NamedParams}}) ({{.Results}}) `+"`"+`{{range .Tags}}{{index . 0}}:"{{index . 1}}"{{end}}`+"`"+`
|
||||||
{{end}}
|
{{end}}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
type {{.Num}}Stub struct {
|
type {{.Num}}Stub struct {
|
||||||
{{range .Include}}
|
{{range .Include}}
|
||||||
|
4
go.mod
4
go.mod
@ -40,11 +40,11 @@ require (
|
|||||||
github.com/filecoin-project/go-fil-commcid v0.1.0
|
github.com/filecoin-project/go-fil-commcid v0.1.0
|
||||||
github.com/filecoin-project/go-fil-commp-hashhash v0.1.0
|
github.com/filecoin-project/go-fil-commp-hashhash v0.1.0
|
||||||
github.com/filecoin-project/go-fil-markets v1.25.2
|
github.com/filecoin-project/go-fil-markets v1.25.2
|
||||||
github.com/filecoin-project/go-jsonrpc v0.1.9
|
github.com/filecoin-project/go-jsonrpc v0.2.1
|
||||||
github.com/filecoin-project/go-legs v0.4.4
|
github.com/filecoin-project/go-legs v0.4.4
|
||||||
github.com/filecoin-project/go-padreader v0.0.1
|
github.com/filecoin-project/go-padreader v0.0.1
|
||||||
github.com/filecoin-project/go-paramfetch v0.0.4
|
github.com/filecoin-project/go-paramfetch v0.0.4
|
||||||
github.com/filecoin-project/go-state-types v0.10.0-alpha-10
|
github.com/filecoin-project/go-state-types v0.10.0-alpha-11
|
||||||
github.com/filecoin-project/go-statemachine v1.0.2
|
github.com/filecoin-project/go-statemachine v1.0.2
|
||||||
github.com/filecoin-project/go-statestore v0.2.0
|
github.com/filecoin-project/go-statestore v0.2.0
|
||||||
github.com/filecoin-project/go-storedcounter v0.1.0
|
github.com/filecoin-project/go-storedcounter v0.1.0
|
||||||
|
9
go.sum
9
go.sum
@ -338,8 +338,8 @@ github.com/filecoin-project/go-hamt-ipld/v2 v2.0.0/go.mod h1:7aWZdaQ1b16BVoQUYR+
|
|||||||
github.com/filecoin-project/go-hamt-ipld/v3 v3.0.1/go.mod h1:gXpNmr3oQx8l3o7qkGyDjJjYSRX7hp/FGOStdqrWyDI=
|
github.com/filecoin-project/go-hamt-ipld/v3 v3.0.1/go.mod h1:gXpNmr3oQx8l3o7qkGyDjJjYSRX7hp/FGOStdqrWyDI=
|
||||||
github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0 h1:rVVNq0x6RGQIzCo1iiJlGFm9AGIZzeifggxtKMU7zmI=
|
github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0 h1:rVVNq0x6RGQIzCo1iiJlGFm9AGIZzeifggxtKMU7zmI=
|
||||||
github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0/go.mod h1:bxmzgT8tmeVQA1/gvBwFmYdT8SOFUwB3ovSUfG1Ux0g=
|
github.com/filecoin-project/go-hamt-ipld/v3 v3.1.0/go.mod h1:bxmzgT8tmeVQA1/gvBwFmYdT8SOFUwB3ovSUfG1Ux0g=
|
||||||
github.com/filecoin-project/go-jsonrpc v0.1.9 h1:HRWLxo7HAWzI3xZGeFG4LZJoYpms+Q+8kwmMTLnyS3A=
|
github.com/filecoin-project/go-jsonrpc v0.2.1 h1:xfxkfIAO300sPiV59DnxnCb4sdTtWYlRz/TsP+ByT2E=
|
||||||
github.com/filecoin-project/go-jsonrpc v0.1.9/go.mod h1:XBBpuKIMaXIIzeqzO1iucq4GvbF8CxmXRFoezRh+Cx4=
|
github.com/filecoin-project/go-jsonrpc v0.2.1/go.mod h1:jBSvPTl8V1N7gSTuCR4bis8wnQnIjHbRPpROol6iQKM=
|
||||||
github.com/filecoin-project/go-legs v0.4.4 h1:mpMmAOOnamaz0CV9rgeKhEWA8j9kMC+f+UGCGrxKaZo=
|
github.com/filecoin-project/go-legs v0.4.4 h1:mpMmAOOnamaz0CV9rgeKhEWA8j9kMC+f+UGCGrxKaZo=
|
||||||
github.com/filecoin-project/go-legs v0.4.4/go.mod h1:JQ3hA6xpJdbR8euZ2rO0jkxaMxeidXf0LDnVuqPAe9s=
|
github.com/filecoin-project/go-legs v0.4.4/go.mod h1:JQ3hA6xpJdbR8euZ2rO0jkxaMxeidXf0LDnVuqPAe9s=
|
||||||
github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20/go.mod h1:mPn+LRRd5gEKNAtc+r3ScpW2JRU/pj4NBKdADYWHiak=
|
github.com/filecoin-project/go-padreader v0.0.0-20200903213702-ed5fae088b20/go.mod h1:mPn+LRRd5gEKNAtc+r3ScpW2JRU/pj4NBKdADYWHiak=
|
||||||
@ -354,8 +354,8 @@ github.com/filecoin-project/go-state-types v0.1.0/go.mod h1:ezYnPf0bNkTsDibL/psS
|
|||||||
github.com/filecoin-project/go-state-types v0.1.6/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
|
github.com/filecoin-project/go-state-types v0.1.6/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
|
||||||
github.com/filecoin-project/go-state-types v0.1.8/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
|
github.com/filecoin-project/go-state-types v0.1.8/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
|
||||||
github.com/filecoin-project/go-state-types v0.1.10/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
|
github.com/filecoin-project/go-state-types v0.1.10/go.mod h1:UwGVoMsULoCK+bWjEdd/xLCvLAQFBC7EDT477SKml+Q=
|
||||||
github.com/filecoin-project/go-state-types v0.10.0-alpha-10 h1:QUpSayVFUADlrtzCh7SDNlbuaNSlYPBR46Nt7WpFl9I=
|
github.com/filecoin-project/go-state-types v0.10.0-alpha-11 h1:lfrbmLXaC3vQk1gQCUwtTuY1U2ANrgDsJ7+VapBjRCo=
|
||||||
github.com/filecoin-project/go-state-types v0.10.0-alpha-10/go.mod h1:FPgQE05BFwZxKw/vCuIaIrzfJKo4RPQQMMPGd43dAFI=
|
github.com/filecoin-project/go-state-types v0.10.0-alpha-11/go.mod h1:aLIas+W8BWAfpLWEPUOGMPBdhcVwoCG4pIQSQk26024=
|
||||||
github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig=
|
github.com/filecoin-project/go-statemachine v0.0.0-20200925024713-05bd7c71fbfe/go.mod h1:FGwQgZAt2Gh5mjlwJUlVB62JeYdo+if0xWxSEfBD9ig=
|
||||||
github.com/filecoin-project/go-statemachine v1.0.2 h1:421SSWBk8GIoCoWYYTE/d+qCWccgmRH0uXotXRDjUbc=
|
github.com/filecoin-project/go-statemachine v1.0.2 h1:421SSWBk8GIoCoWYYTE/d+qCWccgmRH0uXotXRDjUbc=
|
||||||
github.com/filecoin-project/go-statemachine v1.0.2/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54=
|
github.com/filecoin-project/go-statemachine v1.0.2/go.mod h1:jZdXXiHa61n4NmgWFG4w8tnqgvZVHYbJ3yW7+y8bF54=
|
||||||
@ -835,7 +835,6 @@ github.com/ipfs/go-log/v2 v2.0.1/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBW
|
|||||||
github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=
|
github.com/ipfs/go-log/v2 v2.0.2/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=
|
||||||
github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=
|
github.com/ipfs/go-log/v2 v2.0.3/go.mod h1:O7P1lJt27vWHhOwQmcFEvlmo49ry2VY2+JfBWFaa9+0=
|
||||||
github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=
|
github.com/ipfs/go-log/v2 v2.0.5/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=
|
||||||
github.com/ipfs/go-log/v2 v2.0.8/go.mod h1:eZs4Xt4ZUJQFM3DlanGhy7TkwwawCZcSByscwkWG+dw=
|
|
||||||
github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
|
github.com/ipfs/go-log/v2 v2.1.1/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
|
||||||
github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
|
github.com/ipfs/go-log/v2 v2.1.2-0.20200626104915-0016c0b4b3e4/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
|
||||||
github.com/ipfs/go-log/v2 v2.1.2/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
|
github.com/ipfs/go-log/v2 v2.1.2/go.mod h1:2v2nsGfZsvvAJz13SyFzf9ObaqwHiHxsPLEHntrv9KM=
|
||||||
|
1
itests/contracts/AutoSelfDestruct.hex
Normal file
1
itests/contracts/AutoSelfDestruct.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b5061001f61002460201b60201c565b61003d565b3373ffffffffffffffffffffffffffffffffffffffff16ff5b60848061004b6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806383197ef014602d575b600080fd5b60336035565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea26469706673582212208d48a69a112633756d84552847610df29b02ac89dd39e4e295066e99a45e809664736f6c63430008110033
|
11
itests/contracts/AutoSelfDestruct.sol
Normal file
11
itests/contracts/AutoSelfDestruct.sol
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.8.17;
|
||||||
|
|
||||||
|
contract AutoSelfDestruct {
|
||||||
|
constructor() {
|
||||||
|
destroy();
|
||||||
|
}
|
||||||
|
function destroy() public {
|
||||||
|
selfdestruct(payable(msg.sender));
|
||||||
|
}
|
||||||
|
}
|
1
itests/contracts/Constructor.hex
Normal file
1
itests/contracts/Constructor.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b506103ca806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c806358f5ebb614610030575b600080fd5b61004a60048036038101906100459190610123565b610060565b6040516100579190610191565b60405180910390f35b60008082604051610070906100db565b61007a91906101bb565b604051809103906000f080158015610096573d6000803e3d6000fd5b5090507f3a5c468996b00310e3e82919e3af9cce21d49c40c39a2627a9f946e1a54d886232846040516100ca9291906101d6565b60405180910390a180915050919050565b6101958061020083390190565b600080fd5b6000819050919050565b610100816100ed565b811461010b57600080fd5b50565b60008135905061011d816100f7565b92915050565b600060208284031215610139576101386100e8565b5b60006101478482850161010e565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b600061017b82610150565b9050919050565b61018b81610170565b82525050565b60006020820190506101a66000830184610182565b92915050565b6101b5816100ed565b82525050565b60006020820190506101d060008301846101ac565b92915050565b60006040820190506101eb6000830185610182565b6101f860208301846101ac565b939250505056fe608060405234801561001057600080fd5b506040516101953803806101958339818101604052810190610032919061007a565b80600081905550506100a7565b600080fd5b6000819050919050565b61005781610044565b811461006257600080fd5b50565b6000815190506100748161004e565b92915050565b6000602082840312156100905761008f61003f565b5b600061009e84828501610065565b91505092915050565b60e0806100b56000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c80638381f58a146037578063eeb4e367146051575b600080fd5b603d606b565b604051604891906091565b60405180910390f35b60576071565b604051606291906091565b60405180910390f35b60005481565b60008054905090565b6000819050919050565b608b81607a565b82525050565b600060208201905060a460008301846084565b9291505056fea2646970667358221220451c388f24a935fc5f5eef536207cbd982254ac8521d49937bb10e5079e3924164736f6c63430008110033a264697066735822122027da159d84a9bdcd5aff5755c4602f7099db638f7a95d715c76454c99511146f64736f6c63430008110033
|
29
itests/contracts/Constructor.sol
Normal file
29
itests/contracts/Constructor.sol
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.2;
|
||||||
|
|
||||||
|
|
||||||
|
contract Test_contract {
|
||||||
|
uint256 public number;
|
||||||
|
|
||||||
|
constructor(uint256 _number) {
|
||||||
|
number = _number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_number() public view returns (uint256) {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract App {
|
||||||
|
|
||||||
|
event NewTest(address sender, uint256 number);
|
||||||
|
|
||||||
|
function new_Test(uint256 number)
|
||||||
|
public
|
||||||
|
returns (address)
|
||||||
|
{
|
||||||
|
address mynew = address(new Test_contract({_number: number}));
|
||||||
|
emit NewTest(tx.origin, number);
|
||||||
|
return mynew;
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1 @@
|
|||||||
608060405234801561001057600080fd5b50610477806100206000396000f3fe6080604052600436106100345760003560e01c806361bc221a146100395780638ada066e14610064578063d1e0f3081461008f575b600080fd5b34801561004557600080fd5b5061004e6100bf565b60405161005b919061022c565b60405180910390f35b34801561007057600080fd5b506100796100c5565b604051610086919061022c565b60405180910390f35b6100a960048036038101906100a491906102d6565b6100ce565b6040516100b6919061022c565b60405180910390f35b60005481565b60008054905090565b6000808373ffffffffffffffffffffffffffffffffffffffff16836040516024016100f9919061022c565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516101839190610387565b600060405180830381855af49150503d80600081146101be576040519150601f19603f3d011682016040523d82523d6000602084013e6101c3565b606091505b5050905080610207576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101fe90610421565b60405180910390fd5b60005491505092915050565b6000819050919050565b61022681610213565b82525050565b6000602082019050610241600083018461021d565b92915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102778261024c565b9050919050565b6102878161026c565b811461029257600080fd5b50565b6000813590506102a48161027e565b92915050565b6102b381610213565b81146102be57600080fd5b50565b6000813590506102d0816102aa565b92915050565b600080604083850312156102ed576102ec610247565b5b60006102fb85828601610295565b925050602061030c858286016102c1565b9150509250929050565b600081519050919050565b600081905092915050565b60005b8381101561034a57808201518184015260208101905061032f565b60008484015250505050565b600061036182610316565b61036b8185610321565b935061037b81856020860161032c565b80840191505092915050565b60006103938284610356565b915081905092915050565b600082825260208201905092915050565b7f4572726f72206d6573736167653a2044656c656761746563616c6c206661696c60008201527f6564000000000000000000000000000000000000000000000000000000000000602082015250565b600061040b60228361039e565b9150610416826103af565b604082019050919050565b6000602082019050818103600083015261043a816103fe565b905091905056fea26469706673582212203663909b8221e9b87047be99420c00339af1430c085260df209b909ed8e0f05164736f6c63430008110033
|
608060405234801561001057600080fd5b5061087e806100206000396000f3fe6080604052600436106100555760003560e01c80630712ede21461005a57806361bc221a1461008a5780637da3c3ab146100b55780638ada066e146100cc578063bed56f47146100f7578063d1e0f30814610127575b600080fd5b610074600480360381019061006f919061060f565b610157565b604051610081919061065e565b60405180910390f35b34801561009657600080fd5b5061009f610298565b6040516100ac919061065e565b60405180910390f35b3480156100c157600080fd5b506100ca61029e565b005b3480156100d857600080fd5b506100e16102e1565b6040516100ee919061065e565b60405180910390f35b610111600480360381019061010c919061060f565b6102ea565b60405161011e919061065e565b60405180910390f35b610141600480360381019061013c919061060f565b610431565b60405161014e919061065e565b60405180910390f35b6000808373ffffffffffffffffffffffffffffffffffffffff1683604051602401610182919061065e565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff838183161783525050505060405161020c91906106ea565b600060405180830381855af49150503d8060008114610247576040519150601f19603f3d011682016040523d82523d6000602084013e61024c565b606091505b505090506000610291576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102889061075e565b60405180910390fd5b5092915050565b60005481565b60006102df576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102d69061075e565b60405180910390fd5b565b60008054905090565b6000808373ffffffffffffffffffffffffffffffffffffffff16848460405160240161031792919061078d565b6040516020818303038152906040527fbed56f47000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516103a191906106ea565b600060405180830381855af49150503d80600081146103dc576040519150601f19603f3d011682016040523d82523d6000602084013e6103e1565b606091505b5050905080610425576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161041c90610828565b60405180910390fd5b60005491505092915050565b6000808373ffffffffffffffffffffffffffffffffffffffff168360405160240161045c919061065e565b6040516020818303038152906040527f6466414b000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516104e691906106ea565b600060405180830381855af49150503d8060008114610521576040519150601f19603f3d011682016040523d82523d6000602084013e610526565b606091505b505090508061056a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161056190610828565b60405180910390fd5b60005491505092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006105a68261057b565b9050919050565b6105b68161059b565b81146105c157600080fd5b50565b6000813590506105d3816105ad565b92915050565b6000819050919050565b6105ec816105d9565b81146105f757600080fd5b50565b600081359050610609816105e3565b92915050565b6000806040838503121561062657610625610576565b5b6000610634858286016105c4565b9250506020610645858286016105fa565b9150509250929050565b610658816105d9565b82525050565b6000602082019050610673600083018461064f565b92915050565b600081519050919050565b600081905092915050565b60005b838110156106ad578082015181840152602081019050610692565b60008484015250505050565b60006106c482610679565b6106ce8185610684565b93506106de81856020860161068f565b80840191505092915050565b60006106f682846106b9565b915081905092915050565b600082825260208201905092915050565b7f696e74656e74696f6e616c6c79207468726f77696e67206572726f7200000000600082015250565b6000610748601c83610701565b915061075382610712565b602082019050919050565b600060208201905081810360008301526107778161073b565b9050919050565b6107878161059b565b82525050565b60006040820190506107a2600083018561077e565b6107af602083018461064f565b9392505050565b7f4572726f72206d6573736167653a2044656c656761746563616c6c206661696c60008201527f6564000000000000000000000000000000000000000000000000000000000000602082015250565b6000610812602283610701565b915061081d826107b6565b604082019050919050565b6000602082019050818103600083015261084181610805565b905091905056fea2646970667358221220b2a3ae7e2a9ffc78e3e2a7aadb2885435c5e51aa9d3f07372a0dffb6238aa1db64736f6c63430008110033
|
@ -14,4 +14,20 @@ contract DelegatecallStorage {
|
|||||||
require(success, 'Error message: Delegatecall failed');
|
require(success, 'Error message: Delegatecall failed');
|
||||||
return counter;
|
return counter;
|
||||||
}
|
}
|
||||||
|
function setVarsSelf(address _contract, uint _counter) public payable returns (uint){
|
||||||
|
(bool success, ) = _contract.delegatecall(
|
||||||
|
abi.encodeWithSignature("setVarsSelf(address,uint256)", _contract, _counter)
|
||||||
|
);
|
||||||
|
require(success, 'Error message: Delegatecall failed');
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
function setVarsRevert(address _contract, uint _counter) public payable returns (uint){
|
||||||
|
(bool success, ) = _contract.delegatecall(
|
||||||
|
abi.encodeWithSignature("setVars(uint256)", _counter)
|
||||||
|
);
|
||||||
|
require(false,"intentionally throwing error");
|
||||||
|
}
|
||||||
|
function revert() public{
|
||||||
|
require(false,"intentionally throwing error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
1
itests/contracts/GasLimitSend.hex
Normal file
1
itests/contracts/GasLimitSend.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b5061027c806100206000396000f3fe6080604052600436106100385760003560e01c80630bc07a88146100435780633da767881461005a578063f0ba84401461008557610039565b5b6100416100c2565b005b34801561004f57600080fd5b506100586100c2565b005b34801561006657600080fd5b5061006f61010d565b60405161007c9190610156565b60405180910390f35b34801561009157600080fd5b506100ac60048036038101906100a791906101a2565b610119565b6040516100b99190610156565b60405180910390f35b60005b606481101561010a5760008190806001815401808255809150506001900390600052602060002001600090919091909150558080610102906101fe565b9150506100c5565b50565b60008080549050905090565b6000818154811061012957600080fd5b906000526020600020016000915090505481565b6000819050919050565b6101508161013d565b82525050565b600060208201905061016b6000830184610147565b92915050565b600080fd5b61017f8161013d565b811461018a57600080fd5b50565b60008135905061019c81610176565b92915050565b6000602082840312156101b8576101b7610171565b5b60006101c68482850161018d565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60006102098261013d565b91507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361023b5761023a6101cf565b5b60018201905091905056fea2646970667358221220c56d78e0c60a01681eee1b76c95e7b214d16a512c944e31cfee71eb727c1e44064736f6c63430008110033
|
34
itests/contracts/GasLimitSend.sol
Normal file
34
itests/contracts/GasLimitSend.sol
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.17;
|
||||||
|
|
||||||
|
contract GasLimitTest {
|
||||||
|
address payable receiver;
|
||||||
|
constructor(){
|
||||||
|
address mynew = address(new GasLimitTestReceiver());
|
||||||
|
receiver = payable(mynew);
|
||||||
|
}
|
||||||
|
function send() public payable{
|
||||||
|
receiver.transfer(msg.value);
|
||||||
|
}
|
||||||
|
function expensiveTest() public{
|
||||||
|
GasLimitTestReceiver(receiver).expensive();
|
||||||
|
}
|
||||||
|
function getDataLength() public returns (uint256) {
|
||||||
|
return GasLimitTestReceiver(receiver).getDataLength();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract GasLimitTestReceiver {
|
||||||
|
uint256[] public data;
|
||||||
|
fallback() external payable {
|
||||||
|
expensive();
|
||||||
|
}
|
||||||
|
function expensive() public{
|
||||||
|
for (uint256 i = 0; i < 100; i++) {
|
||||||
|
data.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getDataLength() public view returns (uint256) {
|
||||||
|
return data.length;
|
||||||
|
}
|
||||||
|
}
|
1
itests/contracts/GasSendTest.hex
Normal file
1
itests/contracts/GasSendTest.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80630c55699c14602d575b600080fd5b60336047565b604051603e91906067565b60405180910390f35b60006007905090565b6000819050919050565b6061816050565b82525050565b6000602082019050607a6000830184605a565b9291505056fea2646970667358221220c0f2da1b01178b54afba1ddf14f30307a03cdb66f61b4e1dc342079561db009064736f6c63430008110033
|
9
itests/contracts/GasSendTest.sol
Normal file
9
itests/contracts/GasSendTest.sol
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.17;
|
||||||
|
|
||||||
|
contract GasLimitTestReceiver {
|
||||||
|
function x() public returns (uint256){
|
||||||
|
return 7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1
itests/contracts/NotPayable.hex
Normal file
1
itests/contracts/NotPayable.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
6080604052348015600f57600080fd5b50604780601d6000396000f3fe6080604052348015600f57600080fd5b00fea26469706673582212200cd38951eddebe3692dc8921afb65a04fbe64e10d5e261806330156459bf227264736f6c63430008110033
|
7
itests/contracts/NotPayable.sol
Normal file
7
itests/contracts/NotPayable.sol
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.8.17;
|
||||||
|
|
||||||
|
//sending eth should fall because fallback is not payable
|
||||||
|
contract NotPayable {
|
||||||
|
fallback() external {}
|
||||||
|
}
|
1
itests/contracts/Recursive.hex
Normal file
1
itests/contracts/Recursive.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b506102d9806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c8063032cec451461005c57806372536f3c1461007a57806399fdb86e14610098578063d2aac3ea146100b6578063ec49254c146100d4575b600080fd5b610064610104565b60405161007191906101c7565b60405180910390f35b610082610115565b60405161008f91906101c7565b60405180910390f35b6100a0610126565b6040516100ad91906101c7565b60405180910390f35b6100be610137565b6040516100cb91906101c7565b60405180910390f35b6100ee60048036038101906100e99190610213565b610148565b6040516100fb91906101c7565b60405180910390f35b60006101106001610148565b905090565b6000610121600a610148565b905090565b60006101326002610148565b905090565b60006101436000610148565b905090565b6000808211156101a5577f3110e0ccd510fcbb471c933ad12161c459e8735b5bde2eea61a659c2e2f0a3cc8260405161018191906101c7565b60405180910390a161019e600183610199919061026f565b610148565b90506101a9565b8190505b919050565b6000819050919050565b6101c1816101ae565b82525050565b60006020820190506101dc60008301846101b8565b92915050565b600080fd5b6101f0816101ae565b81146101fb57600080fd5b50565b60008135905061020d816101e7565b92915050565b600060208284031215610229576102286101e2565b5b6000610237848285016101fe565b91505092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061027a826101ae565b9150610285836101ae565b925082820390508181111561029d5761029c610240565b5b9291505056fea26469706673582212206178e15eb87e2f766b94ec09a6a860878c93d72a31de225e1684da1755f917c764736f6c63430008110033
|
26
itests/contracts/Recursive.sol
Normal file
26
itests/contracts/Recursive.sol
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.17;
|
||||||
|
|
||||||
|
contract Recursive {
|
||||||
|
event RecursiveCallEvent(uint256 count);
|
||||||
|
|
||||||
|
function recursive10() public returns (uint256){
|
||||||
|
return recursiveCall(10);
|
||||||
|
}
|
||||||
|
function recursive2() public returns (uint256){
|
||||||
|
return recursiveCall(2);
|
||||||
|
}
|
||||||
|
function recursive1() public returns (uint256){
|
||||||
|
return recursiveCall(1);
|
||||||
|
}
|
||||||
|
function recursive0() public returns (uint256){
|
||||||
|
return recursiveCall(0);
|
||||||
|
}
|
||||||
|
function recursiveCall(uint256 count) public returns (uint256) {
|
||||||
|
if (count > 0) {
|
||||||
|
emit RecursiveCallEvent(count);
|
||||||
|
return recursiveCall(count-1);
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
1
itests/contracts/RecursiveDelegeatecall.hex
Normal file
1
itests/contracts/RecursiveDelegeatecall.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b50610459806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80633af3f24f1461003b578063ec49254c14610059575b600080fd5b610043610089565b6040516100509190610221565b60405180910390f35b610073600480360381019061006e919061026d565b61008f565b6040516100809190610221565b60405180910390f35b60005481565b60007faab69767807d0ab32f0099452739da31b76ecd3e8694bb49898829c8bf9d063582306040516100c29291906102db565b60405180910390a160016000808282546100dc9190610333565b9250508190555060018211156101ff576001826100f99190610367565b91506000803073ffffffffffffffffffffffffffffffffffffffff16846040516024016101269190610221565b6040516020818303038152906040527fec49254c000000000000000000000000000000000000000000000000000000007bffffffffffffffffffffffffffffffffffffffffffffffffffffffff19166020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff83818316178352505050506040516101b0919061040c565b600060405180830381855af49150503d80600081146101eb576040519150601f19603f3d011682016040523d82523d6000602084013e6101f0565b606091505b50915091508392505050610203565b8190505b919050565b6000819050919050565b61021b81610208565b82525050565b60006020820190506102366000830184610212565b92915050565b600080fd5b61024a81610208565b811461025557600080fd5b50565b60008135905061026781610241565b92915050565b6000602082840312156102835761028261023c565b5b600061029184828501610258565b91505092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102c58261029a565b9050919050565b6102d5816102ba565b82525050565b60006040820190506102f06000830185610212565b6102fd60208301846102cc565b9392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061033e82610208565b915061034983610208565b925082820190508082111561036157610360610304565b5b92915050565b600061037282610208565b915061037d83610208565b925082820390508181111561039557610394610304565b5b92915050565b600081519050919050565b600081905092915050565b60005b838110156103cf5780820151818401526020810190506103b4565b60008484015250505050565b60006103e68261039b565b6103f081856103a6565b93506104008185602086016103b1565b80840191505092915050565b600061041882846103db565b91508190509291505056fea2646970667358221220e70fbbfaccd3fbb084623d6d06895fba1abc5fefc181215b56ab1e43db79c7fb64736f6c63430008110033
|
21
itests/contracts/RecursiveDelegeatecall.sol
Normal file
21
itests/contracts/RecursiveDelegeatecall.sol
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.8.17;
|
||||||
|
|
||||||
|
contract RecursiveDelegatecall {
|
||||||
|
event RecursiveCallEvent(uint256 count, address self);
|
||||||
|
uint256 public totalCalls;
|
||||||
|
|
||||||
|
function recursiveCall(uint256 count) public returns (uint256) {
|
||||||
|
emit RecursiveCallEvent(count, address(this));
|
||||||
|
totalCalls += 1;
|
||||||
|
if (count > 1) {
|
||||||
|
count -= 1;
|
||||||
|
(bool success, bytes memory returnedData) = address(this)
|
||||||
|
.delegatecall(
|
||||||
|
abi.encodeWithSignature("recursiveCall(uint256)", count)
|
||||||
|
);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
1
itests/contracts/SelfDestruct.hex
Normal file
1
itests/contracts/SelfDestruct.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
6080604052348015600f57600080fd5b5060848061001e6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806383197ef014602d575b600080fd5b60336035565b005b3373ffffffffffffffffffffffffffffffffffffffff16fffea2646970667358221220d4aa109d42268586e7ce4f0fafb0ebbd04c412c6c7e8c387b009a08ecdff864264736f6c63430008110033
|
8
itests/contracts/SelfDestruct.sol
Normal file
8
itests/contracts/SelfDestruct.sol
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.8.17;
|
||||||
|
|
||||||
|
contract SelfDestruct {
|
||||||
|
function destroy() public {
|
||||||
|
selfdestruct(payable(msg.sender));
|
||||||
|
}
|
||||||
|
}
|
1
itests/contracts/TestApp.hex
Normal file
1
itests/contracts/TestApp.hex
Normal file
File diff suppressed because one or more lines are too long
211
itests/contracts/TestApp.sol
Normal file
211
itests/contracts/TestApp.sol
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.2;
|
||||||
|
pragma experimental ABIEncoderV2;
|
||||||
|
|
||||||
|
contract Test_contract {
|
||||||
|
uint256 timestamp;
|
||||||
|
address sender;
|
||||||
|
string text;
|
||||||
|
uint256 number;
|
||||||
|
|
||||||
|
constructor(string memory _text, uint256 _number) {
|
||||||
|
sender = tx.origin;
|
||||||
|
timestamp = block.timestamp;
|
||||||
|
text = _text;
|
||||||
|
number = _number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getall()
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
address,
|
||||||
|
uint256,
|
||||||
|
address,
|
||||||
|
string memory,
|
||||||
|
uint256
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return (address(this), timestamp, sender, text, number);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_timestamp() public view returns (uint256) {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_sender() public view returns (address) {
|
||||||
|
return sender;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_text() public view returns (string memory) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_number() public view returns (uint256) {
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract App {
|
||||||
|
address[] Test_list;
|
||||||
|
uint256 Test_list_length;
|
||||||
|
|
||||||
|
function get_Test_list_length() public view returns (uint256) {
|
||||||
|
return Test_list_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Test_getter {
|
||||||
|
address _address;
|
||||||
|
uint256 timestamp;
|
||||||
|
address sender;
|
||||||
|
string text;
|
||||||
|
uint256 number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_Test_N(uint256 index)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
address,
|
||||||
|
uint256,
|
||||||
|
address,
|
||||||
|
string memory,
|
||||||
|
uint256
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return Test_contract(Test_list[index]).getall();
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_first_Test_N(uint256 count, uint256 offset)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (Test_getter[] memory)
|
||||||
|
{
|
||||||
|
Test_getter[] memory getters = new Test_getter[](count);
|
||||||
|
for (uint256 i = offset; i < count; i++) {
|
||||||
|
Test_contract myTest = Test_contract(Test_list[i + offset]);
|
||||||
|
getters[i - offset]._address = address(myTest);
|
||||||
|
getters[i - offset].timestamp = myTest.get_timestamp();
|
||||||
|
getters[i - offset].sender = myTest.get_sender();
|
||||||
|
getters[i - offset].text = myTest.get_text();
|
||||||
|
getters[i - offset].number = myTest.get_number();
|
||||||
|
}
|
||||||
|
return getters;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_last_Test_N(uint256 count, uint256 offset)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (Test_getter[] memory)
|
||||||
|
{
|
||||||
|
Test_getter[] memory getters = new Test_getter[](count);
|
||||||
|
for (uint256 i = 0; i < count; i++) {
|
||||||
|
Test_contract myTest =
|
||||||
|
Test_contract(Test_list[Test_list_length - i - offset - 1]);
|
||||||
|
getters[i]._address = address(myTest);
|
||||||
|
|
||||||
|
getters[i].timestamp = myTest.get_timestamp();
|
||||||
|
getters[i].sender = myTest.get_sender();
|
||||||
|
getters[i].text = myTest.get_text();
|
||||||
|
getters[i].number = myTest.get_number();
|
||||||
|
}
|
||||||
|
return getters;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_Test_user_length(address user) public view returns (uint256) {
|
||||||
|
return user_map[user].Test_list_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_Test_user_N(address user, uint256 index)
|
||||||
|
public
|
||||||
|
view
|
||||||
|
returns (
|
||||||
|
address,
|
||||||
|
uint256,
|
||||||
|
address,
|
||||||
|
string memory,
|
||||||
|
uint256
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return Test_contract(user_map[user].Test_list[index]).getall();
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_last_Test_user_N(
|
||||||
|
address user,
|
||||||
|
uint256 count,
|
||||||
|
uint256 offset
|
||||||
|
) public view returns (Test_getter[] memory) {
|
||||||
|
Test_getter[] memory getters = new Test_getter[](count);
|
||||||
|
|
||||||
|
for (uint256 i = offset; i < count; i++) {
|
||||||
|
getters[i - offset]._address = user_map[user].Test_list[i + offset];
|
||||||
|
getters[i - offset].timestamp = Test_contract(
|
||||||
|
user_map[user].Test_list[i + offset]
|
||||||
|
)
|
||||||
|
.get_timestamp();
|
||||||
|
getters[i - offset].sender = Test_contract(
|
||||||
|
user_map[user].Test_list[i + offset]
|
||||||
|
)
|
||||||
|
.get_sender();
|
||||||
|
getters[i - offset].text = Test_contract(
|
||||||
|
user_map[user].Test_list[i + offset]
|
||||||
|
)
|
||||||
|
.get_text();
|
||||||
|
getters[i - offset].number = Test_contract(
|
||||||
|
user_map[user].Test_list[i + offset]
|
||||||
|
)
|
||||||
|
.get_number();
|
||||||
|
}
|
||||||
|
return getters;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct UserInfo {
|
||||||
|
address owner;
|
||||||
|
bool exists;
|
||||||
|
address[] Test_list;
|
||||||
|
uint256 Test_list_length;
|
||||||
|
}
|
||||||
|
mapping(address => UserInfo) public user_map;
|
||||||
|
address[] UserInfoList;
|
||||||
|
uint256 UserInfoListLength;
|
||||||
|
|
||||||
|
event NewTest(address sender);
|
||||||
|
|
||||||
|
function new_Test(string memory text, uint256 number)
|
||||||
|
public
|
||||||
|
returns (address)
|
||||||
|
{
|
||||||
|
address mynew =
|
||||||
|
address(new Test_contract({_text: text, _number: number}));
|
||||||
|
|
||||||
|
if (!user_map[tx.origin].exists) {
|
||||||
|
user_map[tx.origin] = create_user_on_new_Test(mynew);
|
||||||
|
}
|
||||||
|
user_map[tx.origin].Test_list.push(mynew);
|
||||||
|
|
||||||
|
user_map[tx.origin].Test_list_length += 1;
|
||||||
|
|
||||||
|
Test_list.push(mynew);
|
||||||
|
Test_list_length += 1;
|
||||||
|
|
||||||
|
emit NewTest(tx.origin);
|
||||||
|
|
||||||
|
return mynew;
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_user_on_new_Test(address addr)
|
||||||
|
private
|
||||||
|
returns (UserInfo memory)
|
||||||
|
{
|
||||||
|
address[] memory Test_list_;
|
||||||
|
|
||||||
|
UserInfoList.push(addr);
|
||||||
|
return
|
||||||
|
UserInfo({
|
||||||
|
exists: true,
|
||||||
|
owner: addr,
|
||||||
|
Test_list: Test_list_,
|
||||||
|
Test_list_length: 0
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
1
itests/contracts/ValueSender.hex
Normal file
1
itests/contracts/ValueSender.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b506106dc806100206000396000f3fe60806040526004361061002d5760003560e01c8063dbdc275d14610072578063fd75295a1461009d5761006d565b3661006d577f34fb9cb8f63eaccc6c0beefc202db703e529c3bf9ce83f485b398af7fd679308333460405161006392919061020f565b60405180910390a1005b600080fd5b34801561007e57600080fd5b506100876100b9565b6040516100949190610238565b60405180910390f35b6100b760048036038101906100b29190610296565b610125565b005b6000806040516100c8906101a8565b604051809103906000f0801580156100e4573d6000803e3d6000fd5b5090507f8db3b20eed31d927a4f613b5c11765212e129cf726d025649650665569ea683b816040516101169190610238565b60405180910390a18091505090565b7f34fb9cb8f63eaccc6c0beefc202db703e529c3bf9ce83f485b398af7fd6793088134604051610156929190610322565b60405180910390a18073ffffffffffffffffffffffffffffffffffffffff166108fc349081150290604051600060405180830381858888f193505050501580156101a4573d6000803e3d6000fd5b5050565b61035b8061034c83390190565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101e0826101b5565b9050919050565b6101f0816101d5565b82525050565b6000819050919050565b610209816101f6565b82525050565b600060408201905061022460008301856101e7565b6102316020830184610200565b9392505050565b600060208201905061024d60008301846101e7565b92915050565b600080fd5b6000610263826101b5565b9050919050565b61027381610258565b811461027e57600080fd5b50565b6000813590506102908161026a565b92915050565b6000602082840312156102ac576102ab610253565b5b60006102ba84828501610281565b91505092915050565b6000819050919050565b60006102e86102e36102de846101b5565b6102c3565b6101b5565b9050919050565b60006102fa826102cd565b9050919050565b600061030c826102ef565b9050919050565b61031c81610301565b82525050565b60006040820190506103376000830185610313565b6103446020830184610200565b939250505056fe608060405234801561001057600080fd5b50336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506102fb806100606000396000f3fe60806040526004361061002d5760003560e01c806337cb6570146100725780639cb8a26a1461007c5761006d565b3661006d577fe1494f56a1ccfd8c7361f2ca5b8fd2b1a2fe11773821ac29534f09f4a0637d603334604051610063929190610214565b60405180910390a1005b600080fd5b61007a610093565b005b34801561008857600080fd5b50610091610155565b005b7f76cff203b0794a9e9013657ecb172f2d6e8de5941fd11a6bfbc0fb6014a5f07960008054906101000a900473ffffffffffffffffffffffffffffffffffffffff16476040516100e492919061029c565b60405180910390a160008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166108fc479081150290604051600060405180830381858888f19350505050158015610152573d6000803e3d6000fd5b50565b7f1cbd47e7b0f55dc1a45ba8ebada53eaa1712b3e3e86f49a12c008ff22334569060405160405180910390a160008054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006101e5826101ba565b9050919050565b6101f5816101da565b82525050565b6000819050919050565b61020e816101fb565b82525050565b600060408201905061022960008301856101ec565b6102366020830184610205565b9392505050565b6000819050919050565b600061026261025d610258846101ba565b61023d565b6101ba565b9050919050565b600061027482610247565b9050919050565b600061028682610269565b9050919050565b6102968161027b565b82525050565b60006040820190506102b1600083018561028d565b6102be6020830184610205565b939250505056fea2646970667358221220bdf21908b1c91973a8440fe81130e0077cf83c8f8e9a053d8a0c3063391aa40764736f6c63430008110033a26469706673582212202e514fe078dfcf4f1142a088c57cfa71ada74d72ee0cc4a46b7e1141cdbaeeed64736f6c63430008110033
|
54
itests/contracts/ValueSender.sol
Normal file
54
itests/contracts/ValueSender.sol
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.8.17;
|
||||||
|
|
||||||
|
contract A {
|
||||||
|
event LogCreateB(address _bAddress);
|
||||||
|
event LogSendEthA(address _bAddress, uint _value);
|
||||||
|
event LogReceiveEthA(address _bAddress, uint _value);
|
||||||
|
|
||||||
|
// Function to create a new instance of contract B and return its address
|
||||||
|
function createB() public returns (address) {
|
||||||
|
address bAddress = address(new B());
|
||||||
|
emit LogCreateB(bAddress);
|
||||||
|
return bAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Payable method to accept eth and an address for B and send the eth to B
|
||||||
|
function sendEthToB(address payable _bAddress) public payable {
|
||||||
|
emit LogSendEthA(_bAddress, msg.value);
|
||||||
|
_bAddress.transfer(msg.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Payable function to accept the eth
|
||||||
|
receive() external payable {
|
||||||
|
emit LogSendEthA(msg.sender, msg.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract B {
|
||||||
|
event LogSelfDestruct();
|
||||||
|
event LogSendEthToA(address _to, uint _value);
|
||||||
|
event LogReceiveEth(address from, uint value);
|
||||||
|
address payable creator;
|
||||||
|
|
||||||
|
constructor(){
|
||||||
|
creator = payable(msg.sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Payable function to accept the eth
|
||||||
|
receive() external payable {
|
||||||
|
emit LogReceiveEth(msg.sender, msg.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method to send ether to contract A
|
||||||
|
function sendEthToA() public payable {
|
||||||
|
emit LogSendEthToA(creator,address(this).balance);
|
||||||
|
creator.transfer(address(this).balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Self destruct method to send eth to its creator
|
||||||
|
function selfDestruct() public {
|
||||||
|
emit LogSelfDestruct();
|
||||||
|
selfdestruct(creator);
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,19 @@
|
|||||||
|
set -eu
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
#use the solc compiler https://docs.soliditylang.org/en/v0.8.17/installing-solidity.html
|
#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
|
# 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
|
# 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 |
|
find . -name \*.sol -print0 |
|
||||||
xargs -0 -I{} bash -c 'solc --bin {} |tail -n1 | tr -d "\n" > $(echo {} | sed -e s/.sol$/.hex/)'
|
xargs -0 -I{} bash -euc -o pipefail 'solc --bin {} |tail -n1 | tr -d "\n" > $(echo {} | sed -e s/.sol$/.hex/)'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#for these contracts we have 2 contracts in the same solidity file
|
||||||
|
#this command grabs the correct bytecode for us
|
||||||
|
for filename in Constructor TestApp ValueSender ; do
|
||||||
|
echo $filename
|
||||||
|
solc --bin $filename.sol | tail -n5|head -n1 | tr -d "\n" > $filename.hex
|
||||||
|
done
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ func TestEthAccountAbstraction(t *testing.T) {
|
|||||||
msgFromPlaceholder, err = client.GasEstimateMessageGas(ctx, msgFromPlaceholder, nil, types.EmptyTSK)
|
msgFromPlaceholder, err = client.GasEstimateMessageGas(ctx, msgFromPlaceholder, nil, types.EmptyTSK)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
txArgs, err := ethtypes.EthTxArgsFromMessage(msgFromPlaceholder)
|
txArgs, err := ethtypes.EthTxArgsFromUnsignedEthMessage(msgFromPlaceholder)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
digest, err := txArgs.ToRlpUnsignedMsg()
|
digest, err := txArgs.ToRlpUnsignedMsg()
|
||||||
@ -108,7 +108,7 @@ func TestEthAccountAbstraction(t *testing.T) {
|
|||||||
msgFromPlaceholder, err = client.GasEstimateMessageGas(ctx, msgFromPlaceholder, nil, types.EmptyTSK)
|
msgFromPlaceholder, err = client.GasEstimateMessageGas(ctx, msgFromPlaceholder, nil, types.EmptyTSK)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
txArgs, err = ethtypes.EthTxArgsFromMessage(msgFromPlaceholder)
|
txArgs, err = ethtypes.EthTxArgsFromUnsignedEthMessage(msgFromPlaceholder)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
digest, err = txArgs.ToRlpUnsignedMsg()
|
digest, err = txArgs.ToRlpUnsignedMsg()
|
||||||
@ -180,7 +180,7 @@ func TestEthAccountAbstractionFailure(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
msgFromPlaceholder.Value = abi.TokenAmount(types.MustParseFIL("1000"))
|
msgFromPlaceholder.Value = abi.TokenAmount(types.MustParseFIL("1000"))
|
||||||
txArgs, err := ethtypes.EthTxArgsFromMessage(msgFromPlaceholder)
|
txArgs, err := ethtypes.EthTxArgsFromUnsignedEthMessage(msgFromPlaceholder)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
digest, err := txArgs.ToRlpUnsignedMsg()
|
digest, err := txArgs.ToRlpUnsignedMsg()
|
||||||
@ -218,7 +218,7 @@ func TestEthAccountAbstractionFailure(t *testing.T) {
|
|||||||
msgFromPlaceholder, err = client.GasEstimateMessageGas(ctx, msgFromPlaceholder, nil, types.EmptyTSK)
|
msgFromPlaceholder, err = client.GasEstimateMessageGas(ctx, msgFromPlaceholder, nil, types.EmptyTSK)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
txArgs, err = ethtypes.EthTxArgsFromMessage(msgFromPlaceholder)
|
txArgs, err = ethtypes.EthTxArgsFromUnsignedEthMessage(msgFromPlaceholder)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
digest, err = txArgs.ToRlpUnsignedMsg()
|
digest, err = txArgs.ToRlpUnsignedMsg()
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
@ -19,6 +20,7 @@ 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-jsonrpc"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
|
||||||
@ -27,6 +29,7 @@ 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"
|
||||||
|
res "github.com/filecoin-project/lotus/lib/result"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEthNewPendingTransactionFilter(t *testing.T) {
|
func TestEthNewPendingTransactionFilter(t *testing.T) {
|
||||||
@ -389,15 +392,15 @@ func TestEthSubscribeLogsNoTopicSpec(t *testing.T) {
|
|||||||
t.Logf("actor ID address is %s", idAddr)
|
t.Logf("actor ID address is %s", idAddr)
|
||||||
|
|
||||||
// install filter
|
// install filter
|
||||||
respCh, err := client.EthSubscribe(ctx, "logs", nil)
|
subId, err := client.EthSubscribe(ctx, res.Wrap[jsonrpc.RawParams](json.Marshal(ethtypes.EthSubscribeParams{EventType: "logs"})).Assert(require.NoError))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
subResponses := []ethtypes.EthSubscriptionResponse{}
|
var subResponses []ethtypes.EthSubscriptionResponse
|
||||||
go func() {
|
err = client.EthSubRouter.AddSub(ctx, subId, func(ctx context.Context, resp *ethtypes.EthSubscriptionResponse) error {
|
||||||
for resp := range respCh {
|
subResponses = append(subResponses, *resp)
|
||||||
subResponses = append(subResponses, resp)
|
return nil
|
||||||
}
|
})
|
||||||
}()
|
require.NoError(err)
|
||||||
|
|
||||||
const iterations = 10
|
const iterations = 10
|
||||||
ethContractAddr, messages := invokeLogFourData(t, client, iterations)
|
ethContractAddr, messages := invokeLogFourData(t, client, iterations)
|
||||||
@ -518,44 +521,33 @@ func TestEthSubscribeLogs(t *testing.T) {
|
|||||||
|
|
||||||
testResponses := map[string]chan ethtypes.EthSubscriptionResponse{}
|
testResponses := map[string]chan ethtypes.EthSubscriptionResponse{}
|
||||||
|
|
||||||
// quit is used to signal that we're ready to start testing collected results
|
|
||||||
quit := make(chan struct{})
|
|
||||||
|
|
||||||
// Create all the filters
|
// Create all the filters
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
|
||||||
// subscribe to topics in filter
|
// subscribe to topics in filter
|
||||||
subCh, err := client.EthSubscribe(ctx, "logs", ðtypes.EthSubscriptionParams{Topics: tc.spec.Topics})
|
subParam, err := json.Marshal(ethtypes.EthSubscribeParams{
|
||||||
|
EventType: "logs",
|
||||||
|
Params: ðtypes.EthSubscriptionParams{Topics: tc.spec.Topics},
|
||||||
|
})
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
|
subId, err := client.EthSubscribe(ctx, subParam)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
|
|
||||||
responseCh := make(chan ethtypes.EthSubscriptionResponse, len(invocations))
|
responseCh := make(chan ethtypes.EthSubscriptionResponse, len(invocations))
|
||||||
testResponses[tc.name] = responseCh
|
testResponses[tc.name] = responseCh
|
||||||
|
|
||||||
// start a goroutine to forward responses from subscription to a buffered channel with guaranteed capacity
|
err = client.EthSubRouter.AddSub(ctx, subId, func(ctx context.Context, resp *ethtypes.EthSubscriptionResponse) error {
|
||||||
go func(subCh <-chan ethtypes.EthSubscriptionResponse, responseCh chan<- ethtypes.EthSubscriptionResponse, quit chan struct{}) {
|
responseCh <- *resp
|
||||||
defer func() {
|
return nil
|
||||||
close(responseCh)
|
})
|
||||||
}()
|
require.NoError(err)
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case resp := <-subCh:
|
|
||||||
responseCh <- resp
|
|
||||||
case <-quit:
|
|
||||||
return
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}(subCh, responseCh, quit)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform all the invocations
|
// Perform all the invocations
|
||||||
messages := invokeAndWaitUntilAllOnChain(t, client, invocations)
|
messages := invokeAndWaitUntilAllOnChain(t, client, invocations)
|
||||||
|
|
||||||
// wait a little for subscriptions to gather results and then tell all the goroutines to stop
|
// wait a little for subscriptions to gather results
|
||||||
time.Sleep(blockTime * 6)
|
time.Sleep(blockTime * 6)
|
||||||
close(quit)
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
tc := tc // appease the lint despot
|
tc := tc // appease the lint despot
|
||||||
@ -563,6 +555,9 @@ func TestEthSubscribeLogs(t *testing.T) {
|
|||||||
responseCh, ok := testResponses[tc.name]
|
responseCh, ok := testResponses[tc.name]
|
||||||
require.True(ok)
|
require.True(ok)
|
||||||
|
|
||||||
|
// don't expect any more responses
|
||||||
|
close(responseCh)
|
||||||
|
|
||||||
var elogs []*ethtypes.EthLog
|
var elogs []*ethtypes.EthLog
|
||||||
for resp := range responseCh {
|
for resp := range responseCh {
|
||||||
rlist, ok := resp.Result.([]interface{})
|
rlist, ok := resp.Result.([]interface{})
|
||||||
@ -1055,7 +1050,8 @@ func invokeAndWaitUntilAllOnChain(t *testing.T, client *kit.TestFullNode, invoca
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret := client.EVM().InvokeSolidity(ctx, inv.Sender, inv.Target, inv.Selector, inv.Data)
|
ret, err := client.EVM().InvokeSolidity(ctx, inv.Sender, inv.Target, inv.Selector, inv.Data)
|
||||||
|
require.NoError(err)
|
||||||
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
|
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
|
||||||
|
|
||||||
invocationMap[ret.Message] = inv
|
invocationMap[ret.Message] = inv
|
||||||
|
@ -83,6 +83,11 @@ func TestValueTransferValidSignature(t *testing.T) {
|
|||||||
|
|
||||||
// Success.
|
// Success.
|
||||||
require.EqualValues(t, ethtypes.EthUint64(0x1), receipt.Status)
|
require.EqualValues(t, ethtypes.EthUint64(0x1), receipt.Status)
|
||||||
|
|
||||||
|
ethTx, err := client.EthGetTransactionByHash(ctx, &hash)
|
||||||
|
require.Nil(t, err)
|
||||||
|
require.EqualValues(t, ethAddr, ethTx.From)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLegacyTransaction(t *testing.T) {
|
func TestLegacyTransaction(t *testing.T) {
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
@ -44,14 +43,43 @@ func effectiveEthAddressForCreate(t *testing.T, sender address.Address) ethtypes
|
|||||||
panic("unreachable")
|
panic("unreachable")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createAndDeploy(ctx context.Context, t *testing.T, client *kit.TestFullNode, fromAddr address.Address, contract []byte) *api.MsgLookup {
|
||||||
|
// Create and deploy evm actor
|
||||||
|
|
||||||
|
method := builtintypes.MethodsEAM.CreateExternal
|
||||||
|
contractParams := abi.CborBytes(contract)
|
||||||
|
params, actorsErr := actors.SerializeParams(&contractParams)
|
||||||
|
require.NoError(t, actorsErr)
|
||||||
|
|
||||||
|
createMsg := &types.Message{
|
||||||
|
To: builtintypes.EthereumAddressManagerActorAddr,
|
||||||
|
From: fromAddr,
|
||||||
|
Value: big.Zero(),
|
||||||
|
Method: method,
|
||||||
|
Params: params,
|
||||||
|
}
|
||||||
|
smsg, err := client.MpoolPushMessage(ctx, createMsg, nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
wait, err := client.StateWaitMsg(ctx, smsg.Cid(), 0, 0, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, exitcode.Ok, wait.Receipt.ExitCode)
|
||||||
|
return wait
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEthAddressTX(ctx context.Context, t *testing.T, client *kit.TestFullNode, wait *api.MsgLookup, ethAddr ethtypes.EthAddress) ethtypes.EthAddress {
|
||||||
|
// Check if eth address returned from CreateExternal is the same as eth address predicted at the start
|
||||||
|
var createExternalReturn eam.CreateExternalReturn
|
||||||
|
err := createExternalReturn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
createdEthAddr, err := ethtypes.CastEthAddress(createExternalReturn.EthAddress[:])
|
||||||
|
require.NoError(t, err)
|
||||||
|
return createdEthAddr
|
||||||
|
}
|
||||||
|
|
||||||
func TestAddressCreationBeforeDeploy(t *testing.T) {
|
func TestAddressCreationBeforeDeploy(t *testing.T) {
|
||||||
kit.QuietMiningLogs()
|
ctx, cancel, client := kit.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()
|
||||||
|
|
||||||
// install contract
|
// install contract
|
||||||
@ -72,22 +100,11 @@ func TestAddressCreationBeforeDeploy(t *testing.T) {
|
|||||||
contractFilAddr, err := ethAddr.ToFilecoinAddress()
|
contractFilAddr, err := ethAddr.ToFilecoinAddress()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Send contract address some funds
|
//transfer half the wallet balance
|
||||||
|
|
||||||
bal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
|
bal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
sendAmount := big.Div(bal, big.NewInt(2))
|
sendAmount := big.Div(bal, big.NewInt(2))
|
||||||
|
client.EVM().TransferValueOrFail(ctx, fromAddr, contractFilAddr, sendAmount)
|
||||||
sendMsg := &types.Message{
|
|
||||||
From: fromAddr,
|
|
||||||
To: contractFilAddr,
|
|
||||||
Value: sendAmount,
|
|
||||||
}
|
|
||||||
signedMsg, err := client.MpoolPushMessage(ctx, sendMsg, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
mLookup, err := client.StateWaitMsg(ctx, signedMsg.Cid(), 3, api.LookbackNoLimit, true)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, exitcode.Ok, mLookup.Receipt.ExitCode)
|
|
||||||
|
|
||||||
// Check if actor at new address is a placeholder actor
|
// Check if actor at new address is a placeholder actor
|
||||||
actor, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK)
|
actor, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK)
|
||||||
@ -95,40 +112,69 @@ func TestAddressCreationBeforeDeploy(t *testing.T) {
|
|||||||
require.True(t, builtin.IsPlaceholderActor(actor.Code))
|
require.True(t, builtin.IsPlaceholderActor(actor.Code))
|
||||||
|
|
||||||
// Create and deploy evm actor
|
// Create and deploy evm actor
|
||||||
|
wait := createAndDeploy(ctx, t, client, fromAddr, contract)
|
||||||
method := builtintypes.MethodsEAM.CreateExternal
|
|
||||||
contractParams := abi.CborBytes(contract)
|
|
||||||
params, err := actors.SerializeParams(&contractParams)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
createMsg := &types.Message{
|
|
||||||
To: builtintypes.EthereumAddressManagerActorAddr,
|
|
||||||
From: fromAddr,
|
|
||||||
Value: big.Zero(),
|
|
||||||
Method: method,
|
|
||||||
Params: params,
|
|
||||||
}
|
|
||||||
smsg, err := client.MpoolPushMessage(ctx, createMsg, nil)
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
wait, err := client.StateWaitMsg(ctx, smsg.Cid(), 0, 0, false)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, exitcode.Ok, wait.Receipt.ExitCode)
|
|
||||||
|
|
||||||
// Check if eth address returned from CreateExternal is the same as eth address predicted at the start
|
// Check if eth address returned from CreateExternal is the same as eth address predicted at the start
|
||||||
var createExternalReturn eam.CreateExternalReturn
|
createdEthAddr := getEthAddressTX(ctx, t, client, wait, ethAddr)
|
||||||
err = createExternalReturn.UnmarshalCBOR(bytes.NewReader(wait.Receipt.Return))
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
createdEthAddr, err := ethtypes.CastEthAddress(createExternalReturn.EthAddress[:])
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, ethAddr, createdEthAddr)
|
require.Equal(t, ethAddr, createdEthAddr)
|
||||||
|
|
||||||
// Check if newly deployed actor still has funds
|
// Check if newly deployed actor still has funds
|
||||||
actorPostCreate, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK)
|
actorPostCreate, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
require.Equal(t, actorPostCreate.Balance, sendAmount)
|
require.Equal(t, actorPostCreate.Balance, sendAmount)
|
||||||
require.True(t, builtin.IsEvmActor(actorPostCreate.Code))
|
require.True(t, builtin.IsEvmActor(actorPostCreate.Code))
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeployAddressMultipleTimes(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
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)
|
||||||
|
|
||||||
|
fromAddr, err := client.WalletDefaultAddress(ctx)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// We hash the f1/f3 address into the EVM's address space when deploying contracts from
|
||||||
|
// accounts.
|
||||||
|
effectiveEvmAddress := effectiveEthAddressForCreate(t, fromAddr)
|
||||||
|
ethAddr := client.EVM().ComputeContractAddress(effectiveEvmAddress, 1)
|
||||||
|
|
||||||
|
contractFilAddr, err := ethAddr.ToFilecoinAddress()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// Send contract address small funds to init
|
||||||
|
sendAmount := big.NewInt(2)
|
||||||
|
client.EVM().TransferValueOrFail(ctx, fromAddr, contractFilAddr, sendAmount)
|
||||||
|
|
||||||
|
// Check if actor at new address is a placeholder actor
|
||||||
|
actor, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, builtin.IsPlaceholderActor(actor.Code))
|
||||||
|
|
||||||
|
// Create and deploy evm actor
|
||||||
|
wait := createAndDeploy(ctx, t, client, fromAddr, contract)
|
||||||
|
|
||||||
|
// Check if eth address returned from CreateExternal is the same as eth address predicted at the start
|
||||||
|
createdEthAddr := getEthAddressTX(ctx, t, client, wait, ethAddr)
|
||||||
|
require.Equal(t, ethAddr, createdEthAddr)
|
||||||
|
|
||||||
|
// Check if newly deployed actor still has funds
|
||||||
|
actorPostCreate, err := client.StateGetActor(ctx, contractFilAddr, types.EmptyTSK)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, actorPostCreate.Balance, sendAmount)
|
||||||
|
require.True(t, builtin.IsEvmActor(actorPostCreate.Code))
|
||||||
|
|
||||||
|
// Create and deploy evm actor
|
||||||
|
wait = createAndDeploy(ctx, t, client, fromAddr, contract)
|
||||||
|
|
||||||
|
// Check that this time eth address returned from CreateExternal is not the same as eth address predicted at the start
|
||||||
|
createdEthAddr = getEthAddressTX(ctx, t, client, wait, ethAddr)
|
||||||
|
require.NotEqual(t, ethAddr, createdEthAddr)
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -64,20 +64,23 @@ func TestFEVMEvents(t *testing.T) {
|
|||||||
require.Empty(res.Results)
|
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, err := client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x00}, nil)
|
||||||
|
require.NoError(err)
|
||||||
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
|
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
|
||||||
require.NotNil(ret.Receipt.EventsRoot)
|
require.NotNil(ret.Receipt.EventsRoot)
|
||||||
fmt.Println(ret)
|
fmt.Println(ret)
|
||||||
fmt.Printf("Events:\n %+v\n", client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot))
|
fmt.Printf("Events:\n %+v\n", client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot))
|
||||||
|
|
||||||
// log a zero topic event with no data
|
// log a zero topic event with no data
|
||||||
ret = client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x01}, nil)
|
ret, err = client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x01}, nil)
|
||||||
|
require.NoError(err)
|
||||||
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
|
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
|
||||||
fmt.Println(ret)
|
fmt.Println(ret)
|
||||||
fmt.Printf("Events:\n %+v\n", client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot))
|
fmt.Printf("Events:\n %+v\n", client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot))
|
||||||
|
|
||||||
// log a four topic event with data
|
// log a four topic event with data
|
||||||
ret = client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x02}, nil)
|
ret, err = client.EVM().InvokeSolidity(ctx, fromAddr, idAddr, []byte{0x00, 0x00, 0x00, 0x02}, nil)
|
||||||
|
require.NoError(err)
|
||||||
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
|
require.True(ret.Receipt.ExitCode.IsSuccess(), "contract execution failed")
|
||||||
fmt.Println(ret)
|
fmt.Println(ret)
|
||||||
fmt.Printf("Events:\n %+v\n", client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot))
|
fmt.Printf("Events:\n %+v\n", client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot))
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
package itests
|
package itests
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
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/exitcode"
|
"github.com/filecoin-project/go-state-types/exitcode"
|
||||||
"github.com/filecoin-project/go-state-types/manifest"
|
"github.com/filecoin-project/go-state-types/manifest"
|
||||||
@ -38,19 +40,139 @@ func inputDataFromFrom(ctx context.Context, t *testing.T, client *kit.TestFullNo
|
|||||||
return inputData
|
return inputData
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupFEVMTest(t *testing.T) (context.Context, context.CancelFunc, *kit.TestFullNode) {
|
func decodeOutputToUint64(output []byte) (uint64, error) {
|
||||||
kit.QuietMiningLogs()
|
var result uint64
|
||||||
blockTime := 5 * time.Millisecond
|
buf := bytes.NewReader(output[len(output)-8:])
|
||||||
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC())
|
err := binary.Read(buf, binary.BigEndian, &result)
|
||||||
ens.InterconnectAll().BeginMiningMustPost(blockTime)
|
return result, err
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
}
|
||||||
return ctx, cancel, client
|
func buildInputFromuint64(number uint64) []byte {
|
||||||
|
// Convert the number to a binary uint64 array
|
||||||
|
binaryNumber := make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint64(binaryNumber, number)
|
||||||
|
return inputDataFromArray(binaryNumber)
|
||||||
|
}
|
||||||
|
|
||||||
|
// recursive delegate calls that fail due to gas limits are currently getting to 229 iterations
|
||||||
|
// before running out of gas
|
||||||
|
func recursiveDelegatecallFail(ctx context.Context, t *testing.T, client *kit.TestFullNode, filename string, count uint64) {
|
||||||
|
expectedIterationsBeforeFailing := int(229)
|
||||||
|
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
|
||||||
|
t.Log("recursion count - ", count)
|
||||||
|
inputData := buildInputFromuint64(count)
|
||||||
|
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", inputData)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "totalCalls()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
resultUint, err := decodeOutputToUint64(result)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.NotEqual(t, int(resultUint), int(count))
|
||||||
|
require.Equal(t, expectedIterationsBeforeFailing, int(resultUint))
|
||||||
|
}
|
||||||
|
func recursiveDelegatecallSuccess(ctx context.Context, t *testing.T, client *kit.TestFullNode, filename string, count uint64) {
|
||||||
|
t.Log("Count - ", count)
|
||||||
|
|
||||||
|
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
|
||||||
|
inputData := buildInputFromuint64(count)
|
||||||
|
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", inputData)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "totalCalls()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
resultUint, err := decodeOutputToUint64(result)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, int(count), int(resultUint))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFEVMRecursive does a basic fevm contract installation and invocation
|
||||||
|
func TestFEVMRecursive(t *testing.T) {
|
||||||
|
callCounts := []uint64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 100, 230, 330}
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
filename := "contracts/Recursive.hex"
|
||||||
|
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
|
||||||
|
|
||||||
|
// Successful calls
|
||||||
|
for _, callCount := range callCounts {
|
||||||
|
callCount := callCount // linter unhappy unless callCount is local to loop
|
||||||
|
t.Run(fmt.Sprintf("TestFEVMRecursive%d", callCount), func(t *testing.T) {
|
||||||
|
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", buildInputFromuint64(callCount))
|
||||||
|
require.NoError(t, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFEVMRecursiveFail(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
filename := "contracts/Recursive.hex"
|
||||||
|
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
|
||||||
|
|
||||||
|
// Unsuccessful calls
|
||||||
|
failCallCounts := []uint64{340, 400, 600, 850, 1000}
|
||||||
|
for _, failCallCount := range failCallCounts {
|
||||||
|
failCallCount := failCallCount // linter unhappy unless callCount is local to loop
|
||||||
|
t.Run(fmt.Sprintf("TestFEVMRecursiveFail%d", failCallCount), func(t *testing.T) {
|
||||||
|
_, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursiveCall(uint256)", buildInputFromuint64(failCallCount))
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Equal(t, exitcode.ExitCode(23), wait.Receipt.ExitCode)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFEVMRecursive1(t *testing.T) {
|
||||||
|
callCount := 1
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
filename := "contracts/Recursive.hex"
|
||||||
|
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
|
||||||
|
_, ret, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursive1()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
events := client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot)
|
||||||
|
require.Equal(t, callCount, len(events))
|
||||||
|
}
|
||||||
|
func TestFEVMRecursive2(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
filename := "contracts/Recursive.hex"
|
||||||
|
fromAddr, idAddr := client.EVM().DeployContractFromFilename(ctx, filename)
|
||||||
|
_, ret, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "recursive2()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
events := client.EVM().LoadEvents(ctx, *ret.Receipt.EventsRoot)
|
||||||
|
require.Equal(t, 2, len(events))
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFEVMBasic does a basic fevm contract installation and invocation
|
||||||
|
// recursive delegate call succeeds up to 238 times
|
||||||
|
func TestFEVMRecursiveDelegatecall(t *testing.T) {
|
||||||
|
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
filename := "contracts/RecursiveDelegeatecall.hex"
|
||||||
|
|
||||||
|
//success with 238 or fewer calls
|
||||||
|
for i := uint64(1); i <= 238; i += 30 {
|
||||||
|
recursiveDelegatecallSuccess(ctx, t, client, filename, i)
|
||||||
|
}
|
||||||
|
recursiveDelegatecallSuccess(ctx, t, client, filename, uint64(238))
|
||||||
|
|
||||||
|
for i := uint64(239); i <= 800; i += 40 {
|
||||||
|
recursiveDelegatecallFail(ctx, t, client, filename, i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestFEVMBasic does a basic fevm contract installation and invocation
|
// TestFEVMBasic does a basic fevm contract installation and invocation
|
||||||
func TestFEVMBasic(t *testing.T) {
|
func TestFEVMBasic(t *testing.T) {
|
||||||
|
|
||||||
ctx, cancel, client := setupFEVMTest(t)
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
filename := "contracts/SimpleCoin.hex"
|
filename := "contracts/SimpleCoin.hex"
|
||||||
@ -60,7 +182,8 @@ func TestFEVMBasic(t *testing.T) {
|
|||||||
// invoke the contract with owner
|
// invoke the contract with owner
|
||||||
{
|
{
|
||||||
inputData := inputDataFromFrom(ctx, t, client, fromAddr)
|
inputData := inputDataFromFrom(ctx, t, client, fromAddr)
|
||||||
result := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData)
|
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000002710")
|
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000002710")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -70,8 +193,9 @@ func TestFEVMBasic(t *testing.T) {
|
|||||||
// invoke the contract with non owner
|
// invoke the contract with non owner
|
||||||
{
|
{
|
||||||
inputData := inputDataFromFrom(ctx, t, client, fromAddr)
|
inputData := inputDataFromFrom(ctx, t, client, fromAddr)
|
||||||
inputData[31]++ // change the pub address to one that has 0 balance by incrementing the last byte of the address
|
inputData[31]++ // change the pub address to one that has 0 balance by modifying the last byte of the address
|
||||||
result := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData)
|
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, idAddr, "getBalance(address)", inputData)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
|
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -81,7 +205,7 @@ func TestFEVMBasic(t *testing.T) {
|
|||||||
|
|
||||||
// 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) {
|
||||||
ctx, cancel, client := setupFEVMTest(t)
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
eth0id, err := address.NewIDAddress(1001)
|
eth0id, err := address.NewIDAddress(1001)
|
||||||
@ -100,7 +224,47 @@ func TestFEVMETH0(t *testing.T) {
|
|||||||
// TestFEVMDelegateCall deploys two contracts and makes a delegate call transaction
|
// TestFEVMDelegateCall deploys two contracts and makes a delegate call transaction
|
||||||
func TestFEVMDelegateCall(t *testing.T) {
|
func TestFEVMDelegateCall(t *testing.T) {
|
||||||
|
|
||||||
ctx, cancel, client := setupFEVMTest(t)
|
ctx, cancel, client := kit.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, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "setVars(address,uint256)", inputData)
|
||||||
|
require.NoError(t, err)
|
||||||
|
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000007")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, result, expectedResult)
|
||||||
|
|
||||||
|
//test the value is 7 a second way by calling the getter
|
||||||
|
result, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "getCounter()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, result, expectedResult)
|
||||||
|
|
||||||
|
//test the value is 0 via calling the getter on the Actor contract
|
||||||
|
result, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "getCounter()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
expectedResultActor, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, result, expectedResultActor)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFEVMDelegateCallRevert makes a delegatecall action and then calls revert.
|
||||||
|
// the state should not have changed because of the revert
|
||||||
|
func TestFEVMDelegateCallRevert(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
//install contract Actor
|
//install contract Actor
|
||||||
@ -119,20 +283,247 @@ func TestFEVMDelegateCall(t *testing.T) {
|
|||||||
inputData := append(inputDataContract, inputDataValue...)
|
inputData := append(inputDataContract, inputDataValue...)
|
||||||
|
|
||||||
//verify that the returned value of the call to setvars is 7
|
//verify that the returned value of the call to setvars is 7
|
||||||
result := client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "setVars(address,uint256)", inputData)
|
_, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "setVarsRevert(address,uint256)", inputData)
|
||||||
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000007")
|
require.Error(t, err)
|
||||||
require.NoError(t, err)
|
require.Equal(t, exitcode.ExitCode(33), wait.Receipt.ExitCode)
|
||||||
require.Equal(t, result, expectedResult)
|
|
||||||
|
|
||||||
//test the value is 7 via calling the getter
|
//test the value is 0 via calling the getter and was not set to 7
|
||||||
result = client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "getCounter()", []byte{})
|
expectedResult, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
require.NoError(t, err)
|
||||||
|
result, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, storageAddr, "getCounter()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
require.Equal(t, result, expectedResult)
|
require.Equal(t, result, expectedResult)
|
||||||
|
|
||||||
//test the value is 0 via calling the getter on the Actor contract
|
//test the value is 0 via calling the getter on the Actor contract
|
||||||
result = client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "getCounter()", []byte{})
|
result, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "getCounter()", []byte{})
|
||||||
expectedResultActor, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, result, expectedResultActor)
|
require.Equal(t, result, expectedResult)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFEVMSimpleRevert makes a call that is a simple revert
|
||||||
|
func TestFEVMSimpleRevert(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
//install contract Actor
|
||||||
|
filenameStorage := "contracts/DelegatecallStorage.hex"
|
||||||
|
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
|
||||||
|
|
||||||
|
//call revert
|
||||||
|
_, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "revert()", []byte{})
|
||||||
|
|
||||||
|
require.Equal(t, wait.Receipt.ExitCode, exitcode.ExitCode(33))
|
||||||
|
require.Error(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFEVMSelfDestruct creates a contract that just has a self destruct feature and calls it
|
||||||
|
func TestFEVMSelfDestruct(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
//install contract Actor
|
||||||
|
filenameStorage := "contracts/SelfDestruct.hex"
|
||||||
|
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
|
||||||
|
|
||||||
|
//call destroy
|
||||||
|
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "destroy()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
//call destroy a second time and also no error
|
||||||
|
_, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "destroy()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFEVMTestApp deploys a fairly complex app contract and confirms it works as expected
|
||||||
|
func TestFEVMTestApp(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
//install contract Actor
|
||||||
|
filenameStorage := "contracts/TestApp.hex"
|
||||||
|
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
|
||||||
|
|
||||||
|
inputData, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000000000000000066162636465660000000000000000000000000000000000000000000000000000") // sending string "abcdef" and int 7 - constructed using remix
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "new_Test(string,uint256)", inputData)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
inputData, err = hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "get_Test_N(uint256)", inputData)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFEVMTestApp creates a contract that just has a self destruct feature and calls it
|
||||||
|
func TestFEVMTestConstructor(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
//install contract Actor
|
||||||
|
filenameStorage := "contracts/Constructor.hex"
|
||||||
|
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
|
||||||
|
|
||||||
|
//input = uint256{7}. set value and confirm tx success
|
||||||
|
inputData, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000007")
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "new_Test(uint256)", inputData)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFEVMAutoSelfDestruct creates a contract that just has a self destruct feature and calls it
|
||||||
|
func TestFEVMAutoSelfDestruct(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
//install contract Actor
|
||||||
|
filenameStorage := "contracts/AutoSelfDestruct.hex"
|
||||||
|
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
|
||||||
|
|
||||||
|
//call destroy
|
||||||
|
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "destroy()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFEVMTestApp creates a contract that just has a self destruct feature and calls it
|
||||||
|
func TestFEVMTestSendToContract(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
bal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
//install contract TestApp
|
||||||
|
filenameStorage := "contracts/SelfDestruct.hex"
|
||||||
|
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
|
||||||
|
|
||||||
|
//transfer half balance to contract
|
||||||
|
|
||||||
|
sendAmount := big.Div(bal, big.NewInt(2))
|
||||||
|
client.EVM().TransferValueOrFail(ctx, fromAddr, contractAddr, sendAmount)
|
||||||
|
|
||||||
|
//call self destruct which should return balance
|
||||||
|
_, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "destroy()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
finalBalanceMinimum := types.FromFil(uint64(99_999_999)) // 100 million FIL - 1 FIL for gas upper bounds
|
||||||
|
finalBal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, true, finalBal.GreaterThan(finalBalanceMinimum))
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a contract that would fail when tx are sent to it
|
||||||
|
// on eth but on fevm it succeeds
|
||||||
|
// example failing on testnet https://goerli.etherscan.io/address/0x2ff1525e060169dbf97b9461758c8f701f107cd2
|
||||||
|
func TestFEVMTestNotPayable(t *testing.T) {
|
||||||
|
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
fromAddr := client.DefaultKey.Address
|
||||||
|
t.Log("from - ", fromAddr)
|
||||||
|
|
||||||
|
//create contract A
|
||||||
|
filenameStorage := "contracts/NotPayable.hex"
|
||||||
|
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
|
||||||
|
sendAmount := big.NewInt(10_000_000)
|
||||||
|
|
||||||
|
client.EVM().TransferValueOrFail(ctx, fromAddr, contractAddr, sendAmount)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// tx to non function succeeds
|
||||||
|
func TestFEVMSendCall(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
//install contract
|
||||||
|
filenameActor := "contracts/GasSendTest.hex"
|
||||||
|
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)
|
||||||
|
|
||||||
|
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "x()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a contract that would fail when tx are sent to it
|
||||||
|
// on eth but on fevm it succeeds
|
||||||
|
// example on goerli of tx failing https://goerli.etherscan.io/address/0xec037bdc9a79420985a53a49fdae3ccf8989909b
|
||||||
|
func TestFEVMSendGasLimit(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
//install contract
|
||||||
|
filenameActor := "contracts/GasLimitSend.hex"
|
||||||
|
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)
|
||||||
|
|
||||||
|
//send $ to contract
|
||||||
|
//transfer 1 attoFIL to contract
|
||||||
|
sendAmount := big.MustFromString("1")
|
||||||
|
|
||||||
|
client.EVM().TransferValueOrFail(ctx, fromAddr, contractAddr, sendAmount)
|
||||||
|
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "getDataLength()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestFEVMDelegateCall deploys the two contracts in TestFEVMDelegateCall but instead of A calling B, A calls A which should cause A to cause A in an infinite loop and should give a reasonable error
|
||||||
|
// XXX should not be fatal errors
|
||||||
|
func TestFEVMDelegateCallRecursiveFail(t *testing.T) {
|
||||||
|
//TODO change the gas limit of this invocation and confirm that the number of errors is different
|
||||||
|
//also TODO should we not have fatal error show up here?
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
//install contract Actor
|
||||||
|
filenameActor := "contracts/DelegatecallStorage.hex"
|
||||||
|
fromAddr, actorAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)
|
||||||
|
|
||||||
|
//any data will do for this test that fails
|
||||||
|
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
|
||||||
|
_, wait, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, actorAddr, "setVarsSelf(address,uint256)", inputData)
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Equal(t, exitcode.SysErrorIllegalArgument, wait.Receipt.ExitCode)
|
||||||
|
|
||||||
|
//assert no fatal errors but still there are errors::
|
||||||
|
errorAny := "fatal error"
|
||||||
|
require.NotContains(t, err.Error(), errorAny)
|
||||||
|
}
|
||||||
|
|
||||||
|
// XXX Currently fails as self destruct has a bug
|
||||||
|
// TestFEVMTestSendValueThroughContracts creates A and B contract and exchanges value
|
||||||
|
// and self destructs and accounts for value sent
|
||||||
|
func TestFEVMTestSendValueThroughContractsAndDestroy(t *testing.T) {
|
||||||
|
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
fromAddr := client.DefaultKey.Address
|
||||||
|
t.Log("from - ", fromAddr)
|
||||||
|
|
||||||
|
//create contract A
|
||||||
|
filenameStorage := "contracts/ValueSender.hex"
|
||||||
|
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameStorage)
|
||||||
|
|
||||||
|
//create contract B
|
||||||
|
ret, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "createB()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ethAddr, err := ethtypes.CastEthAddress(ret[12:])
|
||||||
|
require.NoError(t, err)
|
||||||
|
contractBAddress, err := ethAddr.ToFilecoinAddress()
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Log("contractBAddress - ", contractBAddress)
|
||||||
|
|
||||||
|
//self destruct contract B
|
||||||
|
_, _, err = client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractBAddress, "selfDestruct()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEVMRpcDisable(t *testing.T) {
|
func TestEVMRpcDisable(t *testing.T) {
|
||||||
@ -144,7 +535,7 @@ func TestEVMRpcDisable(t *testing.T) {
|
|||||||
|
|
||||||
// TestFEVMRecursiveFuncCall deploys a contract and makes a recursive function calls
|
// TestFEVMRecursiveFuncCall deploys a contract and makes a recursive function calls
|
||||||
func TestFEVMRecursiveFuncCall(t *testing.T) {
|
func TestFEVMRecursiveFuncCall(t *testing.T) {
|
||||||
ctx, cancel, client := setupFEVMTest(t)
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
//install contract Actor
|
//install contract Actor
|
||||||
@ -155,7 +546,6 @@ func TestFEVMRecursiveFuncCall(t *testing.T) {
|
|||||||
return func(t *testing.T) {
|
return func(t *testing.T) {
|
||||||
inputData := make([]byte, 32)
|
inputData := make([]byte, 32)
|
||||||
binary.BigEndian.PutUint64(inputData[24:], uint64(n))
|
binary.BigEndian.PutUint64(inputData[24:], uint64(n))
|
||||||
|
|
||||||
client.EVM().InvokeContractByFuncNameExpectExit(ctx, fromAddr, actorAddr, "exec1(uint256)", inputData, ex)
|
client.EVM().InvokeContractByFuncNameExpectExit(ctx, fromAddr, actorAddr, "exec1(uint256)", inputData, ex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,7 +560,7 @@ func TestFEVMRecursiveFuncCall(t *testing.T) {
|
|||||||
|
|
||||||
// TestFEVMRecursiveActorCall deploys a contract and makes a recursive actor calls
|
// TestFEVMRecursiveActorCall deploys a contract and makes a recursive actor calls
|
||||||
func TestFEVMRecursiveActorCall(t *testing.T) {
|
func TestFEVMRecursiveActorCall(t *testing.T) {
|
||||||
ctx, cancel, client := setupFEVMTest(t)
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
//install contract Actor
|
//install contract Actor
|
||||||
|
@ -290,7 +290,7 @@ func startNodes(
|
|||||||
ens.InterconnectAll().BeginMining(blocktime)
|
ens.InterconnectAll().BeginMining(blocktime)
|
||||||
|
|
||||||
// Create a gateway server in front of the full node
|
// Create a gateway server in front of the full node
|
||||||
gwapi := gateway.NewNode(full, lookbackCap, stateWaitLookbackLimit, 0, time.Minute)
|
gwapi := gateway.NewNode(full, nil, lookbackCap, stateWaitLookbackLimit, 0, time.Minute)
|
||||||
handler, err := gateway.Handler(gwapi, full, 0, 0)
|
handler, err := gateway.Handler(gwapi, full, 0, 0)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/wallet/key"
|
"github.com/filecoin-project/lotus/chain/wallet/key"
|
||||||
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
|
"github.com/filecoin-project/lotus/cmd/lotus-seed/seed"
|
||||||
"github.com/filecoin-project/lotus/cmd/lotus-worker/sealworker"
|
"github.com/filecoin-project/lotus/cmd/lotus-worker/sealworker"
|
||||||
|
"github.com/filecoin-project/lotus/gateway"
|
||||||
"github.com/filecoin-project/lotus/genesis"
|
"github.com/filecoin-project/lotus/genesis"
|
||||||
"github.com/filecoin-project/lotus/markets/idxprov"
|
"github.com/filecoin-project/lotus/markets/idxprov"
|
||||||
"github.com/filecoin-project/lotus/markets/idxprov/idxprov_test"
|
"github.com/filecoin-project/lotus/markets/idxprov/idxprov_test"
|
||||||
@ -210,7 +211,7 @@ func (n *Ensemble) FullNode(full *TestFullNode, opts ...NodeOpt) *Ensemble {
|
|||||||
n.genesis.accounts = append(n.genesis.accounts, genacc)
|
n.genesis.accounts = append(n.genesis.accounts, genacc)
|
||||||
}
|
}
|
||||||
|
|
||||||
*full = TestFullNode{t: n.t, options: options, DefaultKey: key}
|
*full = TestFullNode{t: n.t, options: options, DefaultKey: key, EthSubRouter: gateway.NewEthSubHandler()}
|
||||||
|
|
||||||
n.inactive.fullnodes = append(n.inactive.fullnodes, full)
|
n.inactive.fullnodes = append(n.inactive.fullnodes, full)
|
||||||
return n
|
return n
|
||||||
|
@ -7,8 +7,11 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
logging "github.com/ipfs/go-log/v2"
|
||||||
"github.com/multiformats/go-varint"
|
"github.com/multiformats/go-varint"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
cbg "github.com/whyrusleeping/cbor-gen"
|
||||||
@ -101,13 +104,13 @@ func (e *EVM) DeployContractFromFilename(ctx context.Context, binFilename string
|
|||||||
return fromAddr, idAddr
|
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, error) {
|
||||||
require := require.New(e.t)
|
|
||||||
|
|
||||||
params := append(selector, inputData...)
|
params := append(selector, inputData...)
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
err := cbg.WriteByteArray(&buffer, params)
|
err := cbg.WriteByteArray(&buffer, params)
|
||||||
require.NoError(err)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
params = buffer.Bytes()
|
params = buffer.Bytes()
|
||||||
|
|
||||||
msg := &types.Message{
|
msg := &types.Message{
|
||||||
@ -121,13 +124,17 @@ func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target
|
|||||||
|
|
||||||
e.t.Log("sending invoke message")
|
e.t.Log("sending invoke message")
|
||||||
smsg, err := e.MpoolPushMessage(ctx, msg, nil)
|
smsg, err := e.MpoolPushMessage(ctx, msg, nil)
|
||||||
require.NoError(err)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
e.t.Log("waiting for message to execute")
|
e.t.Log("waiting for message to execute")
|
||||||
wait, err := e.StateWaitMsg(ctx, smsg.Cid(), 0, 0, false)
|
wait, err := e.StateWaitMsg(ctx, smsg.Cid(), 0, 0, false)
|
||||||
require.NoError(err)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return wait
|
return wait, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadEvents loads all events in an event AMT.
|
// LoadEvents loads all events in an event AMT.
|
||||||
@ -237,18 +244,25 @@ 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 {
|
func (e *EVM) InvokeContractByFuncName(ctx context.Context, fromAddr address.Address, idAddr address.Address, funcSignature string, inputData []byte) ([]byte, *api.MsgLookup, error) {
|
||||||
entryPoint := CalcFuncSignature(funcSignature)
|
entryPoint := CalcFuncSignature(funcSignature)
|
||||||
wait := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
|
wait, err := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
|
||||||
require.True(e.t, wait.Receipt.ExitCode.IsSuccess(), "contract execution failed: %d", wait.Receipt.ExitCode)
|
if err != nil {
|
||||||
|
return nil, wait, err
|
||||||
|
}
|
||||||
|
if !wait.Receipt.ExitCode.IsSuccess() {
|
||||||
|
return nil, wait, fmt.Errorf("contract execution failed - %v", wait.Receipt.ExitCode)
|
||||||
|
}
|
||||||
result, err := cbg.ReadByteArray(bytes.NewBuffer(wait.Receipt.Return), uint64(len(wait.Receipt.Return)))
|
result, err := cbg.ReadByteArray(bytes.NewBuffer(wait.Receipt.Return), uint64(len(wait.Receipt.Return)))
|
||||||
require.NoError(e.t, err)
|
if err != nil {
|
||||||
return result
|
return nil, wait, err
|
||||||
|
}
|
||||||
|
return result, wait, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EVM) InvokeContractByFuncNameExpectExit(ctx context.Context, fromAddr address.Address, idAddr address.Address, funcSignature string, inputData []byte, exit exitcode.ExitCode) {
|
func (e *EVM) InvokeContractByFuncNameExpectExit(ctx context.Context, fromAddr address.Address, idAddr address.Address, funcSignature string, inputData []byte, exit exitcode.ExitCode) {
|
||||||
entryPoint := CalcFuncSignature(funcSignature)
|
entryPoint := CalcFuncSignature(funcSignature)
|
||||||
wait := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
|
wait, _ := e.InvokeSolidity(ctx, fromAddr, idAddr, entryPoint, inputData)
|
||||||
require.Equal(e.t, exit, wait.Receipt.ExitCode)
|
require.Equal(e.t, exit, wait.Receipt.ExitCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,6 +325,43 @@ func removeLeadingZeros(data []byte) []byte {
|
|||||||
return data[firstNonZeroIndex:]
|
return data[firstNonZeroIndex:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetupFEVMTest(t *testing.T) (context.Context, context.CancelFunc, *TestFullNode) {
|
||||||
|
// make all logs extra quiet for fevm tests
|
||||||
|
lvl, err := logging.LevelFromString("error")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
logging.SetAllLoggers(lvl)
|
||||||
|
|
||||||
|
blockTime := 100 * time.Millisecond
|
||||||
|
client, _, ens := EnsembleMinimal(t, MockProofs(), ThroughRPC())
|
||||||
|
ens.InterconnectAll().BeginMining(blockTime)
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
|
||||||
|
// require that the initial balance is 100 million FIL in setup
|
||||||
|
// this way other tests can count on this initial wallet balance
|
||||||
|
fromAddr := client.DefaultKey.Address
|
||||||
|
bal, err := client.WalletBalance(ctx, fromAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
originalBalance := types.FromFil(uint64(100_000_000)) // 100 million FIL
|
||||||
|
require.Equal(t, originalBalance, bal)
|
||||||
|
|
||||||
|
return ctx, cancel, client
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EVM) TransferValueOrFail(ctx context.Context, fromAddr address.Address, toAddr address.Address, sendAmount big.Int) {
|
||||||
|
sendMsg := &types.Message{
|
||||||
|
From: fromAddr,
|
||||||
|
To: toAddr,
|
||||||
|
Value: sendAmount,
|
||||||
|
}
|
||||||
|
signedMsg, err := e.MpoolPushMessage(ctx, sendMsg, nil)
|
||||||
|
require.NoError(e.t, err)
|
||||||
|
mLookup, err := e.StateWaitMsg(ctx, signedMsg.Cid(), 3, api.LookbackNoLimit, true)
|
||||||
|
require.NoError(e.t, err)
|
||||||
|
require.Equal(e.t, exitcode.Ok, mLookup.Receipt.ExitCode)
|
||||||
|
}
|
||||||
|
|
||||||
func NewEthFilterBuilder() *EthFilterBuilder {
|
func NewEthFilterBuilder() *EthFilterBuilder {
|
||||||
return &EthFilterBuilder{}
|
return &EthFilterBuilder{}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/wallet/key"
|
"github.com/filecoin-project/lotus/chain/wallet/key"
|
||||||
cliutil "github.com/filecoin-project/lotus/cli/util"
|
cliutil "github.com/filecoin-project/lotus/cli/util"
|
||||||
|
"github.com/filecoin-project/lotus/gateway"
|
||||||
"github.com/filecoin-project/lotus/node"
|
"github.com/filecoin-project/lotus/node"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -46,6 +47,10 @@ type TestFullNode struct {
|
|||||||
|
|
||||||
Stop node.StopFunc
|
Stop node.StopFunc
|
||||||
|
|
||||||
|
// gateway handler makes it convenient to register callbalks per topic, so we
|
||||||
|
// also use it for tests
|
||||||
|
EthSubRouter *gateway.EthSubHandler
|
||||||
|
|
||||||
options nodeOpts
|
options nodeOpts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ import (
|
|||||||
manet "github.com/multiformats/go-multiaddr/net"
|
manet "github.com/multiformats/go-multiaddr/net"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api/client"
|
"github.com/filecoin-project/lotus/api/client"
|
||||||
"github.com/filecoin-project/lotus/cmd/lotus-worker/sealworker"
|
"github.com/filecoin-project/lotus/cmd/lotus-worker/sealworker"
|
||||||
"github.com/filecoin-project/lotus/node"
|
"github.com/filecoin-project/lotus/node"
|
||||||
@ -52,7 +54,12 @@ func fullRpc(t *testing.T, f *TestFullNode) (*TestFullNode, Closer) {
|
|||||||
fmt.Printf("FULLNODE RPC ENV FOR CLI DEBUGGING `export FULLNODE_API_INFO=%s`\n", "ws://"+srv.Listener.Addr().String())
|
fmt.Printf("FULLNODE RPC ENV FOR CLI DEBUGGING `export FULLNODE_API_INFO=%s`\n", "ws://"+srv.Listener.Addr().String())
|
||||||
sendItestdNotif("FULLNODE_API_INFO", t.Name(), "ws://"+srv.Listener.Addr().String())
|
sendItestdNotif("FULLNODE_API_INFO", t.Name(), "ws://"+srv.Listener.Addr().String())
|
||||||
|
|
||||||
cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil)
|
rpcOpts := []jsonrpc.Option{
|
||||||
|
jsonrpc.WithClientHandler("Filecoin", f.EthSubRouter),
|
||||||
|
jsonrpc.WithClientHandlerAlias("eth_subscription", "Filecoin.EthSubscription"),
|
||||||
|
}
|
||||||
|
|
||||||
|
cl, stop, err := client.NewFullNodeRPCV1(context.Background(), "ws://"+srv.Listener.Addr().String()+"/rpc/v1", nil, rpcOpts...)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
f.ListenAddr, f.ListenURL, f.FullNode = maddr, srv.URL, cl
|
f.ListenAddr, f.ListenURL, f.FullNode = maddr, srv.URL, cl
|
||||||
|
|
||||||
|
@ -30,6 +30,12 @@ func Wrap[T any](value T, err error) Result[T] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Result[T]) Unwrap() (T, error) {
|
func (r Result[T]) Unwrap() (T, error) {
|
||||||
return r.Value, r.Error
|
return r.Value, r.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r Result[T]) Assert(noErrFn func(err error, msgAndArgs ...interface{})) T {
|
||||||
|
noErrFn(r.Error)
|
||||||
|
|
||||||
|
return r.Value
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ package full
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -16,6 +17,7 @@ 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-jsonrpc"
|
||||||
"github.com/filecoin-project/go-state-types/abi"
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
"github.com/filecoin-project/go-state-types/big"
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||||
@ -75,7 +77,7 @@ type EthEventAPI interface {
|
|||||||
EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error)
|
EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error)
|
||||||
EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error)
|
EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error)
|
||||||
EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error)
|
EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error)
|
||||||
EthSubscribe(ctx context.Context, eventType string, params *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error)
|
EthSubscribe(ctx context.Context, params jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error)
|
||||||
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error)
|
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,6 +134,7 @@ type EthEvent struct {
|
|||||||
FilterStore filter.FilterStore
|
FilterStore filter.FilterStore
|
||||||
SubManager *EthSubscriptionManager
|
SubManager *EthSubscriptionManager
|
||||||
MaxFilterHeightRange abi.ChainEpoch
|
MaxFilterHeightRange abi.ChainEpoch
|
||||||
|
SubscribtionCtx context.Context
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ EthEventAPI = (*EthEvent)(nil)
|
var _ EthEventAPI = (*EthEvent)(nil)
|
||||||
@ -212,7 +215,7 @@ func (a *EthModule) EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthH
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EthBlock{}, xerrors.Errorf("error loading tipset %s: %w", ts, err)
|
return ethtypes.EthBlock{}, xerrors.Errorf("error loading tipset %s: %w", ts, err)
|
||||||
}
|
}
|
||||||
return newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo, a.Chain, a.ChainAPI, a.StateAPI)
|
return newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo, a.Chain, a.StateAPI)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *EthModule) parseBlkParam(ctx context.Context, blkParam string) (tipset *types.TipSet, err error) {
|
func (a *EthModule) parseBlkParam(ctx context.Context, blkParam string) (tipset *types.TipSet, err error) {
|
||||||
@ -249,7 +252,7 @@ func (a *EthModule) EthGetBlockByNumber(ctx context.Context, blkParam string, fu
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EthBlock{}, err
|
return ethtypes.EthBlock{}, err
|
||||||
}
|
}
|
||||||
return newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo, a.Chain, a.ChainAPI, a.StateAPI)
|
return newEthBlockFromFilecoinTipSet(ctx, ts, fullTxInfo, a.Chain, a.StateAPI)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) {
|
func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) {
|
||||||
@ -270,8 +273,8 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
|
|||||||
|
|
||||||
// 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, c, api.LookbackNoLimit, true)
|
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, c, api.LookbackNoLimit, true)
|
||||||
if err == nil {
|
if err == nil && msgLookup != nil {
|
||||||
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI)
|
tx, err := newEthTxFromMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return &tx, nil
|
return &tx, nil
|
||||||
}
|
}
|
||||||
@ -287,7 +290,7 @@ func (a *EthModule) EthGetTransactionByHash(ctx context.Context, txHash *ethtype
|
|||||||
|
|
||||||
for _, p := range pending {
|
for _, p := range pending {
|
||||||
if p.Cid() == c {
|
if p.Cid() == c {
|
||||||
tx, err := NewEthTxFromFilecoinMessage(ctx, p, a.StateAPI)
|
tx, err := newEthTxFromSignedMessage(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)
|
||||||
}
|
}
|
||||||
@ -336,7 +339,7 @@ func (a *EthModule) EthGetMessageCidByTransactionHash(ctx context.Context, txHas
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *EthModule) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) {
|
func (a *EthModule) EthGetTransactionHashByCid(ctx context.Context, cid cid.Cid) (*ethtypes.EthHash, error) {
|
||||||
hash, err := EthTxHashFromFilecoinMessageCid(ctx, cid, a.StateAPI)
|
hash, err := EthTxHashFromMessageCid(ctx, cid, a.StateAPI)
|
||||||
if hash == ethtypes.EmptyEthHash {
|
if hash == ethtypes.EmptyEthHash {
|
||||||
// not found
|
// not found
|
||||||
return nil, nil
|
return nil, nil
|
||||||
@ -379,7 +382,7 @@ func (a *EthModule) EthGetTransactionReceipt(ctx context.Context, txHash ethtype
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, err := newEthTxFromFilecoinMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI)
|
tx, err := newEthTxFromMessageLookup(ctx, msgLookup, -1, a.Chain, a.StateAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
@ -610,7 +613,7 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint
|
|||||||
for ts.Height() >= abi.ChainEpoch(oldestBlkHeight) {
|
for ts.Height() >= abi.ChainEpoch(oldestBlkHeight) {
|
||||||
// Unfortunately we need to rebuild the full message view so we can
|
// Unfortunately we need to rebuild the full message view so we can
|
||||||
// totalize gas used in the tipset.
|
// totalize gas used in the tipset.
|
||||||
block, err := newEthBlockFromFilecoinTipSet(ctx, ts, false, a.Chain, a.ChainAPI, a.StateAPI)
|
block, err := newEthBlockFromFilecoinTipSet(ctx, ts, false, a.Chain, a.StateAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EthFeeHistory{}, fmt.Errorf("cannot create eth block: %v", err)
|
return ethtypes.EthFeeHistory{}, fmt.Errorf("cannot create eth block: %v", err)
|
||||||
}
|
}
|
||||||
@ -695,13 +698,6 @@ func (a *EthModule) EthSendRawTransaction(ctx context.Context, rawTx ethtypes.Et
|
|||||||
return ethtypes.EmptyEthHash, err
|
return ethtypes.EmptyEthHash, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = a.StateAPI.StateGetActor(ctx, smsg.Message.To, types.EmptyTSK)
|
|
||||||
if err != nil {
|
|
||||||
// if actor does not exist on chain yet, set the method to 0 because
|
|
||||||
// placeholders only implement method 0
|
|
||||||
smsg.Message.Method = builtinactors.MethodSend
|
|
||||||
}
|
|
||||||
|
|
||||||
_, 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
|
||||||
@ -1111,37 +1107,45 @@ const (
|
|||||||
EthSubscribeEventTypeLogs = "logs"
|
EthSubscribeEventTypeLogs = "logs"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *EthEvent) EthSubscribe(ctx context.Context, eventType string, params *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) {
|
func (e *EthEvent) EthSubscribe(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {
|
||||||
if e.SubManager == nil {
|
params, err := jsonrpc.DecodeParams[ethtypes.EthSubscribeParams](p)
|
||||||
return nil, api.ErrNotSupported
|
|
||||||
}
|
|
||||||
// Note that go-jsonrpc will set the method field of the response to "xrpc.ch.val" but the ethereum api expects the name of the
|
|
||||||
// method to be "eth_subscription". This probably doesn't matter in practice.
|
|
||||||
|
|
||||||
sub, err := e.SubManager.StartSubscription(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return ethtypes.EthSubscriptionID{}, xerrors.Errorf("decoding params: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch eventType {
|
if e.SubManager == nil {
|
||||||
|
return ethtypes.EthSubscriptionID{}, api.ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
|
ethCb, ok := jsonrpc.ExtractReverseClient[api.EthSubscriberMethods](ctx)
|
||||||
|
if !ok {
|
||||||
|
return ethtypes.EthSubscriptionID{}, xerrors.Errorf("connection doesn't support callbacks")
|
||||||
|
}
|
||||||
|
|
||||||
|
sub, err := e.SubManager.StartSubscription(e.SubscribtionCtx, ethCb.EthSubscription)
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EthSubscriptionID{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch params.EventType {
|
||||||
case EthSubscribeEventTypeHeads:
|
case EthSubscribeEventTypeHeads:
|
||||||
f, err := e.TipSetFilterManager.Install(ctx)
|
f, err := e.TipSetFilterManager.Install(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// clean up any previous filters added and stop the sub
|
// clean up any previous filters added and stop the sub
|
||||||
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
||||||
return nil, err
|
return ethtypes.EthSubscriptionID{}, err
|
||||||
}
|
}
|
||||||
sub.addFilter(ctx, f)
|
sub.addFilter(ctx, f)
|
||||||
|
|
||||||
case EthSubscribeEventTypeLogs:
|
case EthSubscribeEventTypeLogs:
|
||||||
keys := map[string][][]byte{}
|
keys := map[string][][]byte{}
|
||||||
if params != nil {
|
if params.Params != nil {
|
||||||
var err error
|
var err error
|
||||||
keys, err = parseEthTopics(params.Topics)
|
keys, err = parseEthTopics(params.Params.Topics)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// clean up any previous filters added and stop the sub
|
// clean up any previous filters added and stop the sub
|
||||||
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
||||||
return nil, err
|
return ethtypes.EthSubscriptionID{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1149,14 +1153,14 @@ func (e *EthEvent) EthSubscribe(ctx context.Context, eventType string, params *e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
// clean up any previous filters added and stop the sub
|
// clean up any previous filters added and stop the sub
|
||||||
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
||||||
return nil, err
|
return ethtypes.EthSubscriptionID{}, err
|
||||||
}
|
}
|
||||||
sub.addFilter(ctx, f)
|
sub.addFilter(ctx, f)
|
||||||
default:
|
default:
|
||||||
return nil, xerrors.Errorf("unsupported event type: %s", eventType)
|
return ethtypes.EthSubscriptionID{}, xerrors.Errorf("unsupported event type: %s", params.EventType)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sub.out, nil
|
return sub.id, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EthEvent) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) {
|
func (e *EthEvent) EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) {
|
||||||
@ -1244,7 +1248,7 @@ func ethFilterResultFromEvents(evs []*filter.CollectedEvent, sa StateAPI) (*etht
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.TransactionHash, err = EthTxHashFromFilecoinMessageCid(context.TODO(), ev.MsgCid, sa)
|
log.TransactionHash, err = EthTxHashFromMessageCid(context.TODO(), ev.MsgCid, sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1286,7 +1290,7 @@ func ethFilterResultFromMessages(cs []*types.SignedMessage, sa StateAPI) (*ethty
|
|||||||
res := ðtypes.EthFilterResult{}
|
res := ðtypes.EthFilterResult{}
|
||||||
|
|
||||||
for _, c := range cs {
|
for _, c := range cs {
|
||||||
hash, err := EthTxHashFromSignedFilecoinMessage(context.TODO(), c, sa)
|
hash, err := EthTxHashFromSignedMessage(context.TODO(), c, sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1305,7 +1309,7 @@ type EthSubscriptionManager struct {
|
|||||||
subs map[ethtypes.EthSubscriptionID]*ethSubscription
|
subs map[ethtypes.EthSubscriptionID]*ethSubscription
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EthSubscriptionManager) StartSubscription(ctx context.Context) (*ethSubscription, error) { // nolint
|
func (e *EthSubscriptionManager) StartSubscription(ctx context.Context, out ethSubscriptionCallback) (*ethSubscription, error) { // nolint
|
||||||
rawid, err := uuid.NewRandom()
|
rawid, err := uuid.NewRandom()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("new uuid: %w", err)
|
return nil, xerrors.Errorf("new uuid: %w", err)
|
||||||
@ -1321,7 +1325,7 @@ func (e *EthSubscriptionManager) StartSubscription(ctx context.Context) (*ethSub
|
|||||||
ChainAPI: e.ChainAPI,
|
ChainAPI: e.ChainAPI,
|
||||||
id: id,
|
id: id,
|
||||||
in: make(chan interface{}, 200),
|
in: make(chan interface{}, 200),
|
||||||
out: make(chan ethtypes.EthSubscriptionResponse, 20),
|
out: out,
|
||||||
quit: quit,
|
quit: quit,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1351,13 +1355,15 @@ func (e *EthSubscriptionManager) StopSubscription(ctx context.Context, id ethtyp
|
|||||||
return sub.filters, nil
|
return sub.filters, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ethSubscriptionCallback func(context.Context, jsonrpc.RawParams) error
|
||||||
|
|
||||||
type ethSubscription struct {
|
type ethSubscription struct {
|
||||||
Chain *store.ChainStore
|
Chain *store.ChainStore
|
||||||
StateAPI StateAPI
|
StateAPI StateAPI
|
||||||
ChainAPI ChainAPI
|
ChainAPI ChainAPI
|
||||||
id ethtypes.EthSubscriptionID
|
id ethtypes.EthSubscriptionID
|
||||||
in chan interface{}
|
in chan interface{}
|
||||||
out chan ethtypes.EthSubscriptionResponse
|
out ethSubscriptionCallback
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
filters []filter.Filter
|
filters []filter.Filter
|
||||||
@ -1387,7 +1393,7 @@ func (e *ethSubscription) start(ctx context.Context) {
|
|||||||
case *filter.CollectedEvent:
|
case *filter.CollectedEvent:
|
||||||
resp.Result, err = ethFilterResultFromEvents([]*filter.CollectedEvent{vt}, e.StateAPI)
|
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.StateAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -1401,10 +1407,15 @@ func (e *ethSubscription) start(ctx context.Context) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
outParam, err := json.Marshal(resp)
|
||||||
case e.out <- resp:
|
if err != nil {
|
||||||
default:
|
log.Warnw("marshaling subscription response", "sub", e.id, "error", err)
|
||||||
// Skip if client is not reading responses
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := e.out(ctx, outParam); err != nil {
|
||||||
|
log.Warnw("sending subscription response", "sub", e.id, "error", err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1416,12 +1427,11 @@ func (e *ethSubscription) stop() {
|
|||||||
|
|
||||||
if e.quit != nil {
|
if e.quit != nil {
|
||||||
e.quit()
|
e.quit()
|
||||||
close(e.out)
|
|
||||||
e.quit = nil
|
e.quit = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTxInfo bool, cs *store.ChainStore, ca ChainAPI, sa StateAPI) (ethtypes.EthBlock, error) {
|
func newEthBlockFromFilecoinTipSet(ctx context.Context, ts *types.TipSet, fullTxInfo bool, cs *store.ChainStore, sa StateAPI) (ethtypes.EthBlock, error) {
|
||||||
parent, err := cs.LoadTipSet(ctx, ts.Parents())
|
parent, err := cs.LoadTipSet(ctx, ts.Parents())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EthBlock{}, err
|
return ethtypes.EthBlock{}, err
|
||||||
@ -1460,7 +1470,7 @@ 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)
|
tx, err := newEthTxFromMessageLookup(ctx, msgLookup, txIdx, cs, sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EthBlock{}, nil
|
return ethtypes.EthBlock{}, nil
|
||||||
}
|
}
|
||||||
@ -1520,11 +1530,11 @@ func lookupEthAddress(ctx context.Context, addr address.Address, sa StateAPI) (e
|
|||||||
return ethtypes.EthAddressFromFilecoinAddress(idAddr)
|
return ethtypes.EthAddressFromFilecoinAddress(idAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func EthTxHashFromFilecoinMessageCid(ctx context.Context, c cid.Cid, sa StateAPI) (ethtypes.EthHash, error) {
|
func EthTxHashFromMessageCid(ctx context.Context, c cid.Cid, sa StateAPI) (ethtypes.EthHash, error) {
|
||||||
smsg, err := sa.Chain.GetSignedMessage(ctx, c)
|
smsg, err := sa.Chain.GetSignedMessage(ctx, c)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// This is an Eth Tx, Secp message, Or BLS message in the mpool
|
// This is an Eth Tx, Secp message, Or BLS message in the mpool
|
||||||
return EthTxHashFromSignedFilecoinMessage(ctx, smsg, sa)
|
return EthTxHashFromSignedMessage(ctx, smsg, sa)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = sa.Chain.GetMessage(ctx, c)
|
_, err = sa.Chain.GetMessage(ctx, c)
|
||||||
@ -1536,93 +1546,51 @@ func EthTxHashFromFilecoinMessageCid(ctx context.Context, c cid.Cid, sa StateAPI
|
|||||||
return ethtypes.EmptyEthHash, nil
|
return ethtypes.EmptyEthHash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func EthTxHashFromSignedFilecoinMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthHash, error) {
|
func EthTxHashFromSignedMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthHash, error) {
|
||||||
if smsg.Signature.Type == crypto.SigTypeDelegated {
|
if smsg.Signature.Type == crypto.SigTypeDelegated {
|
||||||
ethTx, err := NewEthTxFromFilecoinMessage(ctx, smsg, sa)
|
ethTx, err := newEthTxFromSignedMessage(ctx, smsg, sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EmptyEthHash, err
|
return ethtypes.EmptyEthHash, err
|
||||||
}
|
}
|
||||||
return ethTx.Hash, nil
|
return ethTx.Hash, nil
|
||||||
}
|
} else if smsg.Signature.Type == crypto.SigTypeSecp256k1 {
|
||||||
|
|
||||||
return ethtypes.EthHashFromCid(smsg.Cid())
|
return ethtypes.EthHashFromCid(smsg.Cid())
|
||||||
|
} else { // BLS message
|
||||||
|
return ethtypes.EthHashFromCid(smsg.Message.Cid())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEthTxFromFilecoinMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthTx, error) {
|
func newEthTxFromSignedMessage(ctx context.Context, smsg *types.SignedMessage, sa StateAPI) (ethtypes.EthTx, error) {
|
||||||
// Ignore errors here so we can still parse non-eth messages
|
var tx ethtypes.EthTx
|
||||||
fromEthAddr, _ := lookupEthAddress(ctx, smsg.Message.From, sa)
|
|
||||||
toEthAddr, _ := lookupEthAddress(ctx, smsg.Message.To, sa)
|
|
||||||
|
|
||||||
toAddr := &toEthAddr
|
|
||||||
input := smsg.Message.Params
|
|
||||||
var err error
|
var err error
|
||||||
// Check to see if we need to decode as contract deployment.
|
|
||||||
// We don't need to resolve the to address, because there's only one form (an ID).
|
|
||||||
if smsg.Message.To == builtintypes.EthereumAddressManagerActorAddr {
|
|
||||||
switch smsg.Message.Method {
|
|
||||||
case builtintypes.MethodsEAM.Create:
|
|
||||||
toAddr = nil
|
|
||||||
var params eam.CreateParams
|
|
||||||
err = params.UnmarshalCBOR(bytes.NewReader(smsg.Message.Params))
|
|
||||||
input = params.Initcode
|
|
||||||
case builtintypes.MethodsEAM.Create2:
|
|
||||||
toAddr = nil
|
|
||||||
var params eam.Create2Params
|
|
||||||
err = params.UnmarshalCBOR(bytes.NewReader(smsg.Message.Params))
|
|
||||||
input = params.Initcode
|
|
||||||
case builtintypes.MethodsEAM.CreateExternal:
|
|
||||||
toAddr = nil
|
|
||||||
var params abi.CborBytes
|
|
||||||
err = params.UnmarshalCBOR(bytes.NewReader(smsg.Message.Params))
|
|
||||||
input = []byte(params)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return ethtypes.EthTx{}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Otherwise, try to decode as a cbor byte array.
|
|
||||||
// TODO: Actually check if this is an ethereum call. This code will work for demo purposes, but is not correct.
|
|
||||||
if toAddr != nil {
|
|
||||||
if decodedParams, err := cbg.ReadByteArray(bytes.NewReader(smsg.Message.Params), uint64(len(smsg.Message.Params))); err == nil {
|
|
||||||
input = decodedParams
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
r, s, v, err := ethtypes.RecoverSignature(smsg.Signature)
|
|
||||||
if err != nil {
|
|
||||||
// we don't want to return error if the message is not an Eth tx
|
|
||||||
r, s, v = ethtypes.EthBigIntZero, ethtypes.EthBigIntZero, ethtypes.EthBigIntZero
|
|
||||||
}
|
|
||||||
|
|
||||||
tx := ethtypes.EthTx{
|
|
||||||
Nonce: ethtypes.EthUint64(smsg.Message.Nonce),
|
|
||||||
ChainID: ethtypes.EthUint64(build.Eip155ChainId),
|
|
||||||
From: fromEthAddr,
|
|
||||||
To: toAddr,
|
|
||||||
Value: ethtypes.EthBigInt(smsg.Message.Value),
|
|
||||||
Type: ethtypes.EthUint64(2),
|
|
||||||
Input: input,
|
|
||||||
Gas: ethtypes.EthUint64(smsg.Message.GasLimit),
|
|
||||||
MaxFeePerGas: ethtypes.EthBigInt(smsg.Message.GasFeeCap),
|
|
||||||
MaxPriorityFeePerGas: ethtypes.EthBigInt(smsg.Message.GasPremium),
|
|
||||||
V: v,
|
|
||||||
R: r,
|
|
||||||
S: s,
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is an eth tx
|
// This is an eth tx
|
||||||
if smsg.Signature.Type == crypto.SigTypeDelegated {
|
if smsg.Signature.Type == crypto.SigTypeDelegated {
|
||||||
|
tx, err = ethtypes.EthTxFromSignedEthMessage(smsg)
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EthTx{}, xerrors.Errorf("failed to convert from signed message: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
tx.Hash, err = tx.TxHash()
|
tx.Hash, err = tx.TxHash()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx, err
|
return ethtypes.EthTx{}, xerrors.Errorf("failed to calculate hash for ethTx: %w", err)
|
||||||
}
|
}
|
||||||
} else if smsg.Signature.Type == crypto.SigTypeUnknown { // BLS Filecoin message
|
|
||||||
tx.Hash, err = ethtypes.EthHashFromCid(smsg.Message.Cid())
|
fromAddr, err := lookupEthAddress(ctx, smsg.Message.From, sa)
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EthTx{}, xerrors.Errorf("failed to resolve Ethereum address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.From = fromAddr
|
||||||
|
} else if smsg.Signature.Type == crypto.SigTypeSecp256k1 { // Secp Filecoin Message
|
||||||
|
tx = ethTxFromNativeMessage(ctx, smsg.VMMessage(), sa)
|
||||||
|
tx.Hash, err = ethtypes.EthHashFromCid(smsg.Cid())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx, err
|
return tx, err
|
||||||
}
|
}
|
||||||
} else { // Secp Filecoin Message
|
} else { // BLS Filecoin message
|
||||||
tx.Hash, err = ethtypes.EthHashFromCid(smsg.Cid())
|
tx = ethTxFromNativeMessage(ctx, smsg.VMMessage(), sa)
|
||||||
|
tx.Hash, err = ethtypes.EthHashFromCid(smsg.Message.Cid())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx, err
|
return tx, err
|
||||||
}
|
}
|
||||||
@ -1631,14 +1599,32 @@ func NewEthTxFromFilecoinMessage(ctx context.Context, smsg *types.SignedMessage,
|
|||||||
return tx, nil
|
return tx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// newEthTxFromFilecoinMessageLookup creates an ethereum transaction from filecoin message lookup. If a negative txIdx is passed
|
// ethTxFromNativeMessage does NOT populate:
|
||||||
// into the function, it looksup the transaction index of the message in the tipset, otherwise it uses the txIdx passed into the
|
// - BlockHash
|
||||||
// function
|
// - BlockNumber
|
||||||
func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLookup, txIdx int, cs *store.ChainStore, sa StateAPI) (ethtypes.EthTx, error) {
|
// - TransactionIndex
|
||||||
if msgLookup == nil {
|
// - Hash
|
||||||
return ethtypes.EthTx{}, fmt.Errorf("msg does not exist")
|
func ethTxFromNativeMessage(ctx context.Context, msg *types.Message, sa StateAPI) ethtypes.EthTx {
|
||||||
|
// We don't care if we error here, conversion is best effort for non-eth transactions
|
||||||
|
from, _ := lookupEthAddress(ctx, msg.From, sa)
|
||||||
|
to, _ := lookupEthAddress(ctx, msg.To, sa)
|
||||||
|
return ethtypes.EthTx{
|
||||||
|
To: &to,
|
||||||
|
From: from,
|
||||||
|
Nonce: ethtypes.EthUint64(msg.Nonce),
|
||||||
|
ChainID: ethtypes.EthUint64(build.Eip155ChainId),
|
||||||
|
Value: ethtypes.EthBigInt(msg.Value),
|
||||||
|
Type: ethtypes.Eip1559TxType,
|
||||||
|
Gas: ethtypes.EthUint64(msg.GasLimit),
|
||||||
|
MaxFeePerGas: ethtypes.EthBigInt(msg.GasFeeCap),
|
||||||
|
MaxPriorityFeePerGas: ethtypes.EthBigInt(msg.GasPremium),
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// newEthTxFromMessageLookup creates an ethereum transaction from filecoin message lookup. If a negative txIdx is passed
|
||||||
|
// into the function, it looks up the transaction index of the message in the tipset, otherwise it uses the txIdx passed into the
|
||||||
|
// function
|
||||||
|
func newEthTxFromMessageLookup(ctx context.Context, msgLookup *api.MsgLookup, txIdx int, cs *store.ChainStore, sa StateAPI) (ethtypes.EthTx, error) {
|
||||||
ts, err := cs.LoadTipSet(ctx, msgLookup.TipSet)
|
ts, err := cs.LoadTipSet(ctx, msgLookup.TipSet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EthTx{}, err
|
return ethtypes.EthTx{}, err
|
||||||
@ -1687,13 +1673,13 @@ func newEthTxFromFilecoinMessageLookup(ctx context.Context, msgLookup *api.MsgLo
|
|||||||
smsg = &types.SignedMessage{
|
smsg = &types.SignedMessage{
|
||||||
Message: *msg,
|
Message: *msg,
|
||||||
Signature: crypto.Signature{
|
Signature: crypto.Signature{
|
||||||
Type: crypto.SigTypeUnknown,
|
Type: crypto.SigTypeBLS,
|
||||||
Data: nil,
|
Data: nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tx, err := NewEthTxFromFilecoinMessage(ctx, smsg, sa)
|
tx, err := newEthTxFromSignedMessage(ctx, smsg, sa)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EthTx{}, err
|
return ethtypes.EthTx{}, err
|
||||||
}
|
}
|
||||||
@ -1739,16 +1725,6 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook
|
|||||||
LogsBloom: ethtypes.EmptyEthBloom[:],
|
LogsBloom: ethtypes.EmptyEthBloom[:],
|
||||||
}
|
}
|
||||||
|
|
||||||
if receipt.To == nil && lookup.Receipt.ExitCode.IsSuccess() {
|
|
||||||
// Create and Create2 return the same things.
|
|
||||||
var ret eam.CreateReturn
|
|
||||||
if err := ret.UnmarshalCBOR(bytes.NewReader(lookup.Receipt.Return)); err != nil {
|
|
||||||
return api.EthTxReceipt{}, xerrors.Errorf("failed to parse contract creation result: %w", err)
|
|
||||||
}
|
|
||||||
addr := ethtypes.EthAddress(ret.EthAddress)
|
|
||||||
receipt.ContractAddress = &addr
|
|
||||||
}
|
|
||||||
|
|
||||||
if lookup.Receipt.ExitCode.IsSuccess() {
|
if lookup.Receipt.ExitCode.IsSuccess() {
|
||||||
receipt.Status = 1
|
receipt.Status = 1
|
||||||
}
|
}
|
||||||
@ -1756,6 +1732,24 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook
|
|||||||
receipt.Status = 0
|
receipt.Status = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
receipt.GasUsed = ethtypes.EthUint64(lookup.Receipt.GasUsed)
|
||||||
|
|
||||||
|
// TODO: handle CumulativeGasUsed
|
||||||
|
receipt.CumulativeGasUsed = ethtypes.EmptyEthInt
|
||||||
|
|
||||||
|
effectiveGasPrice := big.Div(replay.GasCost.TotalCost, big.NewInt(lookup.Receipt.GasUsed))
|
||||||
|
receipt.EffectiveGasPrice = ethtypes.EthBigInt(effectiveGasPrice)
|
||||||
|
|
||||||
|
if receipt.To == nil && lookup.Receipt.ExitCode.IsSuccess() {
|
||||||
|
// Create and Create2 return the same things.
|
||||||
|
var ret eam.CreateExternalReturn
|
||||||
|
if err := ret.UnmarshalCBOR(bytes.NewReader(lookup.Receipt.Return)); err != nil {
|
||||||
|
return api.EthTxReceipt{}, xerrors.Errorf("failed to parse contract creation result: %w", err)
|
||||||
|
}
|
||||||
|
addr := ethtypes.EthAddress(ret.EthAddress)
|
||||||
|
receipt.ContractAddress = &addr
|
||||||
|
}
|
||||||
|
|
||||||
if len(events) > 0 {
|
if len(events) > 0 {
|
||||||
// TODO return a dummy non-zero bloom to signal that there are logs
|
// TODO return a dummy non-zero bloom to signal that there are logs
|
||||||
// need to figure out how worth it is to populate with a real bloom
|
// need to figure out how worth it is to populate with a real bloom
|
||||||
@ -1799,14 +1793,6 @@ func newEthTxReceipt(ctx context.Context, tx ethtypes.EthTx, lookup *api.MsgLook
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
receipt.GasUsed = ethtypes.EthUint64(lookup.Receipt.GasUsed)
|
|
||||||
|
|
||||||
// TODO: handle CumulativeGasUsed
|
|
||||||
receipt.CumulativeGasUsed = ethtypes.EmptyEthInt
|
|
||||||
|
|
||||||
effectiveGasPrice := big.Div(replay.GasCost.TotalCost, big.NewInt(lookup.Receipt.GasUsed))
|
|
||||||
receipt.EffectiveGasPrice = ethtypes.EthBigInt(effectiveGasPrice)
|
|
||||||
|
|
||||||
return receipt, nil
|
return receipt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1822,7 +1808,7 @@ func (m *EthTxHashManager) Apply(ctx context.Context, from, to *types.TipSet) er
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
hash, err := EthTxHashFromSignedFilecoinMessage(ctx, smsg, m.StateAPI)
|
hash, err := EthTxHashFromSignedMessage(ctx, smsg, m.StateAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -1859,7 +1845,7 @@ func WaitForMpoolUpdates(ctx context.Context, ch <-chan api.MpoolUpdate, manager
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
ethTx, err := NewEthTxFromFilecoinMessage(ctx, u.Message, manager.StateAPI)
|
ethTx, err := newEthTxFromSignedMessage(ctx, u.Message, manager.StateAPI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error converting filecoin message to eth tx: %s", err)
|
log.Errorf("error converting filecoin message to eth tx: %s", err)
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ func EthEventAPI(cfg config.FevmConfig) func(helpers.MetricsCtx, repo.LockedRepo
|
|||||||
ee := &full.EthEvent{
|
ee := &full.EthEvent{
|
||||||
Chain: cs,
|
Chain: cs,
|
||||||
MaxFilterHeightRange: abi.ChainEpoch(cfg.Events.MaxFilterHeightRange),
|
MaxFilterHeightRange: abi.ChainEpoch(cfg.Events.MaxFilterHeightRange),
|
||||||
|
SubscribtionCtx: ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !cfg.EnableEthRPC || cfg.Events.DisableRealTimeFilterAPI {
|
if !cfg.EnableEthRPC || cfg.Events.DisableRealTimeFilterAPI {
|
||||||
|
@ -75,7 +75,7 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server
|
|||||||
m := mux.NewRouter()
|
m := mux.NewRouter()
|
||||||
|
|
||||||
serveRpc := func(path string, hnd interface{}) {
|
serveRpc := func(path string, hnd interface{}) {
|
||||||
rpcServer := jsonrpc.NewServer(append(opts, jsonrpc.WithServerErrors(api.RPCErrors))...)
|
rpcServer := jsonrpc.NewServer(append(opts, jsonrpc.WithReverseClient[api.EthSubscriberMethods]("Filecoin"), jsonrpc.WithServerErrors(api.RPCErrors))...)
|
||||||
rpcServer.Register("Filecoin", hnd)
|
rpcServer.Register("Filecoin", hnd)
|
||||||
rpcServer.AliasMethod("rpc.discover", "Filecoin.Discover")
|
rpcServer.AliasMethod("rpc.discover", "Filecoin.Discover")
|
||||||
|
|
||||||
@ -94,8 +94,9 @@ func FullNodeHandler(a v1api.FullNode, permissioned bool, opts ...jsonrpc.Server
|
|||||||
fnapi = api.PermissionedFullAPI(fnapi)
|
fnapi = api.PermissionedFullAPI(fnapi)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var v0 v0api.FullNode = &(struct{ v0api.FullNode }{&v0api.WrapperV1Full{FullNode: fnapi}})
|
||||||
serveRpc("/rpc/v1", fnapi)
|
serveRpc("/rpc/v1", fnapi)
|
||||||
serveRpc("/rpc/v0", &v0api.WrapperV1Full{FullNode: fnapi})
|
serveRpc("/rpc/v0", v0)
|
||||||
|
|
||||||
// Import handler
|
// Import handler
|
||||||
handleImportFunc := handleImport(a.(*impl.FullNodeAPI))
|
handleImportFunc := handleImport(a.(*impl.FullNodeAPI))
|
||||||
|
12
scripts/docker-git-state-check.sh
Executable file
12
scripts/docker-git-state-check.sh
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$(git status --porcelain)" ]; then
|
||||||
|
echo "PASSED: Working directory clean"
|
||||||
|
else
|
||||||
|
echo "FAILED: Working directory not clean."
|
||||||
|
echo "This is likely because the .dockerignore file has removed something checked into git."
|
||||||
|
echo "Add the missing files listed below to the .dockerignore to fix this issue:"
|
||||||
|
echo "$(git status)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
@ -1 +0,0 @@
|
|||||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" viewBox="0 0 127 127" xml:space="preserve" enable-background="new 0 0 127 127"><style type="text/css">.st0{fill:#00d2d6}.st1{fill:#fff}</style><g><path class="st0" d="M63.5,127C28.5,127.1-0.2,98.4,0,63.2C0.2,28.3,28.6-0.2,63.9,0c34.8,0.2,63.3,28.7,63.1,64 C126.7,98.7,98.5,127.1,63.5,127z M71.4,57.6c5.5,0.8,11,1.5,16.5,2.3c0.5-1.7,0.9-3.1,1.3-4.7c-5.7-0.8-11.2-1.7-17.1-2.5 c2-7,3.7-13.7,5.8-20.2c0.7-2.2,2.3-4.2,3.9-5.9c2.1-2.2,5-1.7,6.8,0.7c0.7,1,1.4,2.1,2.3,2.9c1.1,1.1,2.8,1.6,4,0.6 c0.8-0.7,0.7-2.4,0.8-3.6c0-0.5-0.6-1.1-1-1.6c-2-2.3-4.7-3.1-7.5-3.2c-6.3-0.3-10.9,3-14.5,7.8c-3.5,4.8-5.1,10.5-6.8,16.2 c-0.5,1.6-0.9,3.3-1.4,5.1c-6.2-0.9-12.1-1.7-18.2-2.6c-0.2,1.6-0.4,3.2-0.6,4.8c6,0.9,11.8,1.8,17.8,2.7c-0.8,3.4-1.5,6.5-2.3,9.7 c-5.8-0.8-11.4-1.6-17-2.4c-0.2,1.8-0.4,3.2-0.6,4.8c5.6,0.9,11,1.7,16.5,2.5c0,0.6,0.1,1,0,1.3c-1.7,7.4-3.4,14.8-5.3,22.2 c-0.9,3.5-2.4,6.9-5.3,9.3c-2.4,2-5,1.7-6.8-0.8c-0.8-1.1-1.5-2.5-2.6-3.3c-0.8-0.6-2.5-0.9-3.1-0.5c-0.9,0.7-1.5,2.2-1.4,3.3 c0.1,1,1,2.2,1.9,2.8c3,2.3,6.5,2.6,10,1.9c5.9-1.2,10.1-4.9,12.7-10.1c2-4.1,3.6-8.5,5-12.9c1.3-4,2.2-8,3.3-12.2 c5.8,0.8,11.5,1.7,17.3,2.5c0.5-1.7,0.9-3.2,1.4-4.8c-6.1-0.9-11.9-1.7-17.7-2.6C70.1,64,70.7,60.9,71.4,57.6z"/><path class="st1" d="M71.4,57.6c-0.7,3.3-1.3,6.4-2,9.8c5.9,0.9,11.7,1.7,17.7,2.6c-0.5,1.6-0.9,3.1-1.4,4.8 c-5.8-0.8-11.5-1.7-17.3-2.5c-1.1,4.2-2,8.3-3.3,12.2c-1.4,4.4-3,8.7-5,12.9c-2.6,5.2-6.8,8.9-12.7,10.1c-3.5,0.7-7,0.4-10-1.9 c-0.9-0.7-1.8-1.8-1.9-2.8c-0.1-1.1,0.5-2.7,1.4-3.3c0.6-0.5,2.3-0.1,3.1,0.5c1.1,0.8,1.8,2.1,2.6,3.3c1.8,2.5,4.4,2.9,6.8,0.8 c2.9-2.5,4.4-5.8,5.3-9.3c1.9-7.3,3.6-14.8,5.3-22.2c0.1-0.3,0-0.7,0-1.3c-5.4-0.8-10.8-1.7-16.5-2.5c0.2-1.6,0.4-3,0.6-4.8 c5.6,0.8,11.1,1.6,17,2.4c0.8-3.2,1.5-6.4,2.3-9.7c-6-0.9-11.7-1.8-17.8-2.7c0.2-1.6,0.4-3.2,0.6-4.8c6.1,0.9,12,1.7,18.2,2.6 c0.5-1.8,0.9-3.5,1.4-5.1c1.7-5.6,3.2-11.3,6.8-16.2c3.6-4.9,8.1-8.1,14.5-7.8c2.8,0.1,5.5,0.9,7.5,3.2c0.4,0.5,1,1.1,1,1.6 c-0.1,1.2,0,2.9-0.8,3.6c-1.1,1.1-2.8,0.5-4-0.6c-0.9-0.9-1.6-1.9-2.3-2.9c-1.8-2.4-4.7-2.9-6.8-0.7c-1.6,1.7-3.2,3.7-3.9,5.9 C75.7,39.4,74,46,72,53c5.9,0.9,11.4,1.7,17.1,2.5c-0.5,1.6-0.9,3.1-1.3,4.7C82.3,59.1,76.9,58.3,71.4,57.6z"/></g></svg>
|
|
Before Width: | Height: | Size: 2.2 KiB |
@ -1,96 +0,0 @@
|
|||||||
name: lotus-filecoin
|
|
||||||
base: core20
|
|
||||||
version: latest
|
|
||||||
summary: filecoin daemon/client
|
|
||||||
icon: snap/local/icon.svg
|
|
||||||
description: |
|
|
||||||
Filecoin is a peer-to-peer network that stores files on the internet
|
|
||||||
with built-in economic incentives to ensure files are stored reliably over time
|
|
||||||
|
|
||||||
For documentation and additional information, please see the following resources
|
|
||||||
|
|
||||||
https://filecoin.io
|
|
||||||
|
|
||||||
https://fil.org
|
|
||||||
|
|
||||||
https://lotus.filecoin.io
|
|
||||||
|
|
||||||
https://github.com/filecoin-project/lotus
|
|
||||||
|
|
||||||
confinement: strict
|
|
||||||
|
|
||||||
parts:
|
|
||||||
lotus:
|
|
||||||
plugin: make
|
|
||||||
source: ./
|
|
||||||
build-snaps:
|
|
||||||
- go
|
|
||||||
- rustup
|
|
||||||
build-packages:
|
|
||||||
- git
|
|
||||||
- jq
|
|
||||||
- libhwloc-dev
|
|
||||||
- ocl-icd-opencl-dev
|
|
||||||
- pkg-config
|
|
||||||
stage-packages:
|
|
||||||
- libhwloc15
|
|
||||||
- ocl-icd-libopencl1
|
|
||||||
override-build: |
|
|
||||||
LDFLAGS="" make lotus lotus-miner lotus-worker
|
|
||||||
cp lotus lotus-miner lotus-worker $SNAPCRAFT_PART_INSTALL
|
|
||||||
cp scripts/snap-lotus-entrypoint.sh $SNAPCRAFT_PART_INSTALL
|
|
||||||
|
|
||||||
layout:
|
|
||||||
/var/lib/lotus:
|
|
||||||
symlink: $SNAP_COMMON/lotus
|
|
||||||
/var/lib/lotus-miner:
|
|
||||||
symlink: $SNAP_COMMON/lotus-miner
|
|
||||||
/var/lib/lotus-worker:
|
|
||||||
symlink: $SNAP_COMMON/lotus-worker
|
|
||||||
|
|
||||||
apps:
|
|
||||||
lotus:
|
|
||||||
command: lotus
|
|
||||||
plugs:
|
|
||||||
- network
|
|
||||||
- network-bind
|
|
||||||
- home
|
|
||||||
environment:
|
|
||||||
FIL_PROOFS_PARAMETER_CACHE: $SNAP_USER_COMMON/filecoin-proof-parameters
|
|
||||||
LOTUS_PATH: $SNAP_COMMON/lotus
|
|
||||||
LOTUS_MINER_PATH: $SNAP_COMMON/lotus-miner
|
|
||||||
LOTUS_WORKER_PATH: $SNAP_COMMON/lotus-worker
|
|
||||||
lotus-miner:
|
|
||||||
command: lotus-miner
|
|
||||||
plugs:
|
|
||||||
- network
|
|
||||||
- network-bind
|
|
||||||
- opengl
|
|
||||||
environment:
|
|
||||||
FIL_PROOFS_PARAMETER_CACHE: $SNAP_USER_COMMON/filecoin-proof-parameters
|
|
||||||
LOTUS_PATH: $SNAP_COMMON/lotus
|
|
||||||
LOTUS_MINER_PATH: $SNAP_COMMON/lotus-miner
|
|
||||||
LOTUS_WORKER_PATH: $SNAP_COMMON/lotus-worker
|
|
||||||
lotus-worker:
|
|
||||||
command: lotus-worker
|
|
||||||
plugs:
|
|
||||||
- network
|
|
||||||
- network-bind
|
|
||||||
- opengl
|
|
||||||
environment:
|
|
||||||
FIL_PROOFS_PARAMETER_CACHE: $SNAP_USER_COMMON/filecoin-proof-parameters
|
|
||||||
LOTUS_PATH: $SNAP_COMMON/lotus
|
|
||||||
LOTUS_MINER_PATH: $SNAP_COMMON/lotus-miner
|
|
||||||
LOTUS_WORKER_PATH: $SNAP_COMMON/lotus-worker
|
|
||||||
lotus-daemon:
|
|
||||||
command: snap-lotus-entrypoint.sh
|
|
||||||
daemon: simple
|
|
||||||
install-mode: disable
|
|
||||||
plugs:
|
|
||||||
- network
|
|
||||||
- network-bind
|
|
||||||
environment:
|
|
||||||
FIL_PROOFS_PARAMETER_CACHE: $SNAP_COMMON/filecoin-proof-parameters
|
|
||||||
LOTUS_PATH: $SNAP_COMMON/lotus
|
|
||||||
LOTUS_MINER_PATH: $SNAP_COMMON/lotus-miner
|
|
||||||
LOTUS_WORKER_PATH: $SNAP_COMMON/lotus-worker
|
|
Loading…
Reference in New Issue
Block a user