Merge remote-tracking branch 'origin/master' into hsanjuan/chain-export-range-rebased
This commit is contained in:
commit
ea57a1aec3
@ -674,6 +674,12 @@ workflows:
|
|||||||
- build
|
- build
|
||||||
suite: itest-eth_account_abstraction
|
suite: itest-eth_account_abstraction
|
||||||
target: "./itests/eth_account_abstraction_test.go"
|
target: "./itests/eth_account_abstraction_test.go"
|
||||||
|
- test:
|
||||||
|
name: test-itest-eth_api
|
||||||
|
requires:
|
||||||
|
- build
|
||||||
|
suite: itest-eth_api
|
||||||
|
target: "./itests/eth_api_test.go"
|
||||||
- test:
|
- test:
|
||||||
name: test-itest-eth_balance
|
name: test-itest-eth_balance
|
||||||
requires:
|
requires:
|
||||||
|
50
CHANGELOG.md
50
CHANGELOG.md
@ -1,5 +1,55 @@
|
|||||||
# Lotus changelog
|
# Lotus changelog
|
||||||
|
|
||||||
|
# 1.20.0-rc1 / 2023-02-14
|
||||||
|
|
||||||
|
This is the first release candidate for the upcoming MANDATORY 1.20.0 release of Lotus. This release will deliver the Hygge network upgrade, introducing Filecoin network version 18. The centerpiece of the upgrade is the introduction of the [Filecoin Virtual Machine (FVM)’s Milestone 2.1](https://fvm.filecoin.io/), which will allow for EVM-compatible contracts to be deployed on the Filecoin network. This upgrade delivers user-programmablity to the Filecoin network for the first time!
|
||||||
|
|
||||||
|
Note that this release candidate does NOT set the epoch at which mainnet will upgrade; that detail will be finalized in the 1.20.0 release.
|
||||||
|
|
||||||
|
The Hygge upgrade introduces the following Filecoin Improvement Proposals (FIPs), delivered in FVM3 (see FVM [v3.0.0-rc.1](https://github.com/filecoin-project/ref-fvm/pull/1664)) and builtin-actors v10 (see actors [v1.10.0-rc.1](https://github.com/filecoin-project/builtin-actors/releases/tag/v10.0.0-rc.1)):
|
||||||
|
|
||||||
|
- [FIP-0048](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0048.md): f4 Address Class
|
||||||
|
- [FIP-0049](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0049.md): Actor events
|
||||||
|
- [FIP-0050](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0050.md): API between user-programmed actors and built-in actors
|
||||||
|
- [FIP-0054](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0054.md): Filecoin EVM runtime (FEVM)
|
||||||
|
- [FIP-0055](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0055.md): Supporting Ethereum Accounts, Addresses, and Transactions
|
||||||
|
- [FIP-0057](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0057.md): Update gas charging schedule and system limits for FEVM
|
||||||
|
|
||||||
|
## Filecoin Ethereum Virtual Machine (FEVM)
|
||||||
|
|
||||||
|
The Filecoin Ethereum Virtual Machine (FEVM) is built on top of the WASM-based execution environment introduced in the Skyr v16 upgrade. The chief feature introduced is the ability for anyone participating in the Filecoin network to deploy their own EVM-compatible contracts onto the blockchain, and invoke them as appropriate.
|
||||||
|
|
||||||
|
## New Built-in Actors
|
||||||
|
|
||||||
|
The FEVM is principally delivered through the introduction of **the new [EVM actor](https://github.com/filecoin-project/builtin-actors/tree/master/actors/evm)**. This actor “represents” smart contracts on the Filecoin network, and includes an interpreter that implements all EVM opcodes as their Filecoin equivalents, and translates state I/O operations to be compatible with Filecoin’s IPLD-based data model. For more on the EVM actors, please see [FIP-0054](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0054.md).
|
||||||
|
|
||||||
|
The creation of EVM actors is managed by **the new** [Ethereum Address Manager actor (EAM)](https://github.com/filecoin-project/builtin-actors/tree/master/actors/eam), a singleton that is invoked in order to deploy EVM actors. In order to make usage of the FEVM as seamless as possible for users familiar with the Ethereum ecosystem, this upgrades also introduces **a dedicated actor to serve as “[Ethereum Accounts](https://github.com/filecoin-project/builtin-actors/tree/master/actors/ethaccount)”**. This actor exists to allow for secp keys to be used in the Ethereum addressing scheme. **The last new built-in actor introduced is [the Placeholder actor](https://github.com/filecoin-project/builtin-actors/tree/master/actors/placeholder)**, a thin “shell” of an actor that can transform into either EVM or EthAccount actors. For more on the EAM, EthAccount, and Placeholder actors, please see [FIP-0055](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0055.md).
|
||||||
|
|
||||||
|
## Calibration nv18 Hygge Upgrade
|
||||||
|
|
||||||
|
This release candidate sets the calibration-net nv18 Hygge upgrade at epoch 322354, 22023-02-21T16:30:00Z. The bundle the network will be using is [v10.0.0 actors](https://github.com/filecoin-project/builtin-actors/releases/tag/v10.0.0-rc.1)
|
||||||
|
(located at `build/actors/v10.tar.zst`) upon/post migration, manifest CID `bafy2bzaced25ta3j6ygs34roprilbtb3f6mxifyfnm7z7ndquaruxzdq3y7lo`.
|
||||||
|
|
||||||
|
## Node Operators
|
||||||
|
|
||||||
|
FVM has been running in lotus since v1.16.0 and up, and the new FEVM does not increase any node hardware spec requirement.
|
||||||
|
|
||||||
|
With FEVM on Filecoin, we aim to provide full compatibility with the existing EVM ecosystem and its tooling out of box and thus, lotus now provides a full set of [Ethereum-styled APIs](https://github.com/filecoin-project/lotus/blob/release/v1.20.0/node/impl/full/eth.go) for developers and token holders to interact with the Filecoin network as well.
|
||||||
|
|
||||||
|
**Enable Ethereum JSON RPC API**
|
||||||
|
|
||||||
|
Note that Ethereum APIs are only supported in the lotus v1 API, meaning that any node operator who wants to enable Eth API services must be using the v1 API, instead of the v0 API. To enable Eth RPC, simply set `EnableEthRPC` to `true` in your node config.toml file; or set env var `LOTUS_FEVM_ENABLEETHRPC` to `1` before starting your lotus node.
|
||||||
|
|
||||||
|
**Eth tx hash and Filecoin message CID**
|
||||||
|
|
||||||
|
Most of the Eth APIs take Eth accounts and tx has as an input, and they start with `0x` , and that is what Ethereum tooling support. However, in Filecoin, we have Filecoin account formats where things start with `f` (`f410` specifically for eth accounts on Filecoin) and the messages are in the format of CIDs. To enable a smooth developer experience, Lotus internally converts between Ethereum address and Filecoin account address as needed. In addition, lotus also keeps a Eth tx hash <> Filecoin message CID map and stores them in a SQLite database as node sees a FEVM messages. The database is initiated and the maps are populated automatically in `~/<lotus_repo>/sqlite/txhash.db` for any node that as Eth RPC enabled. Node operators can configure how many historical mappings they wanna store by configuring `EthTxHashMappingLifetimeDays` .
|
||||||
|
|
||||||
|
**Events***
|
||||||
|
|
||||||
|
[FIP-0049 introduces actor events](https://github.com/filecoin-project/FIPs/blob/master/FIPS/fip-0049.md) that can be emitted and externally observable during message execution. An `events.db` is created automatically under `~/<lotus_repo>/sqlite` to store these events if the node has Eth RPC enabled. Node operators can configure the events support base on their needs by configuration `Events` configurations.
|
||||||
|
|
||||||
|
Note: All three features are new and we welcome user feedbacks, create an issue if you have any enhancements that you’d like to see!
|
||||||
|
|
||||||
# 1.19.0 / 2022-12-07
|
# 1.19.0 / 2022-12-07
|
||||||
|
|
||||||
This is an optional feature release of Lotus. This feature release includes the SplitStore beta, the experimental Lotus node cluster feature, as well as numerous enhancments and bugfixes.
|
This is an optional feature release of Lotus. This feature release includes the SplitStore beta, the experimental Lotus node cluster feature, as well as numerous enhancments and bugfixes.
|
||||||
|
2
Makefile
2
Makefile
@ -298,7 +298,7 @@ actors-gen: actors-code-gen fiximports
|
|||||||
.PHONY: actors-gen
|
.PHONY: actors-gen
|
||||||
|
|
||||||
bundle-gen:
|
bundle-gen:
|
||||||
$(GOCC) run ./gen/bundle $(RELEASE)
|
$(GOCC) run ./gen/bundle $(VERSION) $(RELEASE) $(RELEASE_OVERRIDES)
|
||||||
$(GOCC) fmt ./build/...
|
$(GOCC) fmt ./build/...
|
||||||
.PHONY: bundle-gen
|
.PHONY: bundle-gen
|
||||||
|
|
||||||
|
@ -779,6 +779,8 @@ type FullNode interface {
|
|||||||
//
|
//
|
||||||
// EthAccounts will always return [] since we don't expect Lotus to manage private keys
|
// EthAccounts will always return [] since we don't expect Lotus to manage private keys
|
||||||
EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) //perm:read
|
EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) //perm:read
|
||||||
|
// EthAddressToFilecoinAddress converts an EthAddress into an f410 Filecoin Address
|
||||||
|
EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) //perm:read
|
||||||
// EthBlockNumber returns the height of the latest (heaviest) TipSet
|
// EthBlockNumber returns the height of the latest (heaviest) TipSet
|
||||||
EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) //perm:read
|
EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) //perm:read
|
||||||
// EthGetBlockTransactionCountByNumber returns the number of messages in the TipSet
|
// EthGetBlockTransactionCountByNumber returns the number of messages in the TipSet
|
||||||
|
@ -967,6 +967,21 @@ func (mr *MockFullNodeMockRecorder) EthAccounts(arg0 interface{}) *gomock.Call {
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthAccounts", reflect.TypeOf((*MockFullNode)(nil).EthAccounts), arg0)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthAccounts", reflect.TypeOf((*MockFullNode)(nil).EthAccounts), arg0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EthAddressToFilecoinAddress mocks base method.
|
||||||
|
func (m *MockFullNode) EthAddressToFilecoinAddress(arg0 context.Context, arg1 ethtypes.EthAddress) (address.Address, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "EthAddressToFilecoinAddress", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(address.Address)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// EthAddressToFilecoinAddress indicates an expected call of EthAddressToFilecoinAddress.
|
||||||
|
func (mr *MockFullNodeMockRecorder) EthAddressToFilecoinAddress(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthAddressToFilecoinAddress", reflect.TypeOf((*MockFullNode)(nil).EthAddressToFilecoinAddress), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// EthBlockNumber mocks base method.
|
// EthBlockNumber mocks base method.
|
||||||
func (m *MockFullNode) EthBlockNumber(arg0 context.Context) (ethtypes.EthUint64, error) {
|
func (m *MockFullNode) EthBlockNumber(arg0 context.Context) (ethtypes.EthUint64, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -117,7 +117,7 @@ type EthSubscriberStruct struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EthSubscriberMethods struct {
|
type EthSubscriberMethods struct {
|
||||||
EthSubscription func(p0 context.Context, p1 jsonrpc.RawParams) error `notify:"true"rpc_method:"eth_subscription"`
|
EthSubscription func(p0 context.Context, p1 jsonrpc.RawParams) error `notify:"true" rpc_method:"eth_subscription"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EthSubscriberStub struct {
|
type EthSubscriberStub struct {
|
||||||
@ -246,6 +246,8 @@ type FullNodeMethods struct {
|
|||||||
|
|
||||||
EthAccounts func(p0 context.Context) ([]ethtypes.EthAddress, error) `perm:"read"`
|
EthAccounts func(p0 context.Context) ([]ethtypes.EthAddress, error) `perm:"read"`
|
||||||
|
|
||||||
|
EthAddressToFilecoinAddress func(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) `perm:"read"`
|
||||||
|
|
||||||
EthBlockNumber func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"`
|
EthBlockNumber func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"`
|
||||||
|
|
||||||
EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) `perm:"read"`
|
EthCall func(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) `perm:"read"`
|
||||||
@ -2020,6 +2022,17 @@ func (s *FullNodeStub) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, e
|
|||||||
return *new([]ethtypes.EthAddress), ErrNotSupported
|
return *new([]ethtypes.EthAddress), ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStruct) EthAddressToFilecoinAddress(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) {
|
||||||
|
if s.Internal.EthAddressToFilecoinAddress == nil {
|
||||||
|
return *new(address.Address), ErrNotSupported
|
||||||
|
}
|
||||||
|
return s.Internal.EthAddressToFilecoinAddress(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStub) EthAddressToFilecoinAddress(p0 context.Context, p1 ethtypes.EthAddress) (address.Address, error) {
|
||||||
|
return *new(address.Address), ErrNotSupported
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FullNodeStruct) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) {
|
func (s *FullNodeStruct) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) {
|
||||||
if s.Internal.EthBlockNumber == nil {
|
if s.Internal.EthBlockNumber == nil {
|
||||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||||
|
@ -52,4 +52,4 @@ popd
|
|||||||
|
|
||||||
echo "Generating metadata..."
|
echo "Generating metadata..."
|
||||||
|
|
||||||
make -C ../../ RELEASE="$RELEASE" bundle-gen
|
make -C ../../ VERSION="$VERSION" RELEASE="$RELEASE" RELEASE_OVERRIDES="${RELEASE_OVERRIDES[*]}" bundle-gen
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWHkVVMJ1rfVLM5poNrgwTJiaDkpDLkPqQ9zVuNPQ7AJ6p
|
/dns4/bootstrap-0.butterfly.fildev.network/tcp/1347/p2p/12D3KooWCa1wgMMBB9JjA2kYqaN1v5uh7xvcsc2gQJBHzPp7G57H
|
||||||
/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWRyzqeQd51HCvVK3nvegmnBsYYPLSZbxR3Q9XAoUrUZ18
|
/dns4/bootstrap-1.butterfly.fildev.network/tcp/1347/p2p/12D3KooWD6fCvo1dyci6wsjTLyv7eJK73pCVz6RCQjbtPvbc8LYw
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -4,7 +4,6 @@
|
|||||||
package build
|
package build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -71,7 +70,8 @@ const UpgradeSkyrHeight = 510
|
|||||||
|
|
||||||
const UpgradeSharkHeight = 16800 // 6 days after genesis
|
const UpgradeSharkHeight = 16800 // 6 days after genesis
|
||||||
|
|
||||||
const UpgradeHyggeHeight = math.MaxInt64
|
// 2023-02-21T16:30:00Z
|
||||||
|
const UpgradeHyggeHeight = 322354
|
||||||
|
|
||||||
var SupportedProofTypes = []abi.RegisteredSealProof{
|
var SupportedProofTypes = []abi.RegisteredSealProof{
|
||||||
abi.RegisteredSealProof_StackedDrg32GiBV1,
|
abi.RegisteredSealProof_StackedDrg32GiBV1,
|
||||||
|
@ -48,6 +48,7 @@ type State interface {
|
|||||||
cbor.Marshaler
|
cbor.Marshaler
|
||||||
|
|
||||||
Nonce() (uint64, error)
|
Nonce() (uint64, error)
|
||||||
|
IsAlive() (bool, error)
|
||||||
GetState() interface{}
|
GetState() interface{}
|
||||||
|
|
||||||
GetBytecode() ([]byte, error)
|
GetBytecode() ([]byte, error)
|
||||||
|
@ -48,6 +48,7 @@ type State interface {
|
|||||||
cbor.Marshaler
|
cbor.Marshaler
|
||||||
|
|
||||||
Nonce() (uint64, error)
|
Nonce() (uint64, error)
|
||||||
|
IsAlive() (bool, error)
|
||||||
GetState() interface{}
|
GetState() interface{}
|
||||||
|
|
||||||
GetBytecode() ([]byte, error)
|
GetBytecode() ([]byte, error)
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||||
|
"github.com/filecoin-project/go-state-types/abi"
|
||||||
|
|
||||||
evm{{.v}} "github.com/filecoin-project/go-state-types/builtin{{.import}}evm"
|
evm{{.v}} "github.com/filecoin-project/go-state-types/builtin{{.import}}evm"
|
||||||
)
|
)
|
||||||
@ -40,6 +42,10 @@ func (s *state{{.v}}) Nonce() (uint64, error) {
|
|||||||
return s.State.Nonce, nil
|
return s.State.Nonce, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *state{{.v}}) IsAlive() (bool, error) {
|
||||||
|
return s.State.Tombstone == nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *state{{.v}}) GetState() interface{} {
|
func (s *state{{.v}}) GetState() interface{} {
|
||||||
return &s.State
|
return &s.State
|
||||||
}
|
}
|
||||||
|
4
chain/actors/builtin/evm/v10.go
generated
4
chain/actors/builtin/evm/v10.go
generated
@ -41,6 +41,10 @@ func (s *state10) Nonce() (uint64, error) {
|
|||||||
return s.State.Nonce, nil
|
return s.State.Nonce, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *state10) IsAlive() (bool, error) {
|
||||||
|
return s.State.Tombstone == nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *state10) GetState() interface{} {
|
func (s *state10) GetState() interface{} {
|
||||||
return &s.State
|
return &s.State
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,10 @@ var ErrExpensiveFork = errors.New("refusing explicit call due to state fork at e
|
|||||||
// tipset's parent. In the presence of null blocks, the height at which the message is invoked may
|
// tipset's parent. In the presence of null blocks, the height at which the message is invoked may
|
||||||
// be less than the specified tipset.
|
// be less than the specified tipset.
|
||||||
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
|
func (sm *StateManager) Call(ctx context.Context, msg *types.Message, ts *types.TipSet) (*api.InvocResult, error) {
|
||||||
|
// Copy the message as we modify it below.
|
||||||
|
msgCopy := *msg
|
||||||
|
msg = &msgCopy
|
||||||
|
|
||||||
if msg.GasLimit == 0 {
|
if msg.GasLimit == 0 {
|
||||||
msg.GasLimit = build.BlockGasLimit
|
msg.GasLimit = build.BlockGasLimit
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,9 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"os"
|
||||||
"sort"
|
"sort"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -26,6 +28,9 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/vm"
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// EnvDisablePreMigrations when set to '1' stops pre-migrations from running
|
||||||
|
const EnvDisablePreMigrations = "LOTUS_DISABLE_PRE_MIGRATIONS"
|
||||||
|
|
||||||
// MigrationCache can be used to cache information used by a migration. This is primarily useful to
|
// MigrationCache can be used to cache information used by a migration. This is primarily useful to
|
||||||
// "pre-compute" some migration state ahead of time, and make it accessible in the migration itself.
|
// "pre-compute" some migration state ahead of time, and make it accessible in the migration itself.
|
||||||
type MigrationCache interface {
|
type MigrationCache interface {
|
||||||
@ -218,6 +223,11 @@ func runPreMigration(ctx context.Context, sm *StateManager, fn PreMigrationFunc,
|
|||||||
height := ts.Height()
|
height := ts.Height()
|
||||||
parent := ts.ParentState()
|
parent := ts.ParentState()
|
||||||
|
|
||||||
|
if disabled := os.Getenv(EnvDisablePreMigrations); strings.TrimSpace(disabled) == "1" {
|
||||||
|
log.Warnw("SKIPPING pre-migration", "height", height)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
|
|
||||||
log.Warn("STARTING pre-migration")
|
log.Warn("STARTING pre-migration")
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -535,3 +536,70 @@ func TestForkPreMigration(t *testing.T) {
|
|||||||
// to this channel.
|
// to this channel.
|
||||||
require.Equal(t, 6, len(counter))
|
require.Equal(t, 6, len(counter))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDisablePreMigration(t *testing.T) {
|
||||||
|
logging.SetAllLoggers(logging.LevelInfo)
|
||||||
|
|
||||||
|
cg, err := gen.NewGenerator()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
err = os.Setenv(EnvDisablePreMigrations, "1")
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
err := os.Unsetenv(EnvDisablePreMigrations)
|
||||||
|
require.NoError(t, err)
|
||||||
|
}()
|
||||||
|
|
||||||
|
counter := make(chan struct{}, 10)
|
||||||
|
|
||||||
|
sm, err := NewStateManager(
|
||||||
|
cg.ChainStore(),
|
||||||
|
consensus.NewTipSetExecutor(filcns.RewardFunc),
|
||||||
|
cg.StateManager().VMSys(),
|
||||||
|
UpgradeSchedule{{
|
||||||
|
Network: network.Version1,
|
||||||
|
Height: testForkHeight,
|
||||||
|
Migration: func(_ context.Context, _ *StateManager, _ MigrationCache, _ ExecMonitor,
|
||||||
|
root cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) (cid.Cid, error) {
|
||||||
|
|
||||||
|
counter <- struct{}{}
|
||||||
|
|
||||||
|
return root, nil
|
||||||
|
},
|
||||||
|
PreMigrations: []PreMigration{{
|
||||||
|
StartWithin: 20,
|
||||||
|
PreMigration: func(ctx context.Context, _ *StateManager, _ MigrationCache,
|
||||||
|
_ cid.Cid, _ abi.ChainEpoch, _ *types.TipSet) error {
|
||||||
|
panic("should be skipped")
|
||||||
|
},
|
||||||
|
}}},
|
||||||
|
},
|
||||||
|
cg.BeaconSchedule(),
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NoError(t, sm.Start(context.Background()))
|
||||||
|
defer func() {
|
||||||
|
require.NoError(t, sm.Stop(context.Background()))
|
||||||
|
}()
|
||||||
|
|
||||||
|
inv := consensus.NewActorRegistry()
|
||||||
|
registry := builtin.MakeRegistryLegacy([]rtt.VMActor{testActor{}})
|
||||||
|
inv.Register(actorstypes.Version0, nil, registry)
|
||||||
|
|
||||||
|
sm.SetVMConstructor(func(ctx context.Context, vmopt *vm.VMOpts) (vm.Interface, error) {
|
||||||
|
nvm, err := vm.NewLegacyVM(ctx, vmopt)
|
||||||
|
require.NoError(t, err)
|
||||||
|
nvm.SetInvoker(inv)
|
||||||
|
return nvm, nil
|
||||||
|
})
|
||||||
|
|
||||||
|
cg.SetStateManager(sm)
|
||||||
|
|
||||||
|
for i := 0; i < 50; i++ {
|
||||||
|
_, err := cg.NextTipSet()
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.Equal(t, 1, len(counter))
|
||||||
|
}
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
gocrypto "github.com/filecoin-project/go-crypto"
|
gocrypto "github.com/filecoin-project/go-crypto"
|
||||||
|
"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"
|
||||||
typescrypto "github.com/filecoin-project/go-state-types/crypto"
|
typescrypto "github.com/filecoin-project/go-state-types/crypto"
|
||||||
@ -38,11 +39,19 @@ type EthTx struct {
|
|||||||
MaxFeePerGas EthBigInt `json:"maxFeePerGas"`
|
MaxFeePerGas EthBigInt `json:"maxFeePerGas"`
|
||||||
MaxPriorityFeePerGas EthBigInt `json:"maxPriorityFeePerGas"`
|
MaxPriorityFeePerGas EthBigInt `json:"maxPriorityFeePerGas"`
|
||||||
AccessList []EthHash `json:"accessList"`
|
AccessList []EthHash `json:"accessList"`
|
||||||
V EthBigInt `json:"yParity"`
|
V EthBigInt `json:"v"`
|
||||||
R EthBigInt `json:"r"`
|
R EthBigInt `json:"r"`
|
||||||
S EthBigInt `json:"s"`
|
S EthBigInt `json:"s"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tx *EthTx) Reward(blkBaseFee big.Int) EthBigInt {
|
||||||
|
availablePriorityFee := big.Sub(big.Int(tx.MaxFeePerGas), blkBaseFee)
|
||||||
|
if big.Cmp(big.Int(tx.MaxPriorityFeePerGas), availablePriorityFee) <= 0 {
|
||||||
|
return tx.MaxPriorityFeePerGas
|
||||||
|
}
|
||||||
|
return EthBigInt(availablePriorityFee)
|
||||||
|
}
|
||||||
|
|
||||||
type EthTxArgs struct {
|
type EthTxArgs struct {
|
||||||
ChainID int `json:"chainId"`
|
ChainID int `json:"chainId"`
|
||||||
Nonce int `json:"nonce"`
|
Nonce int `json:"nonce"`
|
||||||
@ -97,24 +106,31 @@ func EthTxFromSignedEthMessage(smsg *types.SignedMessage) (EthTx, error) {
|
|||||||
|
|
||||||
func EthTxArgsFromUnsignedEthMessage(msg *types.Message) (EthTxArgs, error) {
|
func EthTxArgsFromUnsignedEthMessage(msg *types.Message) (EthTxArgs, error) {
|
||||||
var (
|
var (
|
||||||
to *EthAddress
|
to *EthAddress
|
||||||
params []byte
|
params []byte
|
||||||
paramsReader = bytes.NewReader(msg.Params)
|
err error
|
||||||
err error
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if msg.Version != 0 {
|
if msg.Version != 0 {
|
||||||
return EthTxArgs{}, xerrors.Errorf("unsupported msg version: %d", msg.Version)
|
return EthTxArgs{}, xerrors.Errorf("unsupported msg version: %d", msg.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(msg.Params) > 0 {
|
||||||
|
paramsReader := bytes.NewReader(msg.Params)
|
||||||
|
params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params)))
|
||||||
|
if err != nil {
|
||||||
|
return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err)
|
||||||
|
}
|
||||||
|
if paramsReader.Len() != 0 {
|
||||||
|
return EthTxArgs{}, xerrors.Errorf("extra data found in params")
|
||||||
|
}
|
||||||
|
if len(params) == 0 {
|
||||||
|
return EthTxArgs{}, xerrors.Errorf("non-empty params encode empty byte array")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
|
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
|
||||||
switch msg.Method {
|
if msg.Method != builtintypes.MethodsEAM.CreateExternal {
|
||||||
case builtintypes.MethodsEAM.CreateExternal:
|
|
||||||
params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params)))
|
|
||||||
if err != nil {
|
|
||||||
return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return EthTxArgs{}, fmt.Errorf("unsupported EAM method")
|
return EthTxArgs{}, fmt.Errorf("unsupported EAM method")
|
||||||
}
|
}
|
||||||
} else if msg.Method == builtintypes.MethodsEVM.InvokeContract {
|
} else if msg.Method == builtintypes.MethodsEVM.InvokeContract {
|
||||||
@ -123,23 +139,12 @@ func EthTxArgsFromUnsignedEthMessage(msg *types.Message) (EthTxArgs, error) {
|
|||||||
return EthTxArgs{}, err
|
return EthTxArgs{}, err
|
||||||
}
|
}
|
||||||
to = &addr
|
to = &addr
|
||||||
|
|
||||||
if len(msg.Params) > 0 {
|
|
||||||
params, err = cbg.ReadByteArray(paramsReader, uint64(len(msg.Params)))
|
|
||||||
if err != nil {
|
|
||||||
return EthTxArgs{}, xerrors.Errorf("failed to read params byte array: %w", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return EthTxArgs{},
|
return EthTxArgs{},
|
||||||
xerrors.Errorf("invalid methodnum %d: only allowed method is InvokeContract(%d)",
|
xerrors.Errorf("invalid methodnum %d: only allowed method is InvokeContract(%d)",
|
||||||
msg.Method, builtintypes.MethodsEVM.InvokeContract)
|
msg.Method, builtintypes.MethodsEVM.InvokeContract)
|
||||||
}
|
}
|
||||||
|
|
||||||
if paramsReader.Len() != 0 {
|
|
||||||
return EthTxArgs{}, xerrors.Errorf("extra data found in params")
|
|
||||||
}
|
|
||||||
|
|
||||||
return EthTxArgs{
|
return EthTxArgs{
|
||||||
ChainID: build.Eip155ChainId,
|
ChainID: build.Eip155ChainId,
|
||||||
Nonce: int(msg.Nonce),
|
Nonce: int(msg.Nonce),
|
||||||
@ -159,34 +164,26 @@ func (tx *EthTxArgs) ToUnsignedMessage(from address.Address) (*types.Message, er
|
|||||||
|
|
||||||
var err error
|
var err error
|
||||||
var params []byte
|
var params []byte
|
||||||
var to address.Address
|
if len(tx.Input) > 0 {
|
||||||
method := builtintypes.MethodsEVM.InvokeContract
|
|
||||||
// nil indicates the EAM, only CreateExternal is allowed
|
|
||||||
if tx.To == nil {
|
|
||||||
to = builtintypes.EthereumAddressManagerActorAddr
|
|
||||||
method = builtintypes.MethodsEAM.CreateExternal
|
|
||||||
if len(tx.Input) == 0 {
|
|
||||||
return nil, xerrors.New("cannot call CreateExternal without params")
|
|
||||||
}
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
if err = cbg.WriteByteArray(buf, tx.Input); err != nil {
|
if err = cbg.WriteByteArray(buf, tx.Input); err != nil {
|
||||||
return nil, xerrors.Errorf("failed to serialize Create params: %w", err)
|
return nil, xerrors.Errorf("failed to write input args: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
params = buf.Bytes()
|
params = buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
var to address.Address
|
||||||
|
var method abi.MethodNum
|
||||||
|
// nil indicates the EAM, only CreateExternal is allowed
|
||||||
|
if tx.To == nil {
|
||||||
|
method = builtintypes.MethodsEAM.CreateExternal
|
||||||
|
to = builtintypes.EthereumAddressManagerActorAddr
|
||||||
} else {
|
} else {
|
||||||
|
method = builtintypes.MethodsEVM.InvokeContract
|
||||||
to, err = tx.To.ToFilecoinAddress()
|
to, err = tx.To.ToFilecoinAddress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to convert To into filecoin addr: %w", err)
|
return nil, xerrors.Errorf("failed to convert To into filecoin addr: %w", err)
|
||||||
}
|
}
|
||||||
if len(tx.Input) > 0 {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
if err = cbg.WriteByteArray(buf, tx.Input); err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to write input args: %w", err)
|
|
||||||
}
|
|
||||||
params = buf.Bytes()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &types.Message{
|
return &types.Message{
|
||||||
|
@ -66,6 +66,18 @@ func EthUint64FromHex(s string) (EthUint64, error) {
|
|||||||
return EthUint64(parsedInt), nil
|
return EthUint64(parsedInt), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse a uint64 from big-endian encoded bytes.
|
||||||
|
func EthUint64FromBytes(b []byte) (EthUint64, error) {
|
||||||
|
if len(b) != 32 {
|
||||||
|
return 0, xerrors.Errorf("eth int must be 32 bytes long")
|
||||||
|
}
|
||||||
|
var zeros [32 - 8]byte
|
||||||
|
if !bytes.Equal(b[:len(zeros)], zeros[:]) {
|
||||||
|
return 0, xerrors.Errorf("eth int overflows 64 bits")
|
||||||
|
}
|
||||||
|
return EthUint64(binary.BigEndian.Uint64(b[len(zeros):])), nil
|
||||||
|
}
|
||||||
|
|
||||||
func (e EthUint64) Hex() string {
|
func (e EthUint64) Hex() string {
|
||||||
if e == 0 {
|
if e == 0 {
|
||||||
return "0x0"
|
return "0x0"
|
||||||
@ -78,11 +90,15 @@ type EthBigInt big.Int
|
|||||||
|
|
||||||
var EthBigIntZero = EthBigInt{Int: big.Zero().Int}
|
var EthBigIntZero = EthBigInt{Int: big.Zero().Int}
|
||||||
|
|
||||||
func (e EthBigInt) MarshalJSON() ([]byte, error) {
|
func (e EthBigInt) String() string {
|
||||||
if e.Int == nil || e.Int.BitLen() == 0 {
|
if e.Int == nil || e.Int.BitLen() == 0 {
|
||||||
return json.Marshal("0x0")
|
return "0x0"
|
||||||
}
|
}
|
||||||
return json.Marshal(fmt.Sprintf("0x%x", e.Int))
|
return fmt.Sprintf("0x%x", e.Int)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EthBigInt) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(e.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EthBigInt) UnmarshalJSON(b []byte) error {
|
func (e *EthBigInt) UnmarshalJSON(b []byte) error {
|
||||||
@ -106,12 +122,15 @@ func (e *EthBigInt) UnmarshalJSON(b []byte) error {
|
|||||||
// EthBytes represent arbitrary bytes. A nil or empty slice serializes to "0x".
|
// EthBytes represent arbitrary bytes. A nil or empty slice serializes to "0x".
|
||||||
type EthBytes []byte
|
type EthBytes []byte
|
||||||
|
|
||||||
func (e EthBytes) MarshalJSON() ([]byte, error) {
|
func (e EthBytes) String() string {
|
||||||
if len(e) == 0 {
|
if len(e) == 0 {
|
||||||
return json.Marshal("0x")
|
return "0x"
|
||||||
}
|
}
|
||||||
s := hex.EncodeToString(e)
|
return "0x" + hex.EncodeToString(e)
|
||||||
return json.Marshal("0x" + s)
|
}
|
||||||
|
|
||||||
|
func (e EthBytes) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(e.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *EthBytes) UnmarshalJSON(b []byte) error {
|
func (e *EthBytes) UnmarshalJSON(b []byte) error {
|
||||||
|
16
cli/evm.go
16
cli/evm.go
@ -21,6 +21,7 @@ import (
|
|||||||
|
|
||||||
"github.com/filecoin-project/lotus/api/v0api"
|
"github.com/filecoin-project/lotus/api/v0api"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
|
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||||
)
|
)
|
||||||
@ -75,13 +76,18 @@ var EvmGetInfoCmd = &cli.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
actor, err := api.StateGetActor(ctx, faddr, types.EmptyTSK)
|
actor, err := api.StateGetActor(ctx, faddr, types.EmptyTSK)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Filecoin address: ", faddr)
|
fmt.Println("Filecoin address: ", faddr)
|
||||||
fmt.Println("Eth address: ", eaddr)
|
fmt.Println("Eth address: ", eaddr)
|
||||||
fmt.Println("Code cid: ", actor.Code.String())
|
if err != nil {
|
||||||
|
fmt.Printf("Actor lookup failed for faddr %s with error: %s\n", faddr, err)
|
||||||
|
} else {
|
||||||
|
idAddr, err := api.StateLookupID(ctx, faddr, types.EmptyTSK)
|
||||||
|
if err == nil {
|
||||||
|
fmt.Println("ID address: ", idAddr)
|
||||||
|
fmt.Println("Code cid: ", actor.Code.String())
|
||||||
|
fmt.Println("Actor Type: ", builtin.ActorNameByCode(actor.Code))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
@ -34,8 +34,8 @@ func TestWorkerKeyChange(t *testing.T) {
|
|||||||
|
|
||||||
kit.QuietMiningLogs()
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
blocktime := 1 * time.Millisecond
|
blocktime := 5 * time.Millisecond
|
||||||
client1, client2, miner, ens := kit.EnsembleTwoOne(t, kit.MockProofs())
|
client1, miner, ens := kit.EnsembleMinimal(t, kit.MockProofs())
|
||||||
ens.InterconnectAll().BeginMining(blocktime)
|
ens.InterconnectAll().BeginMining(blocktime)
|
||||||
|
|
||||||
output := bytes.NewBuffer(nil)
|
output := bytes.NewBuffer(nil)
|
||||||
@ -96,7 +96,4 @@ func TestWorkerKeyChange(t *testing.T) {
|
|||||||
// Wait for finality (worker key switch).
|
// Wait for finality (worker key switch).
|
||||||
targetHeight := head.Height() + policy.ChainFinality
|
targetHeight := head.Height() + policy.ChainFinality
|
||||||
client1.WaitTillChain(ctx, kit.HeightAtLeast(targetHeight))
|
client1.WaitTillChain(ctx, kit.HeightAtLeast(targetHeight))
|
||||||
|
|
||||||
// Make sure the other node can catch up.
|
|
||||||
client2.WaitTillChain(ctx, kit.HeightAtLeast(targetHeight))
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/go-units"
|
"github.com/docker/go-units"
|
||||||
@ -33,11 +34,14 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
lcli "github.com/filecoin-project/lotus/cli"
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
cliutil "github.com/filecoin-project/lotus/cli/util"
|
cliutil "github.com/filecoin-project/lotus/cli/util"
|
||||||
|
"github.com/filecoin-project/lotus/lib/result"
|
||||||
"github.com/filecoin-project/lotus/lib/strle"
|
"github.com/filecoin-project/lotus/lib/strle"
|
||||||
"github.com/filecoin-project/lotus/lib/tablewriter"
|
"github.com/filecoin-project/lotus/lib/tablewriter"
|
||||||
sealing "github.com/filecoin-project/lotus/storage/pipeline"
|
sealing "github.com/filecoin-project/lotus/storage/pipeline"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const parallelSectorChecks = 300
|
||||||
|
|
||||||
var sectorsCmd = &cli.Command{
|
var sectorsCmd = &cli.Command{
|
||||||
Name: "sectors",
|
Name: "sectors",
|
||||||
Usage: "interact with sector store",
|
Usage: "interact with sector store",
|
||||||
@ -306,9 +310,15 @@ var sectorsListCmd = &cli.Command{
|
|||||||
Usage: "only show sectors which aren't in the 'Proving' state",
|
Usage: "only show sectors which aren't in the 'Proving' state",
|
||||||
Aliases: []string{"u"},
|
Aliases: []string{"u"},
|
||||||
},
|
},
|
||||||
|
&cli.Int64Flag{
|
||||||
|
Name: "check-parallelism",
|
||||||
|
Usage: "number of parallel requests to make for checking sector states",
|
||||||
|
Value: parallelSectorChecks,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx)
|
// http mode allows for parallel json decoding/encoding, which was a bottleneck here
|
||||||
|
minerApi, closer, err := lcli.GetStorageMinerAPI(cctx, cliutil.StorageMinerUseHttp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -407,16 +417,37 @@ var sectorsListCmd = &cli.Command{
|
|||||||
|
|
||||||
fast := cctx.Bool("fast")
|
fast := cctx.Bool("fast")
|
||||||
|
|
||||||
for _, s := range list {
|
throttle := make(chan struct{}, cctx.Int64("check-parallelism"))
|
||||||
st, err := minerApi.SectorsStatus(ctx, s, !fast)
|
|
||||||
if err != nil {
|
slist := make([]result.Result[api.SectorInfo], len(list))
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for i, s := range list {
|
||||||
|
throttle <- struct{}{}
|
||||||
|
wg.Add(1)
|
||||||
|
go func(i int, s abi.SectorNumber) {
|
||||||
|
defer wg.Done()
|
||||||
|
defer func() { <-throttle }()
|
||||||
|
r := result.Wrap(minerApi.SectorsStatus(ctx, s, !fast))
|
||||||
|
if r.Error != nil {
|
||||||
|
r.Value.SectorID = s
|
||||||
|
}
|
||||||
|
slist[i] = r
|
||||||
|
}(i, s)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
for _, rsn := range slist {
|
||||||
|
if rsn.Error != nil {
|
||||||
tw.Write(map[string]interface{}{
|
tw.Write(map[string]interface{}{
|
||||||
"ID": s,
|
"ID": rsn.Value.SectorID,
|
||||||
"Error": err,
|
"Error": err,
|
||||||
})
|
})
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
st := rsn.Value
|
||||||
|
s := st.SectorID
|
||||||
|
|
||||||
if !showRemoved && st.State == api.SectorState(sealing.Removed) {
|
if !showRemoved && st.State == api.SectorState(sealing.Removed) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -455,9 +455,8 @@ var chainBalanceStateCmd = &cli.Command{
|
|||||||
Description: "Produces a csv file of all account balances from a given stateroot",
|
Description: "Produces a csv file of all account balances from a given stateroot",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "miner-info",
|
Name: "miner-info",
|
||||||
@ -679,9 +678,8 @@ var chainPledgeCmd = &cli.Command{
|
|||||||
Description: "Calculate sector pledge numbers",
|
Description: "Calculate sector pledge numbers",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ArgsUsage: "[stateroot epoch]",
|
ArgsUsage: "[stateroot epoch]",
|
||||||
|
@ -41,11 +41,6 @@ var datastoreListCmd = &cli.Command{
|
|||||||
Name: "list",
|
Name: "list",
|
||||||
Description: "list datastore keys",
|
Description: "list datastore keys",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "repo",
|
|
||||||
Value: "~/.lotus",
|
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo-type",
|
Name: "repo-type",
|
||||||
Usage: "node type (FullNode, StorageMiner, Worker, Wallet)",
|
Usage: "node type (FullNode, StorageMiner, Worker, Wallet)",
|
||||||
@ -115,11 +110,6 @@ var datastoreGetCmd = &cli.Command{
|
|||||||
Name: "get",
|
Name: "get",
|
||||||
Description: "list datastore keys",
|
Description: "list datastore keys",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "repo",
|
|
||||||
Value: "~/.lotus",
|
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo-type",
|
Name: "repo-type",
|
||||||
Usage: "node type (FullNode, StorageMiner, Worker, Wallet)",
|
Usage: "node type (FullNode, StorageMiner, Worker, Wallet)",
|
||||||
@ -133,7 +123,7 @@ var datastoreGetCmd = &cli.Command{
|
|||||||
},
|
},
|
||||||
ArgsUsage: "[namespace key]",
|
ArgsUsage: "[namespace key]",
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
_ = logging.SetLogLevel("badger", "ERROR")
|
logging.SetLogLevel("badger", "ERROR") // nolint:errcheck
|
||||||
|
|
||||||
r, err := repo.NewFS(cctx.String("repo"))
|
r, err := repo.NewFS(cctx.String("repo"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -24,9 +24,8 @@ var dealLabelCmd = &cli.Command{
|
|||||||
Usage: "Scrape state to report on how many deals have non UTF-8 labels",
|
Usage: "Scrape state to report on how many deals have non UTF-8 labels",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
|
@ -33,9 +33,8 @@ var diffMinerStates = &cli.Command{
|
|||||||
ArgsUsage: "<stateCidA> <stateCidB>",
|
ArgsUsage: "<stateCidA> <stateCidB>",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
|
@ -35,9 +35,8 @@ var exportCarCmd = &cli.Command{
|
|||||||
Description: "Export a car from repo",
|
Description: "Export a car from repo",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
ArgsUsage: "[outfile] [root cid]",
|
ArgsUsage: "[outfile] [root cid]",
|
||||||
|
@ -42,9 +42,8 @@ var exportChainCmd = &cli.Command{
|
|||||||
Description: "Export chain from repo (requires node to be offline)",
|
Description: "Export chain from repo (requires node to be offline)",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "tipset",
|
Name: "tipset",
|
||||||
@ -147,9 +146,8 @@ var exportRawCmd = &cli.Command{
|
|||||||
Description: "Export raw blocks from repo (requires node to be offline)",
|
Description: "Export raw blocks from repo (requires node to be offline)",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "car-size",
|
Name: "car-size",
|
||||||
|
@ -58,6 +58,12 @@ var fip36PollCmd = &cli.Command{
|
|||||||
Name: "fip36poll",
|
Name: "fip36poll",
|
||||||
Usage: "Process the FIP0036 FilPoll result",
|
Usage: "Process the FIP0036 FilPoll result",
|
||||||
ArgsUsage: "[state root, votes]",
|
ArgsUsage: "[state root, votes]",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "repo",
|
||||||
|
Value: "~/.lotus",
|
||||||
|
},
|
||||||
|
},
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
finalResultCmd,
|
finalResultCmd,
|
||||||
},
|
},
|
||||||
@ -69,9 +75,8 @@ var finalResultCmd = &cli.Command{
|
|||||||
ArgsUsage: "[state root] [height] [votes json]",
|
ArgsUsage: "[state root] [height] [votes json]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -43,9 +43,8 @@ var gasTraceCmd = &cli.Command{
|
|||||||
ArgsUsage: "[migratedStateRootCid networkVersion messageCid]",
|
ArgsUsage: "[migratedStateRootCid networkVersion messageCid]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
@ -148,9 +147,8 @@ var replayOfflineCmd = &cli.Command{
|
|||||||
ArgsUsage: "[messageCid]",
|
ArgsUsage: "[messageCid]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.Int64Flag{
|
||||||
Name: "lookback-limit",
|
Name: "lookback-limit",
|
||||||
|
@ -19,13 +19,6 @@ import (
|
|||||||
var importCarCmd = &cli.Command{
|
var importCarCmd = &cli.Command{
|
||||||
Name: "import-car",
|
Name: "import-car",
|
||||||
Description: "Import a car file into node chain blockstore",
|
Description: "Import a car file into node chain blockstore",
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "repo",
|
|
||||||
Value: "~/.lotus",
|
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
r, err := repo.NewFS(cctx.String("repo"))
|
r, err := repo.NewFS(cctx.String("repo"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -103,13 +96,6 @@ var importCarCmd = &cli.Command{
|
|||||||
var importObjectCmd = &cli.Command{
|
var importObjectCmd = &cli.Command{
|
||||||
Name: "import-obj",
|
Name: "import-obj",
|
||||||
Usage: "import a raw ipld object into your datastore",
|
Usage: "import a raw ipld object into your datastore",
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "repo",
|
|
||||||
Value: "~/.lotus",
|
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
r, err := repo.NewFS(cctx.String("repo"))
|
r, err := repo.NewFS(cctx.String("repo"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -36,9 +36,8 @@ var invariantsCmd = &cli.Command{
|
|||||||
ArgsUsage: "[StateRootCid, height]",
|
ArgsUsage: "[StateRootCid, height]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
|
@ -146,14 +146,9 @@ var keyinfoImportCmd = &cli.Command{
|
|||||||
Examples
|
Examples
|
||||||
|
|
||||||
env LOTUS_PATH=/var/lib/lotus lotus-shed keyinfo import libp2p-host.keyinfo`,
|
env LOTUS_PATH=/var/lib/lotus lotus-shed keyinfo import libp2p-host.keyinfo`,
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
|
||||||
Name: "repo",
|
|
||||||
Value: "~/.lotus",
|
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
|
flagRepo := cctx.String("repo")
|
||||||
|
|
||||||
var input io.Reader
|
var input io.Reader
|
||||||
if cctx.NArg() == 0 {
|
if cctx.NArg() == 0 {
|
||||||
input = os.Stdin
|
input = os.Stdin
|
||||||
@ -182,7 +177,7 @@ var keyinfoImportCmd = &cli.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fsrepo, err := repo.NewFS(cctx.String("repo"))
|
fsrepo, err := repo.NewFS(flagRepo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
logging "github.com/ipfs/go-log/v2"
|
logging "github.com/ipfs/go-log/v2"
|
||||||
@ -90,6 +91,19 @@ func main() {
|
|||||||
Version: build.UserVersion(),
|
Version: build.UserVersion(),
|
||||||
Commands: local,
|
Commands: local,
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "repo",
|
||||||
|
EnvVars: []string{"LOTUS_PATH"},
|
||||||
|
Hidden: true,
|
||||||
|
Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "miner-repo",
|
||||||
|
Aliases: []string{"storagerepo"},
|
||||||
|
EnvVars: []string{"LOTUS_MINER_PATH", "LOTUS_STORAGE_PATH"},
|
||||||
|
Value: "~/.lotusminer", // TODO: Consider XDG_DATA_HOME
|
||||||
|
Usage: fmt.Sprintf("Specify miner repo path. flag storagerepo and env LOTUS_STORAGE_PATH are DEPRECATION, will REMOVE SOON"),
|
||||||
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "log-level",
|
Name: "log-level",
|
||||||
Value: "info",
|
Value: "info",
|
||||||
|
@ -124,9 +124,8 @@ var marketExportDatastoreCmd = &cli.Command{
|
|||||||
Description: "export markets datastore key/values to a file",
|
Description: "export markets datastore key/values to a file",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Usage: "path to the repo",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "backup-dir",
|
Name: "backup-dir",
|
||||||
@ -242,9 +241,8 @@ var marketImportDatastoreCmd = &cli.Command{
|
|||||||
Description: "import markets datastore key/values from a backup file",
|
Description: "import markets datastore key/values from a backup file",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Usage: "path to the repo",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "backup-path",
|
Name: "backup-path",
|
||||||
|
@ -55,9 +55,8 @@ var migrationsCmd = &cli.Command{
|
|||||||
ArgsUsage: "[new network version, block to look back from]",
|
ArgsUsage: "[new network version, block to look back from]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "skip-pre-migration",
|
Name: "skip-pre-migration",
|
||||||
|
@ -26,12 +26,10 @@ import (
|
|||||||
|
|
||||||
var minerPeeridCmd = &cli.Command{
|
var minerPeeridCmd = &cli.Command{
|
||||||
Name: "miner-peerid",
|
Name: "miner-peerid",
|
||||||
Usage: "Scrape state to find a miner based on peerid",
|
Usage: "Scrape state to find a miner based on peerid", Flags: []cli.Flag{
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
|
@ -28,12 +28,10 @@ import (
|
|||||||
|
|
||||||
var minerTypesCmd = &cli.Command{
|
var minerTypesCmd = &cli.Command{
|
||||||
Name: "miner-types",
|
Name: "miner-types",
|
||||||
Usage: "Scrape state to report on how many miners of each WindowPoStProofType exist",
|
Usage: "Scrape state to report on how many miners of each WindowPoStProofType exist", Flags: []cli.Flag{
|
||||||
Flags: []cli.Flag{
|
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
|
@ -43,9 +43,8 @@ var multisigGetAllCmd = &cli.Command{
|
|||||||
ArgsUsage: "[state root]",
|
ArgsUsage: "[state root]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
|
@ -17,6 +17,12 @@ import (
|
|||||||
var noncefix = &cli.Command{
|
var noncefix = &cli.Command{
|
||||||
Name: "noncefix",
|
Name: "noncefix",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "repo",
|
||||||
|
EnvVars: []string{"LOTUS_PATH"},
|
||||||
|
Hidden: true,
|
||||||
|
Value: "~/.lotus", // TODO: Consider XDG_DATA_HOME
|
||||||
|
},
|
||||||
&cli.Uint64Flag{
|
&cli.Uint64Flag{
|
||||||
Name: "start",
|
Name: "start",
|
||||||
},
|
},
|
||||||
|
@ -86,9 +86,8 @@ var stateTreePruneCmd = &cli.Command{
|
|||||||
Description: "Deletes old state root data from local chainstore",
|
Description: "Deletes old state root data from local chainstore",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
&cli.Int64Flag{
|
&cli.Int64Flag{
|
||||||
Name: "keep-from-lookback",
|
Name: "keep-from-lookback",
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
"gopkg.in/cheggaaa/pb.v1"
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-bitfield"
|
"github.com/filecoin-project/go-bitfield"
|
||||||
@ -31,6 +32,11 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
lcli "github.com/filecoin-project/lotus/cli"
|
lcli "github.com/filecoin-project/lotus/cli"
|
||||||
"github.com/filecoin-project/lotus/lib/parmap"
|
"github.com/filecoin-project/lotus/lib/parmap"
|
||||||
|
"github.com/filecoin-project/lotus/node/repo"
|
||||||
|
"github.com/filecoin-project/lotus/storage/paths"
|
||||||
|
"github.com/filecoin-project/lotus/storage/sealer/fr32"
|
||||||
|
"github.com/filecoin-project/lotus/storage/sealer/fsutil"
|
||||||
|
"github.com/filecoin-project/lotus/storage/sealer/storiface"
|
||||||
)
|
)
|
||||||
|
|
||||||
var sectorsCmd = &cli.Command{
|
var sectorsCmd = &cli.Command{
|
||||||
@ -42,6 +48,8 @@ var sectorsCmd = &cli.Command{
|
|||||||
terminateSectorPenaltyEstimationCmd,
|
terminateSectorPenaltyEstimationCmd,
|
||||||
visAllocatedSectorsCmd,
|
visAllocatedSectorsCmd,
|
||||||
dumpRLESectorCmd,
|
dumpRLESectorCmd,
|
||||||
|
sectorReadCmd,
|
||||||
|
sectorDeleteCmd,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -563,3 +571,219 @@ func rleToPng(rleBytes []byte) ([]byte, error) {
|
|||||||
|
|
||||||
return buf.Bytes(), nil
|
return buf.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sectorReadCmd = &cli.Command{
|
||||||
|
Name: "read",
|
||||||
|
Usage: "read data from a sector into stdout",
|
||||||
|
ArgsUsage: "[sector num] [padded length] [padded offset]",
|
||||||
|
Description: `Read data from a sector.
|
||||||
|
|
||||||
|
TIP: to get sectornum/len/offset for a piece you can use 'boostd pieces piece-info [cid]'
|
||||||
|
|
||||||
|
fr32 padding is removed from the output.`,
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if cctx.NArg() != 3 {
|
||||||
|
return xerrors.Errorf("must pass sectornum/len/offset")
|
||||||
|
}
|
||||||
|
|
||||||
|
sectorNum, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("parsing sector number: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
length, err := strconv.ParseUint(cctx.Args().Get(1), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("parsing length: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
offset, err := strconv.ParseUint(cctx.Args().Get(2), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("parsing offset: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := lcli.ReqContext(cctx)
|
||||||
|
api, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
maddr, err := api.ActorAddress(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting miner actor address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mid, err := address.IDFromAddress(maddr)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting miner id: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sid := abi.SectorID{
|
||||||
|
Miner: abi.ActorID(mid),
|
||||||
|
Number: abi.SectorNumber(sectorNum),
|
||||||
|
}
|
||||||
|
|
||||||
|
si, err := api.SectorsStatus(ctx, sid.Number, false)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting sector status: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sref := storiface.SectorRef{
|
||||||
|
ID: sid,
|
||||||
|
ProofType: si.SealProof,
|
||||||
|
}
|
||||||
|
|
||||||
|
defer closer()
|
||||||
|
|
||||||
|
// Setup remote sector store
|
||||||
|
sminfo, err := lcli.GetAPIInfo(cctx, repo.StorageMiner)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("could not get api info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
localStore, err := paths.NewLocal(ctx, &emptyLocalStorage{}, api, []string{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
remote := paths.NewRemote(localStore, api, sminfo.AuthHeader(), 10,
|
||||||
|
&paths.DefaultPartialFileHandler{})
|
||||||
|
|
||||||
|
readStarter, err := remote.Reader(ctx, sref, abi.PaddedPieceSize(offset), abi.PaddedPieceSize(length))
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting reader: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
rd, err := readStarter(0)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("starting reader: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
upr, err := fr32.NewUnpadReaderBuf(rd, abi.PaddedPieceSize(length), make([]byte, 1<<20))
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("creating unpadded reader: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
l := int64(abi.PaddedPieceSize(length).Unpadded())
|
||||||
|
|
||||||
|
bar := pb.New64(l)
|
||||||
|
br := bar.NewProxyReader(upr)
|
||||||
|
bar.ShowTimeLeft = true
|
||||||
|
bar.ShowPercent = true
|
||||||
|
bar.ShowSpeed = true
|
||||||
|
bar.Units = pb.U_BYTES
|
||||||
|
bar.Output = os.Stderr
|
||||||
|
bar.Start()
|
||||||
|
|
||||||
|
_, err = io.CopyN(os.Stdout, br, l)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("reading data: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var sectorDeleteCmd = &cli.Command{
|
||||||
|
Name: "delete",
|
||||||
|
Usage: "delete a sector file from sector storage",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "really-do-it",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ArgsUsage: "[sector num] [file type]",
|
||||||
|
Action: func(cctx *cli.Context) error {
|
||||||
|
if cctx.NArg() != 2 {
|
||||||
|
return xerrors.Errorf("must pass sectornum/filetype")
|
||||||
|
}
|
||||||
|
|
||||||
|
sectorNum, err := strconv.ParseUint(cctx.Args().Get(0), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("parsing sector number: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ft storiface.SectorFileType
|
||||||
|
switch cctx.Args().Get(1) {
|
||||||
|
case "cache":
|
||||||
|
ft = storiface.FTCache
|
||||||
|
case "sealed":
|
||||||
|
ft = storiface.FTSealed
|
||||||
|
case "unsealed":
|
||||||
|
ft = storiface.FTUnsealed
|
||||||
|
case "update-cache":
|
||||||
|
ft = storiface.FTUpdateCache
|
||||||
|
case "update":
|
||||||
|
ft = storiface.FTUpdate
|
||||||
|
default:
|
||||||
|
return xerrors.Errorf("invalid file type")
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := lcli.ReqContext(cctx)
|
||||||
|
api, closer, err := lcli.GetStorageMinerAPI(cctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer closer()
|
||||||
|
|
||||||
|
maddr, err := api.ActorAddress(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting miner actor address: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mid, err := address.IDFromAddress(maddr)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("getting miner id: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sid := abi.SectorID{
|
||||||
|
Miner: abi.ActorID(mid),
|
||||||
|
Number: abi.SectorNumber(sectorNum),
|
||||||
|
}
|
||||||
|
|
||||||
|
// get remote store
|
||||||
|
sminfo, err := lcli.GetAPIInfo(cctx, repo.StorageMiner)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("could not get api info: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
localStore, err := paths.NewLocal(ctx, &emptyLocalStorage{}, api, []string{})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !cctx.Bool("really-do-it") {
|
||||||
|
return xerrors.Errorf("pass --really-do-it to actually perform the deletion")
|
||||||
|
}
|
||||||
|
|
||||||
|
remote := paths.NewRemote(localStore, api, sminfo.AuthHeader(), 10,
|
||||||
|
&paths.DefaultPartialFileHandler{})
|
||||||
|
|
||||||
|
err = remote.Remove(ctx, sid, ft, true, nil)
|
||||||
|
if err != nil {
|
||||||
|
return xerrors.Errorf("removing sector: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
type emptyLocalStorage struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *emptyLocalStorage) GetStorage() (storiface.StorageConfig, error) {
|
||||||
|
return storiface.StorageConfig{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *emptyLocalStorage) SetStorage(f func(*storiface.StorageConfig)) error {
|
||||||
|
panic("don't call")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *emptyLocalStorage) Stat(path string) (fsutil.FsStat, error) {
|
||||||
|
panic("don't call")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *emptyLocalStorage) DiskUsage(path string) (int64, error) {
|
||||||
|
panic("don't call")
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ paths.LocalStorage = &emptyLocalStorage{}
|
||||||
|
@ -39,9 +39,8 @@ var splitstoreRollbackCmd = &cli.Command{
|
|||||||
Description: "rollbacks a splitstore installation",
|
Description: "rollbacks a splitstore installation",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "gc-coldstore",
|
Name: "gc-coldstore",
|
||||||
@ -130,9 +129,8 @@ var splitstoreClearCmd = &cli.Command{
|
|||||||
Description: "clears a splitstore installation for restart from snapshot",
|
Description: "clears a splitstore installation for restart from snapshot",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
&cli.BoolFlag{
|
&cli.BoolFlag{
|
||||||
Name: "keys-only",
|
Name: "keys-only",
|
||||||
|
@ -33,9 +33,8 @@ var terminationsCmd = &cli.Command{
|
|||||||
ArgsUsage: "[block to look back from] [lookback period (epochs)]",
|
ArgsUsage: "[block to look back from] [lookback period (epochs)]",
|
||||||
Flags: []cli.Flag{
|
Flags: []cli.Flag{
|
||||||
&cli.StringFlag{
|
&cli.StringFlag{
|
||||||
Name: "repo",
|
Name: "repo",
|
||||||
Value: "~/.lotus",
|
Value: "~/.lotus",
|
||||||
EnvVars: []string{"LOTUS_PATH"},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Action: func(cctx *cli.Context) error {
|
Action: func(cctx *cli.Context) error {
|
||||||
|
@ -69,6 +69,7 @@
|
|||||||
* [CreateBackup](#CreateBackup)
|
* [CreateBackup](#CreateBackup)
|
||||||
* [Eth](#Eth)
|
* [Eth](#Eth)
|
||||||
* [EthAccounts](#EthAccounts)
|
* [EthAccounts](#EthAccounts)
|
||||||
|
* [EthAddressToFilecoinAddress](#EthAddressToFilecoinAddress)
|
||||||
* [EthBlockNumber](#EthBlockNumber)
|
* [EthBlockNumber](#EthBlockNumber)
|
||||||
* [EthCall](#EthCall)
|
* [EthCall](#EthCall)
|
||||||
* [EthChainId](#EthChainId)
|
* [EthChainId](#EthChainId)
|
||||||
@ -2307,6 +2308,21 @@ Response:
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### EthAddressToFilecoinAddress
|
||||||
|
EthAddressToFilecoinAddress converts an EthAddress into an f410 Filecoin Address
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"0x5cbeecf99d3fdb3f25e309cc264f240bb0664031"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response: `"f01234"`
|
||||||
|
|
||||||
### EthBlockNumber
|
### EthBlockNumber
|
||||||
EthBlockNumber returns the height of the latest (heaviest) TipSet
|
EthBlockNumber returns the height of the latest (heaviest) TipSet
|
||||||
|
|
||||||
@ -2688,7 +2704,7 @@ Response:
|
|||||||
"accessList": [
|
"accessList": [
|
||||||
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
||||||
],
|
],
|
||||||
"yParity": "0x0",
|
"v": "0x0",
|
||||||
"r": "0x0",
|
"r": "0x0",
|
||||||
"s": "0x0"
|
"s": "0x0"
|
||||||
}
|
}
|
||||||
@ -2727,7 +2743,7 @@ Response:
|
|||||||
"accessList": [
|
"accessList": [
|
||||||
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
||||||
],
|
],
|
||||||
"yParity": "0x0",
|
"v": "0x0",
|
||||||
"r": "0x0",
|
"r": "0x0",
|
||||||
"s": "0x0"
|
"s": "0x0"
|
||||||
}
|
}
|
||||||
@ -2765,7 +2781,7 @@ Response:
|
|||||||
"accessList": [
|
"accessList": [
|
||||||
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
"0x37690cfec6c1bf4c3b9288c7a5d783e98731e90b0a4c177c2a374c7a9427355e"
|
||||||
],
|
],
|
||||||
"yParity": "0x0",
|
"v": "0x0",
|
||||||
"r": "0x0",
|
"r": "0x0",
|
||||||
"s": "0x0"
|
"s": "0x0"
|
||||||
}
|
}
|
||||||
|
@ -1717,13 +1717,14 @@ USAGE:
|
|||||||
lotus-miner sectors list [command options] [arguments...]
|
lotus-miner sectors list [command options] [arguments...]
|
||||||
|
|
||||||
OPTIONS:
|
OPTIONS:
|
||||||
--events, -e display number of events the sector has received (default: false)
|
--check-parallelism value number of parallel requests to make for checking sector states (default: 300)
|
||||||
--fast, -f don't show on-chain info for better performance (default: false)
|
--events, -e display number of events the sector has received (default: false)
|
||||||
--initial-pledge, -p display initial pledge (default: false)
|
--fast, -f don't show on-chain info for better performance (default: false)
|
||||||
--seal-time, -t display how long it took for the sector to be sealed (default: false)
|
--initial-pledge, -p display initial pledge (default: false)
|
||||||
--show-removed, -r show removed sectors (default: false)
|
--seal-time, -t display how long it took for the sector to be sealed (default: false)
|
||||||
--states value filter sectors by a comma-separated list of states
|
--show-removed, -r show removed sectors (default: false)
|
||||||
--unproven, -u only show sectors which aren't in the 'Proving' state (default: false)
|
--states value filter sectors by a comma-separated list of states
|
||||||
|
--unproven, -u only show sectors which aren't in the 'Proving' state (default: false)
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
2
extern/filecoin-ffi
vendored
2
extern/filecoin-ffi
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 4c503e5e2291b5d541f89d982d975e7994536a54
|
Subproject commit 7efaa7b47fe9d4bdb4ba0b2a0fafa4e573864ee5
|
@ -88,6 +88,7 @@ type TargetAPI interface {
|
|||||||
StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (api.CirculatingSupply, error)
|
StateVMCirculatingSupplyInternal(context.Context, types.TipSetKey) (api.CirculatingSupply, error)
|
||||||
WalletBalance(context.Context, address.Address) (types.BigInt, error)
|
WalletBalance(context.Context, address.Address) (types.BigInt, error)
|
||||||
|
|
||||||
|
EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error)
|
||||||
EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error)
|
EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error)
|
||||||
EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error)
|
EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error)
|
||||||
EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error)
|
EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error)
|
||||||
|
@ -307,7 +307,8 @@ type {{.Num}}Struct struct {
|
|||||||
|
|
||||||
type {{.Num}}Methods struct {
|
type {{.Num}}Methods struct {
|
||||||
{{range .Methods}}
|
{{range .Methods}}
|
||||||
{{.Num}} func({{.NamedParams}}) ({{.Results}}) `+"`"+`{{range .Tags}}{{index . 0}}:"{{index . 1}}"{{end}}`+"`"+`
|
{{.Num}} func({{.NamedParams}}) ({{.Results}}) `+"`"+`{{$first := true}}{{range .Tags}}{{if $first}}{{$first = false}}{{else}} {{end}}{{index . 0}}:"{{index . 1}}"{{end}}`+"`"+`
|
||||||
|
|
||||||
{{end}}
|
{{end}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"text/template"
|
"text/template"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
@ -32,19 +34,49 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
|||||||
}
|
}
|
||||||
`))
|
`))
|
||||||
|
|
||||||
|
func splitOverride(override string) (string, string) {
|
||||||
|
x := strings.Split(override, "=")
|
||||||
|
return x[0], x[1]
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
// read metadata from the embedded bundle, includes all info except git tags
|
||||||
metadata, err := build.ReadEmbeddedBuiltinActorsMetadata()
|
metadata, err := build.ReadEmbeddedBuiltinActorsMetadata()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Re-enable this when we can set the tag for ONLY the appropriate version
|
// IF args have been provided, extract git tag info from them, otherwise
|
||||||
// https://github.com/filecoin-project/lotus/issues/10185#issuecomment-1422864836
|
// rely on previously embedded metadata for git tags.
|
||||||
//if len(os.Args) > 1 {
|
if len(os.Args) > 1 {
|
||||||
// for _, m := range metadata {
|
// see ./build/actors/pack.sh
|
||||||
// m.BundleGitTag = os.Args[1]
|
// (optional) expected args are:
|
||||||
// }
|
// $(GOCC) run ./gen/bundle $(VERSION) $(RELEASE) $(RELEASE_OVERRIDES)
|
||||||
//}
|
// overrides are in the format network_name=override
|
||||||
|
gitTag := os.Args[2]
|
||||||
|
packedActorsVersion, err := strconv.Atoi(os.Args[1][1:])
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
overrides := map[string]string{}
|
||||||
|
for _, override := range os.Args[3:] {
|
||||||
|
k, v := splitOverride(override)
|
||||||
|
overrides[k] = v
|
||||||
|
}
|
||||||
|
for _, m := range metadata {
|
||||||
|
if int(m.Version) == packedActorsVersion {
|
||||||
|
override, ok := overrides[m.Network]
|
||||||
|
if ok {
|
||||||
|
m.BundleGitTag = override
|
||||||
|
} else {
|
||||||
|
m.BundleGitTag = gitTag
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m.BundleGitTag = getOldGitTagFromEmbeddedMetadata(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fi, err := os.Create("./build/builtin_actors_gen.go")
|
fi, err := os.Create("./build/builtin_actors_gen.go")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -57,3 +89,14 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getOldGitTagFromEmbeddedMetadata(m *build.BuiltinActorsMetadata) string {
|
||||||
|
for _, v := range build.EmbeddedBuiltinActorsMetadata {
|
||||||
|
// if we agree on the manifestCid for the previously embedded metadata, use the previously set tag
|
||||||
|
if m.Version == v.Version && m.Network == v.Network && m.ManifestCid == v.ManifestCid {
|
||||||
|
return m.BundleGitTag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
8
go.mod
8
go.mod
@ -44,7 +44,7 @@ require (
|
|||||||
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-rc2
|
github.com/filecoin-project/go-state-types v0.10.0-rc3
|
||||||
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
|
||||||
@ -97,7 +97,7 @@ require (
|
|||||||
github.com/ipfs/go-ipfs-util v0.0.2
|
github.com/ipfs/go-ipfs-util v0.0.2
|
||||||
github.com/ipfs/go-ipld-cbor v0.0.6
|
github.com/ipfs/go-ipld-cbor v0.0.6
|
||||||
github.com/ipfs/go-ipld-format v0.4.0
|
github.com/ipfs/go-ipld-format v0.4.0
|
||||||
github.com/ipfs/go-libipfs v0.4.0
|
github.com/ipfs/go-libipfs v0.4.1
|
||||||
github.com/ipfs/go-log/v2 v2.5.1
|
github.com/ipfs/go-log/v2 v2.5.1
|
||||||
github.com/ipfs/go-merkledag v0.8.1
|
github.com/ipfs/go-merkledag v0.8.1
|
||||||
github.com/ipfs/go-metrics-interface v0.0.1
|
github.com/ipfs/go-metrics-interface v0.0.1
|
||||||
@ -239,12 +239,12 @@ require (
|
|||||||
github.com/ipfs/go-ipfs-config v0.18.0 // indirect
|
github.com/ipfs/go-ipfs-config v0.18.0 // indirect
|
||||||
github.com/ipfs/go-ipfs-delay v0.0.1 // indirect
|
github.com/ipfs/go-ipfs-delay v0.0.1 // indirect
|
||||||
github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect
|
github.com/ipfs/go-ipfs-posinfo v0.0.1 // indirect
|
||||||
github.com/ipfs/go-ipfs-pq v0.0.2 // indirect
|
github.com/ipfs/go-ipfs-pq v0.0.3 // indirect
|
||||||
github.com/ipfs/go-ipld-legacy v0.1.1 // indirect
|
github.com/ipfs/go-ipld-legacy v0.1.1 // indirect
|
||||||
github.com/ipfs/go-ipns v0.3.0 // indirect
|
github.com/ipfs/go-ipns v0.3.0 // indirect
|
||||||
github.com/ipfs/go-log v1.0.5 // indirect
|
github.com/ipfs/go-log v1.0.5 // indirect
|
||||||
github.com/ipfs/go-path v0.3.0 // indirect
|
github.com/ipfs/go-path v0.3.0 // indirect
|
||||||
github.com/ipfs/go-peertaskqueue v0.8.0 // indirect
|
github.com/ipfs/go-peertaskqueue v0.8.1 // indirect
|
||||||
github.com/ipfs/go-verifcid v0.0.2 // indirect
|
github.com/ipfs/go-verifcid v0.0.2 // indirect
|
||||||
github.com/ipld/go-ipld-adl-hamt v0.0.0-20220616142416-9004dbd839e0 // indirect
|
github.com/ipld/go-ipld-adl-hamt v0.0.0-20220616142416-9004dbd839e0 // indirect
|
||||||
github.com/ipni/storetheindex v0.5.3-0.20221203123030-16745cb63f15 // indirect
|
github.com/ipni/storetheindex v0.5.3-0.20221203123030-16745cb63f15 // indirect
|
||||||
|
15
go.sum
15
go.sum
@ -356,8 +356,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-rc2 h1:nl92h86XridAoy0fjvW+8/8/eI0caVSm0fhAnIvtR64=
|
github.com/filecoin-project/go-state-types v0.10.0-rc3 h1:qExCc2swTe5ndsiu9dEoMqIwppjuTNRbsAFgpzHnHbc=
|
||||||
github.com/filecoin-project/go-state-types v0.10.0-rc2/go.mod h1:aLIas+W8BWAfpLWEPUOGMPBdhcVwoCG4pIQSQk26024=
|
github.com/filecoin-project/go-state-types v0.10.0-rc3/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=
|
||||||
@ -789,8 +789,9 @@ github.com/ipfs/go-ipfs-http-client v0.4.0/go.mod h1:NXzPUKt/QVCuR74a8angJCGOSLP
|
|||||||
github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs=
|
github.com/ipfs/go-ipfs-posinfo v0.0.1 h1:Esoxj+1JgSjX0+ylc0hUmJCOv6V2vFoZiETLR6OtpRs=
|
||||||
github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A=
|
github.com/ipfs/go-ipfs-posinfo v0.0.1/go.mod h1:SwyeVP+jCwiDu0C313l/8jg6ZxM0qqtlt2a0vILTc1A=
|
||||||
github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
|
github.com/ipfs/go-ipfs-pq v0.0.1/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
|
||||||
github.com/ipfs/go-ipfs-pq v0.0.2 h1:e1vOOW6MuOwG2lqxcLA+wEn93i/9laCY8sXAw76jFOY=
|
|
||||||
github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
|
github.com/ipfs/go-ipfs-pq v0.0.2/go.mod h1:LWIqQpqfRG3fNc5XsnIhz/wQ2XXGyugQwls7BgUmUfY=
|
||||||
|
github.com/ipfs/go-ipfs-pq v0.0.3 h1:YpoHVJB+jzK15mr/xsWC574tyDLkezVrDNeaalQBsTE=
|
||||||
|
github.com/ipfs/go-ipfs-pq v0.0.3/go.mod h1:btNw5hsHBpRcSSgZtiNm/SLj5gYIZ18AKtv3kERkRb4=
|
||||||
github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs=
|
github.com/ipfs/go-ipfs-routing v0.0.1/go.mod h1:k76lf20iKFxQTjcJokbPM9iBXVXVZhcOwc360N4nuKs=
|
||||||
github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY=
|
github.com/ipfs/go-ipfs-routing v0.1.0/go.mod h1:hYoUkJLyAUKhF58tysKpids8RNDPO42BVMgK5dNsoqY=
|
||||||
github.com/ipfs/go-ipfs-routing v0.2.1/go.mod h1:xiNNiwgjmLqPS1cimvAw6EyB9rkVDbiocA4yY+wRNLM=
|
github.com/ipfs/go-ipfs-routing v0.2.1/go.mod h1:xiNNiwgjmLqPS1cimvAw6EyB9rkVDbiocA4yY+wRNLM=
|
||||||
@ -817,8 +818,8 @@ github.com/ipfs/go-ipld-legacy v0.1.1 h1:BvD8PEuqwBHLTKqlGFTHSwrwFOMkVESEvwIYwR2
|
|||||||
github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg=
|
github.com/ipfs/go-ipld-legacy v0.1.1/go.mod h1:8AyKFCjgRPsQFf15ZQgDB8Din4DML/fOmKZkkFkrIEg=
|
||||||
github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A=
|
github.com/ipfs/go-ipns v0.3.0 h1:ai791nTgVo+zTuq2bLvEGmWP1M0A6kGTXUsgv/Yq67A=
|
||||||
github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24=
|
github.com/ipfs/go-ipns v0.3.0/go.mod h1:3cLT2rbvgPZGkHJoPO1YMJeh6LtkxopCkKFcio/wE24=
|
||||||
github.com/ipfs/go-libipfs v0.4.0 h1:TkUxJGjtPnSzAgkw7VjS0/DBay3MPjmTBa4dGdUQCDE=
|
github.com/ipfs/go-libipfs v0.4.1 h1:tyu3RRMKFQUyUQt5jyt5SmDnls93H4Tr3HifL50zihg=
|
||||||
github.com/ipfs/go-libipfs v0.4.0/go.mod h1:XsU2cP9jBhDrXoJDe0WxikB8XcVmD3k2MEZvB3dbYu8=
|
github.com/ipfs/go-libipfs v0.4.1/go.mod h1:Ad8ybPqwCkl2cNiNUMvM/iaVc/5bwNpHu8RPZ5te1hw=
|
||||||
github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
|
github.com/ipfs/go-log v0.0.1/go.mod h1:kL1d2/hzSpI0thNYjiKfjanbVNU+IIGA/WnNESY9leM=
|
||||||
github.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSIKjA=
|
github.com/ipfs/go-log v1.0.0/go.mod h1:JO7RzlMK6rA+CIxFMLOuB6Wf5b81GDiKElL7UPSIKjA=
|
||||||
github.com/ipfs/go-log v1.0.1/go.mod h1:HuWlQttfN6FWNHRhlY5yMk/lW7evQC0HHGOxEwMRR8I=
|
github.com/ipfs/go-log v1.0.1/go.mod h1:HuWlQttfN6FWNHRhlY5yMk/lW7evQC0HHGOxEwMRR8I=
|
||||||
@ -859,8 +860,8 @@ github.com/ipfs/go-peertaskqueue v0.0.4/go.mod h1:03H8fhyeMfKNFWqzYEVyMbcPUeYrqP
|
|||||||
github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U=
|
github.com/ipfs/go-peertaskqueue v0.1.0/go.mod h1:Jmk3IyCcfl1W3jTW3YpghSwSEC6IJ3Vzz/jUmWw8Z0U=
|
||||||
github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU=
|
github.com/ipfs/go-peertaskqueue v0.7.0/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU=
|
||||||
github.com/ipfs/go-peertaskqueue v0.7.1/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU=
|
github.com/ipfs/go-peertaskqueue v0.7.1/go.mod h1:M/akTIE/z1jGNXMU7kFB4TeSEFvj68ow0Rrb04donIU=
|
||||||
github.com/ipfs/go-peertaskqueue v0.8.0 h1:JyNO144tfu9bx6Hpo119zvbEL9iQ760FHOiJYsUjqaU=
|
github.com/ipfs/go-peertaskqueue v0.8.1 h1:YhxAs1+wxb5jk7RvS0LHdyiILpNmRIRnZVztekOF0pg=
|
||||||
github.com/ipfs/go-peertaskqueue v0.8.0/go.mod h1:cz8hEnnARq4Du5TGqiWKgMr/BOSQ5XOgMOh1K5YYKKM=
|
github.com/ipfs/go-peertaskqueue v0.8.1/go.mod h1:Oxxd3eaK279FxeydSPPVGHzbwVeHjatZ2GA8XD+KbPU=
|
||||||
github.com/ipfs/go-unixfs v0.2.2-0.20190827150610-868af2e9e5cb/go.mod h1:IwAAgul1UQIcNZzKPYZWOCijryFBeCV79cNubPzol+k=
|
github.com/ipfs/go-unixfs v0.2.2-0.20190827150610-868af2e9e5cb/go.mod h1:IwAAgul1UQIcNZzKPYZWOCijryFBeCV79cNubPzol+k=
|
||||||
github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw=
|
github.com/ipfs/go-unixfs v0.2.4/go.mod h1:SUdisfUjNoSDzzhGVxvCL9QO/nKdwXdr+gbMUdqcbYw=
|
||||||
github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o=
|
github.com/ipfs/go-unixfs v0.3.1/go.mod h1:h4qfQYzghiIc8ZNFKiLMFWOTzrWIAtzYQ59W/pCFf1o=
|
||||||
|
1
itests/contracts/Errors.hex
Normal file
1
itests/contracts/Errors.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b506102de806100206000396000f3fe608060405234801561001057600080fd5b50600436106100575760003560e01c80630abe88b61461005c57806358d4cbce1461006657806359be8c55146100705780638791bd331461007a578063c6dbcf2e14610084575b600080fd5b61006461008e565b005b61006e61009f565b005b6100786100a4565b005b6100826100df565b005b61008c610111565b005b600061009d5761009c61012a565b5b565b600080fd5b6040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016100d6906101b6565b60405180910390fd5b6040517f09caebf300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006001905060008082610125919061023e565b505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052600160045260246000fd5b600082825260208201905092915050565b7f6d7920726561736f6e0000000000000000000000000000000000000000000000600082015250565b60006101a0600983610159565b91506101ab8261016a565b602082019050919050565b600060208201905081810360008301526101cf81610193565b9050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000610249826101d6565b9150610254836101d6565b925082610264576102636101e0565b5b600160000383147f80000000000000000000000000000000000000000000000000000000000000008314161561029d5761029c61020f565b5b82820590509291505056fea26469706673582212207815355e9e7ced2b8168a953c364e82871c0fe326602bbb9106e6551aea673ed64736f6c63430008120033
|
24
itests/contracts/Errors.sol
Normal file
24
itests/contracts/Errors.sol
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.17;
|
||||||
|
|
||||||
|
contract Errors {
|
||||||
|
error CustomError();
|
||||||
|
|
||||||
|
function failRevertEmpty() public {
|
||||||
|
revert();
|
||||||
|
}
|
||||||
|
function failRevertReason() public {
|
||||||
|
revert("my reason");
|
||||||
|
}
|
||||||
|
function failAssert() public {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
function failDivZero() public {
|
||||||
|
int a = 1;
|
||||||
|
int b = 0;
|
||||||
|
a / b;
|
||||||
|
}
|
||||||
|
function failCustom() public {
|
||||||
|
revert CustomError();
|
||||||
|
}
|
||||||
|
}
|
1
itests/contracts/GetDifficulty.hex
Normal file
1
itests/contracts/GetDifficulty.hex
Normal file
@ -0,0 +1 @@
|
|||||||
|
608060405234801561001057600080fd5b5060b58061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063b6baffe314602d575b600080fd5b60336047565b604051603e91906066565b60405180910390f35b600044905090565b6000819050919050565b606081604f565b82525050565b6000602082019050607960008301846059565b9291505056fea2646970667358221220c113f1abaabaed6a0324d363896b0d15a8bca7b9a540948a5be5b636a12a534f64736f6c63430008110033
|
9
itests/contracts/GetDifficulty.sol
Normal file
9
itests/contracts/GetDifficulty.sol
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity >=0.8.17;
|
||||||
|
|
||||||
|
contract GetDifficulty {
|
||||||
|
function getDifficulty () public view returns (uint256) {
|
||||||
|
return block.difficulty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
1
itests/contracts/TransparentUpgradeableProxy.hex
Normal file
1
itests/contracts/TransparentUpgradeableProxy.hex
Normal file
File diff suppressed because one or more lines are too long
590
itests/contracts/TransparentUpgradeableProxy.sol
Normal file
590
itests/contracts/TransparentUpgradeableProxy.sol
Normal file
@ -0,0 +1,590 @@
|
|||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
pragma solidity ^0.8.0;
|
||||||
|
|
||||||
|
abstract contract Initializable {
|
||||||
|
uint8 private _initialized;
|
||||||
|
|
||||||
|
bool private _initializing;
|
||||||
|
|
||||||
|
event Initialized(uint8 version);
|
||||||
|
|
||||||
|
modifier initializer() {
|
||||||
|
bool isTopLevelCall = !_initializing;
|
||||||
|
require(
|
||||||
|
(isTopLevelCall && _initialized < 1) ||
|
||||||
|
(!Address.isContract(address(this)) && _initialized == 1),
|
||||||
|
"Initializable: contract is already initialized"
|
||||||
|
);
|
||||||
|
_initialized = 1;
|
||||||
|
if (isTopLevelCall) {
|
||||||
|
_initializing = true;
|
||||||
|
}
|
||||||
|
_;
|
||||||
|
if (isTopLevelCall) {
|
||||||
|
_initializing = false;
|
||||||
|
emit Initialized(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier reinitializer(uint8 version) {
|
||||||
|
require(
|
||||||
|
!_initializing && _initialized < version,
|
||||||
|
"Initializable: contract is already initialized"
|
||||||
|
);
|
||||||
|
_initialized = version;
|
||||||
|
_initializing = true;
|
||||||
|
_;
|
||||||
|
_initializing = false;
|
||||||
|
emit Initialized(version);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier onlyInitializing() {
|
||||||
|
require(_initializing, "Initializable: contract is not initializing");
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _disableInitializers() internal virtual {
|
||||||
|
require(!_initializing, "Initializable: contract is initializing");
|
||||||
|
if (_initialized != type(uint8).max) {
|
||||||
|
_initialized = type(uint8).max;
|
||||||
|
emit Initialized(type(uint8).max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _getInitializedVersion() internal view returns (uint8) {
|
||||||
|
return _initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _isInitializing() internal view returns (bool) {
|
||||||
|
return _initializing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Implementation4 is Initializable {
|
||||||
|
uint256 internal _value;
|
||||||
|
|
||||||
|
function initialize() public initializer {}
|
||||||
|
|
||||||
|
function setValue(uint256 _number) public {
|
||||||
|
_value = _number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValue() public view returns (uint256) {
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
|
||||||
|
fallback() external {
|
||||||
|
_value = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract Implementation2 is Initializable {
|
||||||
|
uint256 internal _value;
|
||||||
|
|
||||||
|
function initialize() public initializer {}
|
||||||
|
|
||||||
|
function setValue(uint256 _number) public {
|
||||||
|
_value = _number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValue() public view returns (uint256) {
|
||||||
|
return _value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract contract Proxy {
|
||||||
|
function _delegate(address implementation) internal virtual {
|
||||||
|
assembly {
|
||||||
|
calldatacopy(0, 0, calldatasize())
|
||||||
|
|
||||||
|
let result := delegatecall(
|
||||||
|
gas(),
|
||||||
|
implementation,
|
||||||
|
0,
|
||||||
|
calldatasize(),
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
||||||
|
returndatacopy(0, 0, returndatasize())
|
||||||
|
|
||||||
|
switch result
|
||||||
|
case 0 {
|
||||||
|
revert(0, returndatasize())
|
||||||
|
}
|
||||||
|
default {
|
||||||
|
return(0, returndatasize())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _implementation() internal view virtual returns (address);
|
||||||
|
|
||||||
|
function _fallback() internal virtual {
|
||||||
|
_beforeFallback();
|
||||||
|
_delegate(_implementation());
|
||||||
|
}
|
||||||
|
|
||||||
|
fallback() external payable virtual {
|
||||||
|
_fallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
receive() external payable virtual {
|
||||||
|
_fallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _beforeFallback() internal virtual {}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IBeacon {
|
||||||
|
function implementation() external view returns (address);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IERC1822Proxiable {
|
||||||
|
function proxiableUUID() external view returns (bytes32);
|
||||||
|
}
|
||||||
|
|
||||||
|
library Address {
|
||||||
|
function isContract(address account) internal view returns (bool) {
|
||||||
|
return account.code.length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendValue(address payable recipient, uint256 amount) internal {
|
||||||
|
require(
|
||||||
|
address(this).balance >= amount,
|
||||||
|
"Address: insufficient balance"
|
||||||
|
);
|
||||||
|
|
||||||
|
(bool success, ) = recipient.call{value: amount}("");
|
||||||
|
require(
|
||||||
|
success,
|
||||||
|
"Address: unable to send value, recipient may have reverted"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function functionCall(
|
||||||
|
address target,
|
||||||
|
bytes memory data
|
||||||
|
) internal returns (bytes memory) {
|
||||||
|
return
|
||||||
|
functionCallWithValue(
|
||||||
|
target,
|
||||||
|
data,
|
||||||
|
0,
|
||||||
|
"Address: low-level call failed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function functionCall(
|
||||||
|
address target,
|
||||||
|
bytes memory data,
|
||||||
|
string memory errorMessage
|
||||||
|
) internal returns (bytes memory) {
|
||||||
|
return functionCallWithValue(target, data, 0, errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
function functionCallWithValue(
|
||||||
|
address target,
|
||||||
|
bytes memory data,
|
||||||
|
uint256 value
|
||||||
|
) internal returns (bytes memory) {
|
||||||
|
return
|
||||||
|
functionCallWithValue(
|
||||||
|
target,
|
||||||
|
data,
|
||||||
|
value,
|
||||||
|
"Address: low-level call with value failed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function functionCallWithValue(
|
||||||
|
address target,
|
||||||
|
bytes memory data,
|
||||||
|
uint256 value,
|
||||||
|
string memory errorMessage
|
||||||
|
) internal returns (bytes memory) {
|
||||||
|
require(
|
||||||
|
address(this).balance >= value,
|
||||||
|
"Address: insufficient balance for call"
|
||||||
|
);
|
||||||
|
(bool success, bytes memory returndata) = target.call{value: value}(
|
||||||
|
data
|
||||||
|
);
|
||||||
|
return
|
||||||
|
verifyCallResultFromTarget(
|
||||||
|
target,
|
||||||
|
success,
|
||||||
|
returndata,
|
||||||
|
errorMessage
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function functionStaticCall(
|
||||||
|
address target,
|
||||||
|
bytes memory data
|
||||||
|
) internal view returns (bytes memory) {
|
||||||
|
return
|
||||||
|
functionStaticCall(
|
||||||
|
target,
|
||||||
|
data,
|
||||||
|
"Address: low-level static call failed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function functionStaticCall(
|
||||||
|
address target,
|
||||||
|
bytes memory data,
|
||||||
|
string memory errorMessage
|
||||||
|
) internal view returns (bytes memory) {
|
||||||
|
(bool success, bytes memory returndata) = target.staticcall(data);
|
||||||
|
return
|
||||||
|
verifyCallResultFromTarget(
|
||||||
|
target,
|
||||||
|
success,
|
||||||
|
returndata,
|
||||||
|
errorMessage
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function functionDelegateCall(
|
||||||
|
address target,
|
||||||
|
bytes memory data
|
||||||
|
) internal returns (bytes memory) {
|
||||||
|
return
|
||||||
|
functionDelegateCall(
|
||||||
|
target,
|
||||||
|
data,
|
||||||
|
"Address: low-level delegate call failed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function functionDelegateCall(
|
||||||
|
address target,
|
||||||
|
bytes memory data,
|
||||||
|
string memory errorMessage
|
||||||
|
) internal returns (bytes memory) {
|
||||||
|
(bool success, bytes memory returndata) = target.delegatecall(data);
|
||||||
|
return
|
||||||
|
verifyCallResultFromTarget(
|
||||||
|
target,
|
||||||
|
success,
|
||||||
|
returndata,
|
||||||
|
errorMessage
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyCallResultFromTarget(
|
||||||
|
address target,
|
||||||
|
bool success,
|
||||||
|
bytes memory returndata,
|
||||||
|
string memory errorMessage
|
||||||
|
) internal view returns (bytes memory) {
|
||||||
|
if (success) {
|
||||||
|
if (returndata.length == 0) {
|
||||||
|
require(isContract(target), "Address: call to non-contract");
|
||||||
|
}
|
||||||
|
return returndata;
|
||||||
|
} else {
|
||||||
|
_revert(returndata, errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function verifyCallResult(
|
||||||
|
bool success,
|
||||||
|
bytes memory returndata,
|
||||||
|
string memory errorMessage
|
||||||
|
) internal pure returns (bytes memory) {
|
||||||
|
if (success) {
|
||||||
|
return returndata;
|
||||||
|
} else {
|
||||||
|
_revert(returndata, errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _revert(
|
||||||
|
bytes memory returndata,
|
||||||
|
string memory errorMessage
|
||||||
|
) private pure {
|
||||||
|
if (returndata.length > 0) {
|
||||||
|
assembly {
|
||||||
|
let returndata_size := mload(returndata)
|
||||||
|
revert(add(32, returndata), returndata_size)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
revert(errorMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
library StorageSlot {
|
||||||
|
struct AddressSlot {
|
||||||
|
address value;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BooleanSlot {
|
||||||
|
bool value;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Bytes32Slot {
|
||||||
|
bytes32 value;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Uint256Slot {
|
||||||
|
uint256 value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAddressSlot(
|
||||||
|
bytes32 slot
|
||||||
|
) internal pure returns (AddressSlot storage r) {
|
||||||
|
assembly {
|
||||||
|
r.slot := slot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBooleanSlot(
|
||||||
|
bytes32 slot
|
||||||
|
) internal pure returns (BooleanSlot storage r) {
|
||||||
|
assembly {
|
||||||
|
r.slot := slot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBytes32Slot(
|
||||||
|
bytes32 slot
|
||||||
|
) internal pure returns (Bytes32Slot storage r) {
|
||||||
|
assembly {
|
||||||
|
r.slot := slot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUint256Slot(
|
||||||
|
bytes32 slot
|
||||||
|
) internal pure returns (Uint256Slot storage r) {
|
||||||
|
assembly {
|
||||||
|
r.slot := slot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract contract ERC1967Upgrade {
|
||||||
|
bytes32 private constant _ROLLBACK_SLOT =
|
||||||
|
0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;
|
||||||
|
|
||||||
|
bytes32 internal constant _IMPLEMENTATION_SLOT =
|
||||||
|
0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
|
||||||
|
|
||||||
|
event Upgraded(address indexed implementation);
|
||||||
|
|
||||||
|
function _getImplementation() internal view returns (address) {
|
||||||
|
return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _setImplementation(address newImplementation) private {
|
||||||
|
require(
|
||||||
|
Address.isContract(newImplementation),
|
||||||
|
"ERC1967: new implementation is not a contract"
|
||||||
|
);
|
||||||
|
StorageSlot
|
||||||
|
.getAddressSlot(_IMPLEMENTATION_SLOT)
|
||||||
|
.value = newImplementation;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _upgradeTo(address newImplementation) internal {
|
||||||
|
_setImplementation(newImplementation);
|
||||||
|
emit Upgraded(newImplementation);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _upgradeToAndCall(
|
||||||
|
address newImplementation,
|
||||||
|
bytes memory data,
|
||||||
|
bool forceCall
|
||||||
|
) internal {
|
||||||
|
_upgradeTo(newImplementation);
|
||||||
|
if (data.length > 0 || forceCall) {
|
||||||
|
Address.functionDelegateCall(newImplementation, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function _upgradeToAndCallUUPS(
|
||||||
|
address newImplementation,
|
||||||
|
bytes memory data,
|
||||||
|
bool forceCall
|
||||||
|
) internal {
|
||||||
|
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
|
||||||
|
_setImplementation(newImplementation);
|
||||||
|
} else {
|
||||||
|
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (
|
||||||
|
bytes32 slot
|
||||||
|
) {
|
||||||
|
require(
|
||||||
|
slot == _IMPLEMENTATION_SLOT,
|
||||||
|
"ERC1967Upgrade: unsupported proxiableUUID"
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
revert("ERC1967Upgrade: new implementation is not UUPS");
|
||||||
|
}
|
||||||
|
_upgradeToAndCall(newImplementation, data, forceCall);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 internal constant _ADMIN_SLOT =
|
||||||
|
0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
|
||||||
|
|
||||||
|
event AdminChanged(address previousAdmin, address newAdmin);
|
||||||
|
|
||||||
|
function _getAdmin() internal view returns (address) {
|
||||||
|
return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _setAdmin(address newAdmin) private {
|
||||||
|
require(
|
||||||
|
newAdmin != address(0),
|
||||||
|
"ERC1967: new admin is the zero address"
|
||||||
|
);
|
||||||
|
StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _changeAdmin(address newAdmin) internal {
|
||||||
|
emit AdminChanged(_getAdmin(), newAdmin);
|
||||||
|
_setAdmin(newAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes32 internal constant _BEACON_SLOT =
|
||||||
|
0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;
|
||||||
|
|
||||||
|
event BeaconUpgraded(address indexed beacon);
|
||||||
|
|
||||||
|
function _getBeacon() internal view returns (address) {
|
||||||
|
return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _setBeacon(address newBeacon) private {
|
||||||
|
require(
|
||||||
|
Address.isContract(newBeacon),
|
||||||
|
"ERC1967: new beacon is not a contract"
|
||||||
|
);
|
||||||
|
require(
|
||||||
|
Address.isContract(IBeacon(newBeacon).implementation()),
|
||||||
|
"ERC1967: beacon implementation is not a contract"
|
||||||
|
);
|
||||||
|
StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
|
||||||
|
}
|
||||||
|
|
||||||
|
function _upgradeBeaconToAndCall(
|
||||||
|
address newBeacon,
|
||||||
|
bytes memory data,
|
||||||
|
bool forceCall
|
||||||
|
) internal {
|
||||||
|
_setBeacon(newBeacon);
|
||||||
|
emit BeaconUpgraded(newBeacon);
|
||||||
|
if (data.length > 0 || forceCall) {
|
||||||
|
Address.functionDelegateCall(
|
||||||
|
IBeacon(newBeacon).implementation(),
|
||||||
|
data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract ERC1967Proxy is Proxy, ERC1967Upgrade {
|
||||||
|
constructor(address _logic, bytes memory _data) payable {
|
||||||
|
_upgradeToAndCall(_logic, _data, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _implementation()
|
||||||
|
internal
|
||||||
|
view
|
||||||
|
virtual
|
||||||
|
override
|
||||||
|
returns (address impl)
|
||||||
|
{
|
||||||
|
return ERC1967Upgrade._getImplementation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract TransparentUpgradeableProxy is ERC1967Proxy {
|
||||||
|
constructor(address _logic) payable ERC1967Proxy(_logic, "") {
|
||||||
|
_changeAdmin(msg.sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
modifier ifAdmin() {
|
||||||
|
if (msg.sender == _getAdmin()) {
|
||||||
|
_;
|
||||||
|
} else {
|
||||||
|
_fallback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function admin() external payable ifAdmin returns (address admin_) {
|
||||||
|
_requireZeroValue();
|
||||||
|
admin_ = _getAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
function implementation()
|
||||||
|
external
|
||||||
|
payable
|
||||||
|
ifAdmin
|
||||||
|
returns (address implementation_)
|
||||||
|
{
|
||||||
|
_requireZeroValue();
|
||||||
|
implementation_ = _implementation();
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeAdmin(address newAdmin) external payable virtual ifAdmin {
|
||||||
|
_requireZeroValue();
|
||||||
|
_changeAdmin(newAdmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgradeTo(address newImplementation) external payable ifAdmin {
|
||||||
|
_requireZeroValue();
|
||||||
|
_upgradeToAndCall(newImplementation, bytes(""), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function upgradeToAndCall(
|
||||||
|
address newImplementation,
|
||||||
|
bytes calldata data
|
||||||
|
) external payable ifAdmin {
|
||||||
|
_upgradeToAndCall(newImplementation, data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _admin() internal view virtual returns (address) {
|
||||||
|
return _getAdmin();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _beforeFallback() internal virtual override {
|
||||||
|
require(
|
||||||
|
msg.sender != _getAdmin(),
|
||||||
|
"TransparentUpgradeableProxy: admin cannot fallback to proxy target"
|
||||||
|
);
|
||||||
|
super._beforeFallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
function _requireZeroValue() private {
|
||||||
|
require(msg.value == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract TestHelper {
|
||||||
|
function getValue(address proxyAddress) public returns (uint256) {
|
||||||
|
Implementation2 proxyInstance2 = Implementation2(proxyAddress);
|
||||||
|
return proxyInstance2.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contract TransparentUpgradeableProxyTestRunner {
|
||||||
|
function test() public {
|
||||||
|
assert(0 == getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
function getValue() public returns (uint256) {
|
||||||
|
Implementation4 instance4 = new Implementation4();
|
||||||
|
TransparentUpgradeableProxy proxy = new TransparentUpgradeableProxy(
|
||||||
|
address(instance4)
|
||||||
|
);
|
||||||
|
Implementation2 instance2 = new Implementation2();
|
||||||
|
proxy.upgradeTo(address(instance2));
|
||||||
|
//use helper because proxy admin can't call getValue()
|
||||||
|
TestHelper h = new TestHelper();
|
||||||
|
return h.getValue(address(proxy));
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@ set -o pipefail
|
|||||||
# 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 . -name \*.sol -print0 |
|
find . -maxdepth 1 -name \*.sol -print0 |
|
||||||
xargs -0 -I{} bash -euc -o pipefail '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/)'
|
||||||
|
|
||||||
|
|
||||||
@ -17,3 +17,7 @@ for filename in Constructor TestApp ValueSender Create2Factory DeployValueTest;
|
|||||||
solc --bin $filename.sol | tail -n5|head -n1 | tr -d "\n" > $filename.hex
|
solc --bin $filename.sol | tail -n5|head -n1 | tr -d "\n" > $filename.hex
|
||||||
done
|
done
|
||||||
|
|
||||||
|
for filename in TransparentUpgradeableProxy ; do
|
||||||
|
echo $filename
|
||||||
|
solc --bin $filename.sol | tail -n1| tr -d "\n" > $filename.hex
|
||||||
|
done
|
||||||
|
@ -166,7 +166,7 @@ func testDMExportAsFile(ctx context.Context, client *kit.TestFullNode, expDirect
|
|||||||
func testV0RetrievalAsFile(ctx context.Context, client *kit.TestFullNode, retOrder api0.RetrievalOrder, tempDir string) error {
|
func testV0RetrievalAsFile(ctx context.Context, client *kit.TestFullNode, retOrder api0.RetrievalOrder, tempDir string) error {
|
||||||
out := tempDir + string(os.PathSeparator) + "exp-test" + retOrder.Root.String()
|
out := tempDir + string(os.PathSeparator) + "exp-test" + retOrder.Root.String()
|
||||||
|
|
||||||
cv0 := &api0.WrapperV1Full{client.FullNode} //nolint:govet
|
cv0 := &api0.WrapperV1Full{FullNode: client.FullNode}
|
||||||
err := cv0.ClientRetrieve(ctx, retOrder, &api.FileRef{
|
err := cv0.ClientRetrieve(ctx, retOrder, &api.FileRef{
|
||||||
Path: out,
|
Path: out,
|
||||||
})
|
})
|
||||||
@ -220,7 +220,7 @@ func tesV0RetrievalAsCar(ctx context.Context, client *kit.TestFullNode, retOrder
|
|||||||
}
|
}
|
||||||
defer out.Close() //nolint:errcheck
|
defer out.Close() //nolint:errcheck
|
||||||
|
|
||||||
cv0 := &api0.WrapperV1Full{client.FullNode} //nolint:govet
|
cv0 := &api0.WrapperV1Full{FullNode: client.FullNode}
|
||||||
err = cv0.ClientRetrieve(ctx, retOrder, &api.FileRef{
|
err = cv0.ClientRetrieve(ctx, retOrder, &api.FileRef{
|
||||||
Path: out.Name(),
|
Path: out.Name(),
|
||||||
IsCAR: true,
|
IsCAR: true,
|
||||||
|
48
itests/eth_api_test.go
Normal file
48
itests/eth_api_test.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package itests
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/builtin"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||||
|
"github.com/filecoin-project/lotus/chain/wallet/key"
|
||||||
|
"github.com/filecoin-project/lotus/itests/kit"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEthAddressToFilecoinAddress(t *testing.T) {
|
||||||
|
// Disable EthRPC to confirm that this method does NOT need the EthEnableRPC config set to true
|
||||||
|
client, _, _ := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.DisableEthRPC())
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
secpKey, err := key.GenerateKey(types.KTDelegated)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
filecoinKeyAddr, err := client.WalletImport(ctx, &secpKey.KeyInfo)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(filecoinKeyAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
apiFilAddr, err := client.EthAddressToFilecoinAddress(ctx, ethAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, filecoinKeyAddr, apiFilAddr)
|
||||||
|
|
||||||
|
filecoinIdArr := builtin.StorageMarketActorAddr
|
||||||
|
ethAddr, err = ethtypes.EthAddressFromFilecoinAddress(filecoinIdArr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
apiFilAddr, err = client.EthAddressToFilecoinAddress(ctx, ethAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, filecoinIdArr, apiFilAddr)
|
||||||
|
|
||||||
|
}
|
@ -10,15 +10,16 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||||
"github.com/filecoin-project/lotus/itests/kit"
|
"github.com/filecoin-project/lotus/itests/kit"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestGetCode ensures that GetCode returns the correct results for:
|
// TestGetCodeAndNonce ensures that GetCode and GetTransactionCount return the correct results for:
|
||||||
// 1. Placeholders.
|
// 1. Placeholders.
|
||||||
// 2. Non-existent actors.
|
// 2. Non-existent actors.
|
||||||
// 3. Normal EVM actors.
|
// 3. Normal EVM actors.
|
||||||
// 4. Self-destructed EVM actors.
|
// 4. Self-destructed EVM actors.
|
||||||
func TestGetCode(t *testing.T) {
|
func TestGetCodeAndNonce(t *testing.T) {
|
||||||
kit.QuietMiningLogs()
|
kit.QuietMiningLogs()
|
||||||
|
|
||||||
blockTime := 100 * time.Millisecond
|
blockTime := 100 * time.Millisecond
|
||||||
@ -28,7 +29,7 @@ func TestGetCode(t *testing.T) {
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Accounts should have empty code.
|
// Accounts should have empty code, empty nonce.
|
||||||
{
|
{
|
||||||
// A random eth address should have no code.
|
// A random eth address should have no code.
|
||||||
_, ethAddr, filAddr := client.EVM().NewAccount()
|
_, ethAddr, filAddr := client.EVM().NewAccount()
|
||||||
@ -36,6 +37,11 @@ func TestGetCode(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Empty(t, bytecode)
|
require.Empty(t, bytecode)
|
||||||
|
|
||||||
|
// Nonce should also be zero
|
||||||
|
nonce, err := client.EVM().EthGetTransactionCount(ctx, ethAddr, "latest")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Zero(t, nonce)
|
||||||
|
|
||||||
// send some funds to the account.
|
// send some funds to the account.
|
||||||
kit.SendFunds(ctx, t, client, filAddr, types.FromFil(10))
|
kit.SendFunds(ctx, t, client, filAddr, types.FromFil(10))
|
||||||
|
|
||||||
@ -43,6 +49,11 @@ func TestGetCode(t *testing.T) {
|
|||||||
bytecode, err = client.EVM().EthGetCode(ctx, ethAddr, "latest")
|
bytecode, err = client.EVM().EthGetCode(ctx, ethAddr, "latest")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Empty(t, bytecode)
|
require.Empty(t, bytecode)
|
||||||
|
|
||||||
|
// Nonce should still be zero.
|
||||||
|
nonce, err = client.EVM().EthGetTransactionCount(ctx, ethAddr, "latest")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Zero(t, nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check contract code.
|
// Check contract code.
|
||||||
@ -61,6 +72,11 @@ func TestGetCode(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, bytecode)
|
require.NotEmpty(t, bytecode)
|
||||||
|
|
||||||
|
// Nonce should be one.
|
||||||
|
nonce, err := client.EVM().EthGetTransactionCount(ctx, contractAddr, "latest")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ethtypes.EthUint64(1), nonce)
|
||||||
|
|
||||||
// Destroy it.
|
// Destroy it.
|
||||||
_, _, err = client.EVM().InvokeContractByFuncName(ctx, client.DefaultKey.Address, contractFilAddr, "destroy()", nil)
|
_, _, err = client.EVM().InvokeContractByFuncName(ctx, client.DefaultKey.Address, contractFilAddr, "destroy()", nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -69,6 +85,11 @@ func TestGetCode(t *testing.T) {
|
|||||||
bytecode, err = client.EVM().EthGetCode(ctx, contractAddr, "latest")
|
bytecode, err = client.EVM().EthGetCode(ctx, contractAddr, "latest")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Empty(t, bytecode)
|
require.Empty(t, bytecode)
|
||||||
|
|
||||||
|
// Nonce should go back to zero
|
||||||
|
nonce, err = client.EVM().EthGetTransactionCount(ctx, contractAddr, "latest")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Zero(t, nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ func TestEthFeeHistory(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
// Wait for the network to create 20 blocks
|
// Wait for the network to create 20 blocks
|
||||||
<-time.After(20 * blockTime)
|
client.WaitTillChain(ctx, kit.HeightAtLeast(20))
|
||||||
|
|
||||||
history, err := client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
history, err := client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||||
json.Marshal([]interface{}{5, "0x10"}),
|
json.Marshal([]interface{}{5, "0x10"}),
|
||||||
@ -37,6 +37,7 @@ func TestEthFeeHistory(t *testing.T) {
|
|||||||
require.Equal(6, len(history.BaseFeePerGas))
|
require.Equal(6, len(history.BaseFeePerGas))
|
||||||
require.Equal(5, len(history.GasUsedRatio))
|
require.Equal(5, len(history.GasUsedRatio))
|
||||||
require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock)
|
require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock)
|
||||||
|
require.Nil(history.Reward)
|
||||||
|
|
||||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||||
json.Marshal([]interface{}{"5", "0x10"}),
|
json.Marshal([]interface{}{"5", "0x10"}),
|
||||||
@ -45,6 +46,7 @@ func TestEthFeeHistory(t *testing.T) {
|
|||||||
require.Equal(6, len(history.BaseFeePerGas))
|
require.Equal(6, len(history.BaseFeePerGas))
|
||||||
require.Equal(5, len(history.GasUsedRatio))
|
require.Equal(5, len(history.GasUsedRatio))
|
||||||
require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock)
|
require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock)
|
||||||
|
require.Nil(history.Reward)
|
||||||
|
|
||||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||||
json.Marshal([]interface{}{"0x10", "0x12"}),
|
json.Marshal([]interface{}{"0x10", "0x12"}),
|
||||||
@ -53,6 +55,7 @@ func TestEthFeeHistory(t *testing.T) {
|
|||||||
require.Equal(17, len(history.BaseFeePerGas))
|
require.Equal(17, len(history.BaseFeePerGas))
|
||||||
require.Equal(16, len(history.GasUsedRatio))
|
require.Equal(16, len(history.GasUsedRatio))
|
||||||
require.Equal(ethtypes.EthUint64(18-16+1), history.OldestBlock)
|
require.Equal(ethtypes.EthUint64(18-16+1), history.OldestBlock)
|
||||||
|
require.Nil(history.Reward)
|
||||||
|
|
||||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||||
json.Marshal([]interface{}{5, "0x10"}),
|
json.Marshal([]interface{}{5, "0x10"}),
|
||||||
@ -61,6 +64,7 @@ func TestEthFeeHistory(t *testing.T) {
|
|||||||
require.Equal(6, len(history.BaseFeePerGas))
|
require.Equal(6, len(history.BaseFeePerGas))
|
||||||
require.Equal(5, len(history.GasUsedRatio))
|
require.Equal(5, len(history.GasUsedRatio))
|
||||||
require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock)
|
require.Equal(ethtypes.EthUint64(16-5+1), history.OldestBlock)
|
||||||
|
require.Nil(history.Reward)
|
||||||
|
|
||||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||||
json.Marshal([]interface{}{5, "10"}),
|
json.Marshal([]interface{}{5, "10"}),
|
||||||
@ -69,19 +73,28 @@ func TestEthFeeHistory(t *testing.T) {
|
|||||||
require.Equal(6, len(history.BaseFeePerGas))
|
require.Equal(6, len(history.BaseFeePerGas))
|
||||||
require.Equal(5, len(history.GasUsedRatio))
|
require.Equal(5, len(history.GasUsedRatio))
|
||||||
require.Equal(ethtypes.EthUint64(10-5+1), history.OldestBlock)
|
require.Equal(ethtypes.EthUint64(10-5+1), history.OldestBlock)
|
||||||
|
require.Nil(history.Reward)
|
||||||
|
|
||||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||||
json.Marshal([]interface{}{5, "10", &[]float64{0.25, 0.50, 0.75}}),
|
json.Marshal([]interface{}{5, "10", &[]float64{25, 50, 75}}),
|
||||||
).Assert(require.NoError))
|
).Assert(require.NoError))
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
require.Equal(6, len(history.BaseFeePerGas))
|
require.Equal(6, len(history.BaseFeePerGas))
|
||||||
require.Equal(5, len(history.GasUsedRatio))
|
require.Equal(5, len(history.GasUsedRatio))
|
||||||
require.Equal(ethtypes.EthUint64(10-5+1), history.OldestBlock)
|
require.Equal(ethtypes.EthUint64(10-5+1), history.OldestBlock)
|
||||||
require.NotNil(history.Reward)
|
require.NotNil(history.Reward)
|
||||||
require.Equal(0, len(*history.Reward))
|
require.Equal(5, len(*history.Reward))
|
||||||
|
for _, arr := range *history.Reward {
|
||||||
|
require.Equal(3, len(arr))
|
||||||
|
}
|
||||||
|
|
||||||
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||||
json.Marshal([]interface{}{1025, "10", &[]float64{0.25, 0.50, 0.75}}),
|
json.Marshal([]interface{}{1025, "10", &[]float64{25, 50, 75}}),
|
||||||
).Assert(require.NoError))
|
).Assert(require.NoError))
|
||||||
require.Error(err)
|
require.Error(err)
|
||||||
|
|
||||||
|
history, err = client.EthFeeHistory(ctx, result.Wrap[jsonrpc.RawParams](
|
||||||
|
json.Marshal([]interface{}{5, "10", &[]float64{}}),
|
||||||
|
).Assert(require.NoError))
|
||||||
|
require.NoError(err)
|
||||||
}
|
}
|
||||||
|
@ -136,6 +136,113 @@ func TestEthNewPendingTransactionFilter(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEthNewPendingTransactionSub(t *testing.T) {
|
||||||
|
require := require.New(t)
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
kit.QuietAllLogsExcept("events", "messagepool")
|
||||||
|
|
||||||
|
client, _, ens := kit.EnsembleMinimal(t, kit.MockProofs(), kit.ThroughRPC(), kit.WithEthRPC())
|
||||||
|
ens.InterconnectAll().BeginMining(10 * time.Millisecond)
|
||||||
|
|
||||||
|
// create a new address where to send funds.
|
||||||
|
addr, err := client.WalletNew(ctx, types.KTBLS)
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
|
// get the existing balance from the default wallet to then split it.
|
||||||
|
bal, err := client.WalletBalance(ctx, client.DefaultKey.Address)
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
|
// install filter
|
||||||
|
subId, err := client.EthSubscribe(ctx, res.Wrap[jsonrpc.RawParams](json.Marshal(ethtypes.EthSubscribeParams{EventType: "newPendingTransactions"})).Assert(require.NoError))
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
|
var subResponses []ethtypes.EthSubscriptionResponse
|
||||||
|
err = client.EthSubRouter.AddSub(ctx, subId, func(ctx context.Context, resp *ethtypes.EthSubscriptionResponse) error {
|
||||||
|
subResponses = append(subResponses, *resp)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
|
const iterations = 100
|
||||||
|
|
||||||
|
// we'll send half our balance (saving the other half for gas),
|
||||||
|
// in `iterations` increments.
|
||||||
|
toSend := big.Div(bal, big.NewInt(2))
|
||||||
|
each := big.Div(toSend, big.NewInt(iterations))
|
||||||
|
|
||||||
|
waitAllCh := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
headChangeCh, err := client.ChainNotify(ctx)
|
||||||
|
require.NoError(err)
|
||||||
|
<-headChangeCh // skip hccurrent
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
close(waitAllCh)
|
||||||
|
}()
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return
|
||||||
|
case headChanges := <-headChangeCh:
|
||||||
|
for _, change := range headChanges {
|
||||||
|
if change.Type == store.HCApply {
|
||||||
|
msgs, err := client.ChainGetMessagesInTipset(ctx, change.Val.Key())
|
||||||
|
require.NoError(err)
|
||||||
|
count += len(msgs)
|
||||||
|
if count == iterations {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var sms []*types.SignedMessage
|
||||||
|
for i := 0; i < iterations; i++ {
|
||||||
|
msg := &types.Message{
|
||||||
|
From: client.DefaultKey.Address,
|
||||||
|
To: addr,
|
||||||
|
Value: each,
|
||||||
|
}
|
||||||
|
|
||||||
|
sm, err := client.MpoolPushMessage(ctx, msg, nil)
|
||||||
|
require.NoError(err)
|
||||||
|
require.EqualValues(i, sm.Message.Nonce)
|
||||||
|
|
||||||
|
sms = append(sms, sm)
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-waitAllCh:
|
||||||
|
case <-ctx.Done():
|
||||||
|
t.Errorf("timeout waiting to pack messages")
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := make(map[string]bool)
|
||||||
|
for _, sm := range sms {
|
||||||
|
hash, err := ethtypes.EthHashFromCid(sm.Cid())
|
||||||
|
require.NoError(err)
|
||||||
|
expected[hash.String()] = false
|
||||||
|
}
|
||||||
|
|
||||||
|
// expect to have seen iteration number of mpool messages
|
||||||
|
require.Equal(len(subResponses), len(expected), "expected number of filter results to equal number of messages")
|
||||||
|
|
||||||
|
for _, txid := range subResponses {
|
||||||
|
expected[txid.Result.(string)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, found := range expected {
|
||||||
|
require.True(found)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestEthNewBlockFilter(t *testing.T) {
|
func TestEthNewBlockFilter(t *testing.T) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
@ -265,6 +265,20 @@ func TestFEVMDelegateCall(t *testing.T) {
|
|||||||
expectedResultActor, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
|
expectedResultActor, err := hex.DecodeString("0000000000000000000000000000000000000000000000000000000000000000")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, result, expectedResultActor)
|
require.Equal(t, result, expectedResultActor)
|
||||||
|
|
||||||
|
// The implementation's storage should not have been updated.
|
||||||
|
actorAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(actorAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
value, err := client.EVM().EthGetStorageAt(ctx, actorAddrEth, nil, "latest")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ethtypes.EthBytes(make([]byte, 32)), value)
|
||||||
|
|
||||||
|
// The storage actor's storage _should_ have been updated
|
||||||
|
storageAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(storageAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
value, err = client.EVM().EthGetStorageAt(ctx, storageAddrEth, nil, "latest")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, ethtypes.EthBytes(expectedResult), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestFEVMDelegateCallRevert makes a delegatecall action and then calls revert.
|
// TestFEVMDelegateCallRevert makes a delegatecall action and then calls revert.
|
||||||
@ -843,3 +857,100 @@ func TestFEVMBareTransferTriggersSmartContractLogic(t *testing.T) {
|
|||||||
// The receive() function emits one log, that's how we know we hit it.
|
// The receive() function emits one log, that's how we know we hit it.
|
||||||
require.Len(t, receipt.Logs, 1)
|
require.Len(t, receipt.Logs, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test ensures that we can deploy new contracts from a solidity call to `transfer` without
|
||||||
|
// exceeding the 10M gas limit.
|
||||||
|
func TestFEVMTestDeployOnTransfer(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)
|
||||||
|
|
||||||
|
//send to some random address.
|
||||||
|
params := [32]byte{}
|
||||||
|
params[30] = 0xff
|
||||||
|
randomAddr, err := ethtypes.CastEthAddress(params[12:])
|
||||||
|
value := big.NewInt(100)
|
||||||
|
entryPoint := kit.CalcFuncSignature("sendEthToB(address)")
|
||||||
|
require.NoError(t, err)
|
||||||
|
ret, err := client.EVM().InvokeSolidityWithValue(ctx, fromAddr, contractAddr, entryPoint, params[:], value)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, ret.Receipt.ExitCode.IsSuccess())
|
||||||
|
|
||||||
|
balance, err := client.EVM().EthGetBalance(ctx, randomAddr, "latest")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, value.Int, balance.Int)
|
||||||
|
|
||||||
|
filAddr, err := randomAddr.ToFilecoinAddress()
|
||||||
|
require.NoError(t, err)
|
||||||
|
client.AssertActorType(ctx, filAddr, manifest.PlaceholderKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFEVMProxyUpgradeable(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
//install transparently upgradeable proxy
|
||||||
|
proxyFilename := "contracts/TransparentUpgradeableProxy.hex"
|
||||||
|
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, proxyFilename)
|
||||||
|
|
||||||
|
_, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "test()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFEVMGetBlockDifficulty(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
//install contract
|
||||||
|
filenameActor := "contracts/GetDifficulty.hex"
|
||||||
|
fromAddr, contractAddr := client.EVM().DeployContractFromFilename(ctx, filenameActor)
|
||||||
|
|
||||||
|
ret, _, err := client.EVM().InvokeContractByFuncName(ctx, fromAddr, contractAddr, "getDifficulty()", []byte{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(ret), 32)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFEVMErrorParsing(t *testing.T) {
|
||||||
|
ctx, cancel, client := kit.SetupFEVMTest(t)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
e := client.EVM()
|
||||||
|
|
||||||
|
_, contractAddr := e.DeployContractFromFilename(ctx, "contracts/Errors.hex")
|
||||||
|
contractAddrEth, err := ethtypes.EthAddressFromFilecoinAddress(contractAddr)
|
||||||
|
require.NoError(t, err)
|
||||||
|
customError := ethtypes.EthBytes(kit.CalcFuncSignature("CustomError()")).String()
|
||||||
|
for sig, expected := range map[string]string{
|
||||||
|
"failRevertEmpty()": "none",
|
||||||
|
"failRevertReason()": "Error(my reason)",
|
||||||
|
"failAssert()": "Assert()",
|
||||||
|
"failDivZero()": "DivideByZero()",
|
||||||
|
"failCustom()": customError,
|
||||||
|
} {
|
||||||
|
sig := sig
|
||||||
|
expected := fmt.Sprintf("exit 33, revert reason: %s, vm error", expected)
|
||||||
|
t.Run(sig, func(t *testing.T) {
|
||||||
|
entryPoint := kit.CalcFuncSignature(sig)
|
||||||
|
t.Run("EthCall", func(t *testing.T) {
|
||||||
|
_, err := e.EthCall(ctx, ethtypes.EthCall{
|
||||||
|
To: &contractAddrEth,
|
||||||
|
Data: entryPoint,
|
||||||
|
}, "latest")
|
||||||
|
require.ErrorContains(t, err, expected)
|
||||||
|
})
|
||||||
|
t.Run("EthEstimateGas", func(t *testing.T) {
|
||||||
|
_, err := e.EthEstimateGas(ctx, ethtypes.EthCall{
|
||||||
|
To: &contractAddrEth,
|
||||||
|
Data: entryPoint,
|
||||||
|
})
|
||||||
|
require.ErrorContains(t, err, expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -104,6 +104,10 @@ func (e *EVM) DeployContractFromFilename(ctx context.Context, binFilename string
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte) (*api.MsgLookup, error) {
|
func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte) (*api.MsgLookup, error) {
|
||||||
|
return e.InvokeSolidityWithValue(ctx, sender, target, selector, inputData, big.Zero())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *EVM) InvokeSolidityWithValue(ctx context.Context, sender address.Address, target address.Address, selector []byte, inputData []byte, value big.Int) (*api.MsgLookup, error) {
|
||||||
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)
|
||||||
@ -115,7 +119,7 @@ func (e *EVM) InvokeSolidity(ctx context.Context, sender address.Address, target
|
|||||||
msg := &types.Message{
|
msg := &types.Message{
|
||||||
To: target,
|
To: target,
|
||||||
From: sender,
|
From: sender,
|
||||||
Value: big.Zero(),
|
Value: value,
|
||||||
Method: builtintypes.MethodsEVM.InvokeContract,
|
Method: builtintypes.MethodsEVM.InvokeContract,
|
||||||
GasLimit: build.BlockGasLimit, // note: we hardcode block gas limit due to slightly broken gas estimation - https://github.com/filecoin-project/lotus/issues/10041
|
GasLimit: build.BlockGasLimit, // note: we hardcode block gas limit due to slightly broken gas estimation - https://github.com/filecoin-project/lotus/issues/10041
|
||||||
Params: params,
|
Params: params,
|
||||||
|
@ -178,7 +178,7 @@
|
|||||||
"s",
|
"s",
|
||||||
"type",
|
"type",
|
||||||
"value",
|
"value",
|
||||||
"yParity"
|
"v"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
@ -253,8 +253,8 @@
|
|||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "Chain ID that this transaction is valid on."
|
"description": "Chain ID that this transaction is valid on."
|
||||||
},
|
},
|
||||||
"yParity": {
|
"v": {
|
||||||
"title": "yParity",
|
"title": "v",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||||
@ -285,7 +285,7 @@
|
|||||||
"s",
|
"s",
|
||||||
"type",
|
"type",
|
||||||
"value",
|
"value",
|
||||||
"yParity"
|
"v"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
@ -354,8 +354,8 @@
|
|||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "Chain ID that this transaction is valid on."
|
"description": "Chain ID that this transaction is valid on."
|
||||||
},
|
},
|
||||||
"yParity": {
|
"v": {
|
||||||
"title": "yParity",
|
"title": "v",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||||
@ -649,7 +649,7 @@
|
|||||||
"s",
|
"s",
|
||||||
"type",
|
"type",
|
||||||
"value",
|
"value",
|
||||||
"yParity"
|
"v"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
@ -724,8 +724,8 @@
|
|||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "Chain ID that this transaction is valid on."
|
"description": "Chain ID that this transaction is valid on."
|
||||||
},
|
},
|
||||||
"yParity": {
|
"v": {
|
||||||
"title": "yParity",
|
"title": "v",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||||
@ -756,7 +756,7 @@
|
|||||||
"s",
|
"s",
|
||||||
"type",
|
"type",
|
||||||
"value",
|
"value",
|
||||||
"yParity"
|
"v"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
@ -825,8 +825,8 @@
|
|||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "Chain ID that this transaction is valid on."
|
"description": "Chain ID that this transaction is valid on."
|
||||||
},
|
},
|
||||||
"yParity": {
|
"v": {
|
||||||
"title": "yParity",
|
"title": "v",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||||
@ -1794,9 +1794,9 @@
|
|||||||
"result": {
|
"result": {
|
||||||
"name": "Filter Identifier",
|
"name": "Filter Identifier",
|
||||||
"schema": {
|
"schema": {
|
||||||
"title": "hex encoded unsigned integer",
|
"title": "32 byte hex value",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$"
|
"pattern": "^0x[0-9a-f]{64}$"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1807,9 +1807,9 @@
|
|||||||
"result": {
|
"result": {
|
||||||
"name": "Filter Identifier",
|
"name": "Filter Identifier",
|
||||||
"schema": {
|
"schema": {
|
||||||
"title": "hex encoded unsigned integer",
|
"title": "32 byte hex value",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$"
|
"pattern": "^0x[0-9a-f]{64}$"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1820,9 +1820,9 @@
|
|||||||
"result": {
|
"result": {
|
||||||
"name": "Filter Identifier",
|
"name": "Filter Identifier",
|
||||||
"schema": {
|
"schema": {
|
||||||
"title": "hex encoded unsigned integer",
|
"title": "32 byte hex value",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$"
|
"pattern": "^0x[0-9a-f]{64}$"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1833,9 +1833,9 @@
|
|||||||
{
|
{
|
||||||
"name": "Filter Identifier",
|
"name": "Filter Identifier",
|
||||||
"schema": {
|
"schema": {
|
||||||
"title": "hex encoded unsigned integer",
|
"title": "32 byte hex value",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$"
|
"pattern": "^0x[0-9a-f]{64}$"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -1853,9 +1853,9 @@
|
|||||||
{
|
{
|
||||||
"name": "Filter Identifier",
|
"name": "Filter Identifier",
|
||||||
"schema": {
|
"schema": {
|
||||||
"title": "hex encoded unsigned integer",
|
"title": "32 byte hex value",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$"
|
"pattern": "^0x[0-9a-f]{64}$"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -1954,9 +1954,9 @@
|
|||||||
{
|
{
|
||||||
"name": "Filter Identifier",
|
"name": "Filter Identifier",
|
||||||
"schema": {
|
"schema": {
|
||||||
"title": "hex encoded unsigned integer",
|
"title": "32 byte hex value",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$"
|
"pattern": "^0x[0-9a-f]{64}$"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -3009,7 +3009,7 @@
|
|||||||
"s",
|
"s",
|
||||||
"type",
|
"type",
|
||||||
"value",
|
"value",
|
||||||
"yParity"
|
"v"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
@ -3084,8 +3084,8 @@
|
|||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "Chain ID that this transaction is valid on."
|
"description": "Chain ID that this transaction is valid on."
|
||||||
},
|
},
|
||||||
"yParity": {
|
"v": {
|
||||||
"title": "yParity",
|
"title": "v",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||||
@ -3116,7 +3116,7 @@
|
|||||||
"s",
|
"s",
|
||||||
"type",
|
"type",
|
||||||
"value",
|
"value",
|
||||||
"yParity"
|
"v"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
@ -3185,8 +3185,8 @@
|
|||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "Chain ID that this transaction is valid on."
|
"description": "Chain ID that this transaction is valid on."
|
||||||
},
|
},
|
||||||
"yParity": {
|
"v": {
|
||||||
"title": "yParity",
|
"title": "v",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||||
@ -3359,7 +3359,7 @@
|
|||||||
"s",
|
"s",
|
||||||
"type",
|
"type",
|
||||||
"value",
|
"value",
|
||||||
"yParity"
|
"v"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
@ -3434,8 +3434,8 @@
|
|||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "Chain ID that this transaction is valid on."
|
"description": "Chain ID that this transaction is valid on."
|
||||||
},
|
},
|
||||||
"yParity": {
|
"v": {
|
||||||
"title": "yParity",
|
"title": "v",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||||
@ -3466,7 +3466,7 @@
|
|||||||
"s",
|
"s",
|
||||||
"type",
|
"type",
|
||||||
"value",
|
"value",
|
||||||
"yParity"
|
"v"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
@ -3535,8 +3535,8 @@
|
|||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "Chain ID that this transaction is valid on."
|
"description": "Chain ID that this transaction is valid on."
|
||||||
},
|
},
|
||||||
"yParity": {
|
"v": {
|
||||||
"title": "yParity",
|
"title": "v",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||||
@ -3726,7 +3726,7 @@
|
|||||||
"s",
|
"s",
|
||||||
"type",
|
"type",
|
||||||
"value",
|
"value",
|
||||||
"yParity"
|
"v"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
@ -3801,8 +3801,8 @@
|
|||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "Chain ID that this transaction is valid on."
|
"description": "Chain ID that this transaction is valid on."
|
||||||
},
|
},
|
||||||
"yParity": {
|
"v": {
|
||||||
"title": "yParity",
|
"title": "v",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||||
@ -3833,7 +3833,7 @@
|
|||||||
"s",
|
"s",
|
||||||
"type",
|
"type",
|
||||||
"value",
|
"value",
|
||||||
"yParity"
|
"v"
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"type": {
|
"type": {
|
||||||
@ -3902,8 +3902,8 @@
|
|||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "Chain ID that this transaction is valid on."
|
"description": "Chain ID that this transaction is valid on."
|
||||||
},
|
},
|
||||||
"yParity": {
|
"v": {
|
||||||
"title": "yParity",
|
"title": "v",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
"pattern": "^0x([1-9a-f]+[0-9a-f]*|0)$",
|
||||||
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
"description": "The parity (0 for even, 1 for odd) of the y-value of the secp256k1 signature."
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
|
|
||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
"github.com/filecoin-project/go-jsonrpc"
|
"github.com/filecoin-project/go-jsonrpc"
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/api"
|
"github.com/filecoin-project/lotus/api"
|
||||||
@ -16,6 +17,10 @@ var ErrModuleDisabled = errors.New("module disabled, enable with Fevm.EnableEthR
|
|||||||
|
|
||||||
type EthModuleDummy struct{}
|
type EthModuleDummy struct{}
|
||||||
|
|
||||||
|
func (e *EthModuleDummy) EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) {
|
||||||
|
return address.Undef, ErrModuleDisabled
|
||||||
|
}
|
||||||
|
|
||||||
func (e *EthModuleDummy) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) {
|
func (e *EthModuleDummy) EthGetMessageCidByTransactionHash(ctx context.Context, txHash *ethtypes.EthHash) (*cid.Cid, error) {
|
||||||
return nil, ErrModuleDisabled
|
return nil, ErrModuleDisabled
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
@ -30,6 +31,7 @@ import (
|
|||||||
"github.com/filecoin-project/lotus/build"
|
"github.com/filecoin-project/lotus/build"
|
||||||
"github.com/filecoin-project/lotus/chain/actors"
|
"github.com/filecoin-project/lotus/chain/actors"
|
||||||
builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin"
|
builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||||
|
builtinevm "github.com/filecoin-project/lotus/chain/actors/builtin/evm"
|
||||||
"github.com/filecoin-project/lotus/chain/ethhashlookup"
|
"github.com/filecoin-project/lotus/chain/ethhashlookup"
|
||||||
"github.com/filecoin-project/lotus/chain/events/filter"
|
"github.com/filecoin-project/lotus/chain/events/filter"
|
||||||
"github.com/filecoin-project/lotus/chain/messagepool"
|
"github.com/filecoin-project/lotus/chain/messagepool"
|
||||||
@ -180,6 +182,10 @@ func (a *EthModule) EthAccounts(context.Context) ([]ethtypes.EthAddress, error)
|
|||||||
return []ethtypes.EthAddress{}, nil
|
return []ethtypes.EthAddress{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *EthAPI) EthAddressToFilecoinAddress(ctx context.Context, ethAddress ethtypes.EthAddress) (address.Address, error) {
|
||||||
|
return ethAddress.ToFilecoinAddress()
|
||||||
|
}
|
||||||
|
|
||||||
func (a *EthModule) countTipsetMsgs(ctx context.Context, ts *types.TipSet) (int, error) {
|
func (a *EthModule) countTipsetMsgs(ctx context.Context, ts *types.TipSet) (int, error) {
|
||||||
blkMsgs, err := a.Chain.BlockMsgsForTipset(ctx, ts)
|
blkMsgs, err := a.Chain.BlockMsgsForTipset(ctx, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -362,6 +368,26 @@ func (a *EthModule) EthGetTransactionCount(ctx context.Context, sender ethtypes.
|
|||||||
return ethtypes.EthUint64(0), xerrors.Errorf("cannot parse block param: %s", blkParam)
|
return ethtypes.EthUint64(0), xerrors.Errorf("cannot parse block param: %s", blkParam)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// First, handle the case where the "sender" is an EVM actor.
|
||||||
|
if actor, err := a.StateManager.LoadActor(ctx, addr, ts); err != nil {
|
||||||
|
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
return 0, xerrors.Errorf("failed to lookup contract %s: %w", sender, err)
|
||||||
|
} else if builtinactors.IsEvmActor(actor.Code) {
|
||||||
|
evmState, err := builtinevm.Load(a.Chain.ActorStore(ctx), actor)
|
||||||
|
if err != nil {
|
||||||
|
return 0, xerrors.Errorf("failed to load evm state: %w", err)
|
||||||
|
}
|
||||||
|
if alive, err := evmState.IsAlive(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if !alive {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
nonce, err := evmState.Nonce()
|
||||||
|
return ethtypes.EthUint64(nonce), err
|
||||||
|
}
|
||||||
|
|
||||||
nonce, err := a.Mpool.GetNonce(ctx, addr, ts.Key())
|
nonce, err := a.Mpool.GetNonce(ctx, addr, ts.Key())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EthUint64(0), nil
|
return ethtypes.EthUint64(0), nil
|
||||||
@ -505,13 +531,18 @@ func (a *EthModule) EthGetCode(ctx context.Context, ethAddr ethtypes.EthAddress,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) {
|
func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) {
|
||||||
|
ts, err := a.parseBlkParam(ctx, blkParam)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("cannot parse block param: %s", blkParam)
|
||||||
|
}
|
||||||
|
|
||||||
l := len(position)
|
l := len(position)
|
||||||
if l > 32 {
|
if l > 32 {
|
||||||
return nil, fmt.Errorf("supplied storage key is too long")
|
return nil, fmt.Errorf("supplied storage key is too long")
|
||||||
}
|
}
|
||||||
|
|
||||||
// pad with zero bytes if smaller than 32 bytes
|
// pad with zero bytes if smaller than 32 bytes
|
||||||
position = append(make([]byte, 32-l, 32-l), position...)
|
position = append(make([]byte, 32-l, 32), position...)
|
||||||
|
|
||||||
to, err := ethAddr.ToFilecoinAddress()
|
to, err := ethAddr.ToFilecoinAddress()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -524,8 +555,20 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd
|
|||||||
return nil, fmt.Errorf("failed to construct system sender address: %w", err)
|
return nil, fmt.Errorf("failed to construct system sender address: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
actor, err := a.StateManager.LoadActor(ctx, to, ts)
|
||||||
|
if err != nil {
|
||||||
|
if xerrors.Is(err, types.ErrActorNotFound) {
|
||||||
|
return ethtypes.EthBytes(make([]byte, 32)), nil
|
||||||
|
}
|
||||||
|
return nil, xerrors.Errorf("failed to lookup contract %s: %w", ethAddr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !builtinactors.IsEvmActor(actor.Code) {
|
||||||
|
return ethtypes.EthBytes(make([]byte, 32)), nil
|
||||||
|
}
|
||||||
|
|
||||||
params, err := actors.SerializeParams(&evm.GetStorageAtParams{
|
params, err := actors.SerializeParams(&evm.GetStorageAtParams{
|
||||||
StorageKey: position,
|
StorageKey: *(*[32]byte)(position),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to serialize parameters: %w", err)
|
return nil, fmt.Errorf("failed to serialize parameters: %w", err)
|
||||||
@ -542,8 +585,6 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd
|
|||||||
GasPremium: big.Zero(),
|
GasPremium: big.Zero(),
|
||||||
}
|
}
|
||||||
|
|
||||||
ts := a.Chain.GetHeaviestTipSet()
|
|
||||||
|
|
||||||
// Try calling until we find a height with no migration.
|
// Try calling until we find a height with no migration.
|
||||||
var res *api.InvocResult
|
var res *api.InvocResult
|
||||||
for {
|
for {
|
||||||
@ -562,10 +603,22 @@ func (a *EthModule) EthGetStorageAt(ctx context.Context, ethAddr ethtypes.EthAdd
|
|||||||
}
|
}
|
||||||
|
|
||||||
if res.MsgRct == nil {
|
if res.MsgRct == nil {
|
||||||
return nil, fmt.Errorf("no message receipt")
|
return nil, xerrors.Errorf("no message receipt")
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.MsgRct.Return, nil
|
if res.MsgRct.ExitCode.IsError() {
|
||||||
|
return nil, xerrors.Errorf("failed to lookup storage slot: %s", res.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ret abi.CborBytes
|
||||||
|
if err := ret.UnmarshalCBOR(bytes.NewReader(res.MsgRct.Return)); err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to unmarshal storage slot: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// pad with zero bytes if smaller than 32 bytes
|
||||||
|
ret = append(make([]byte, 32-len(ret), 32), ret...)
|
||||||
|
|
||||||
|
return ethtypes.EthBytes(ret), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) {
|
func (a *EthModule) EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) {
|
||||||
@ -601,6 +654,18 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth
|
|||||||
if params.BlkCount > 1024 {
|
if params.BlkCount > 1024 {
|
||||||
return ethtypes.EthFeeHistory{}, fmt.Errorf("block count should be smaller than 1024")
|
return ethtypes.EthFeeHistory{}, fmt.Errorf("block count should be smaller than 1024")
|
||||||
}
|
}
|
||||||
|
rewardPercentiles := make([]float64, 0)
|
||||||
|
if params.RewardPercentiles != nil {
|
||||||
|
rewardPercentiles = append(rewardPercentiles, *params.RewardPercentiles...)
|
||||||
|
}
|
||||||
|
for i, rp := range rewardPercentiles {
|
||||||
|
if rp < 0 || rp > 100 {
|
||||||
|
return ethtypes.EthFeeHistory{}, fmt.Errorf("invalid reward percentile: %f should be between 0 and 100", rp)
|
||||||
|
}
|
||||||
|
if i > 0 && rp < rewardPercentiles[i-1] {
|
||||||
|
return ethtypes.EthFeeHistory{}, fmt.Errorf("invalid reward percentile: %f should be larger than %f", rp, rewardPercentiles[i-1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ts, err := a.parseBlkParam(ctx, params.NewestBlkNum)
|
ts, err := a.parseBlkParam(ctx, params.NewestBlkNum)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -619,18 +684,40 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth
|
|||||||
// we can do is duplicate the last value.
|
// we can do is duplicate the last value.
|
||||||
baseFeeArray := []ethtypes.EthBigInt{ethtypes.EthBigInt(ts.Blocks()[0].ParentBaseFee)}
|
baseFeeArray := []ethtypes.EthBigInt{ethtypes.EthBigInt(ts.Blocks()[0].ParentBaseFee)}
|
||||||
gasUsedRatioArray := []float64{}
|
gasUsedRatioArray := []float64{}
|
||||||
|
rewardsArray := make([][]ethtypes.EthBigInt, 0)
|
||||||
|
|
||||||
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.StateAPI)
|
msgs, err := a.Chain.MessagesForTipset(ctx, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ethtypes.EthFeeHistory{}, fmt.Errorf("cannot create eth block: %v", err)
|
return ethtypes.EthFeeHistory{}, xerrors.Errorf("error loading messages for tipset: %v: %w", ts, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// both arrays should be reversed at the end
|
txGasRewards := gasRewardSorter{}
|
||||||
|
for txIdx, msg := range msgs {
|
||||||
|
msgLookup, err := a.StateAPI.StateSearchMsg(ctx, types.EmptyTSK, msg.Cid(), api.LookbackNoLimit, false)
|
||||||
|
if err != nil || msgLookup == nil {
|
||||||
|
return ethtypes.EthFeeHistory{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
tx, err := newEthTxFromMessageLookup(ctx, msgLookup, txIdx, a.Chain, a.StateAPI)
|
||||||
|
if err != nil {
|
||||||
|
return ethtypes.EthFeeHistory{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
txGasRewards = append(txGasRewards, gasRewardTuple{
|
||||||
|
reward: tx.Reward(ts.Blocks()[0].ParentBaseFee),
|
||||||
|
gas: uint64(msgLookup.Receipt.GasUsed),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
rewards, totalGasUsed := calculateRewardsAndGasUsed(rewardPercentiles, txGasRewards)
|
||||||
|
|
||||||
|
// arrays should be reversed at the end
|
||||||
baseFeeArray = append(baseFeeArray, ethtypes.EthBigInt(ts.Blocks()[0].ParentBaseFee))
|
baseFeeArray = append(baseFeeArray, ethtypes.EthBigInt(ts.Blocks()[0].ParentBaseFee))
|
||||||
gasUsedRatioArray = append(gasUsedRatioArray, float64(block.GasUsed)/float64(build.BlockGasLimit))
|
gasUsedRatioArray = append(gasUsedRatioArray, float64(totalGasUsed)/float64(build.BlockGasLimit))
|
||||||
|
rewardsArray = append(rewardsArray, rewards)
|
||||||
|
|
||||||
parentTsKey := ts.Parents()
|
parentTsKey := ts.Parents()
|
||||||
ts, err = a.Chain.LoadTipSet(ctx, parentTsKey)
|
ts, err = a.Chain.LoadTipSet(ctx, parentTsKey)
|
||||||
@ -646,6 +733,9 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth
|
|||||||
for i, j := 0, len(gasUsedRatioArray)-1; i < j; i, j = i+1, j-1 {
|
for i, j := 0, len(gasUsedRatioArray)-1; i < j; i, j = i+1, j-1 {
|
||||||
gasUsedRatioArray[i], gasUsedRatioArray[j] = gasUsedRatioArray[j], gasUsedRatioArray[i]
|
gasUsedRatioArray[i], gasUsedRatioArray[j] = gasUsedRatioArray[j], gasUsedRatioArray[i]
|
||||||
}
|
}
|
||||||
|
for i, j := 0, len(rewardsArray)-1; i < j; i, j = i+1, j-1 {
|
||||||
|
rewardsArray[i], rewardsArray[j] = rewardsArray[j], rewardsArray[i]
|
||||||
|
}
|
||||||
|
|
||||||
ret := ethtypes.EthFeeHistory{
|
ret := ethtypes.EthFeeHistory{
|
||||||
OldestBlock: ethtypes.EthUint64(oldestBlkHeight),
|
OldestBlock: ethtypes.EthUint64(oldestBlkHeight),
|
||||||
@ -653,13 +743,7 @@ func (a *EthModule) EthFeeHistory(ctx context.Context, p jsonrpc.RawParams) (eth
|
|||||||
GasUsedRatio: gasUsedRatioArray,
|
GasUsedRatio: gasUsedRatioArray,
|
||||||
}
|
}
|
||||||
if params.RewardPercentiles != nil {
|
if params.RewardPercentiles != nil {
|
||||||
// TODO: Populate reward percentiles
|
ret.Reward = &rewardsArray
|
||||||
// https://github.com/filecoin-project/lotus/issues/10236
|
|
||||||
// We need to calculate the requested percentiles of effective gas premium
|
|
||||||
// based on the newest block (I presume it's the newest, we need to dig in
|
|
||||||
// as it's underspecified). Effective means we're clamped at the gas_fee_cap - base_fee.
|
|
||||||
reward := make([][]ethtypes.EthBigInt, 0)
|
|
||||||
ret.Reward = &reward
|
|
||||||
}
|
}
|
||||||
return ret, nil
|
return ret, nil
|
||||||
}
|
}
|
||||||
@ -751,18 +835,20 @@ func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.Et
|
|||||||
}
|
}
|
||||||
|
|
||||||
var params []byte
|
var params []byte
|
||||||
|
if len(tx.Data) > 0 {
|
||||||
|
initcode := abi.CborBytes(tx.Data)
|
||||||
|
params2, err := actors.SerializeParams(&initcode)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to serialize params: %w", err)
|
||||||
|
}
|
||||||
|
params = params2
|
||||||
|
}
|
||||||
|
|
||||||
var to address.Address
|
var to address.Address
|
||||||
var method abi.MethodNum
|
var method abi.MethodNum
|
||||||
if tx.To == nil {
|
if tx.To == nil {
|
||||||
// this is a contract creation
|
// this is a contract creation
|
||||||
to = builtintypes.EthereumAddressManagerActorAddr
|
to = builtintypes.EthereumAddressManagerActorAddr
|
||||||
|
|
||||||
initcode := abi.CborBytes(tx.Data)
|
|
||||||
params2, err := actors.SerializeParams(&initcode)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to serialize Create params: %w", err)
|
|
||||||
}
|
|
||||||
params = params2
|
|
||||||
method = builtintypes.MethodsEAM.CreateExternal
|
method = builtintypes.MethodsEAM.CreateExternal
|
||||||
} else {
|
} else {
|
||||||
addr, err := tx.To.ToFilecoinAddress()
|
addr, err := tx.To.ToFilecoinAddress()
|
||||||
@ -770,15 +856,6 @@ func (a *EthModule) ethCallToFilecoinMessage(ctx context.Context, tx ethtypes.Et
|
|||||||
return nil, xerrors.Errorf("cannot get Filecoin address: %w", err)
|
return nil, xerrors.Errorf("cannot get Filecoin address: %w", err)
|
||||||
}
|
}
|
||||||
to = addr
|
to = addr
|
||||||
|
|
||||||
if len(tx.Data) > 0 {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := cbg.WriteByteArray(&buf, tx.Data); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to encode tx input into a cbor byte-string")
|
|
||||||
}
|
|
||||||
params = buf.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
method = builtintypes.MethodsEVM.InvokeContract
|
method = builtintypes.MethodsEVM.InvokeContract
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -815,7 +892,8 @@ func (a *EthModule) applyMessage(ctx context.Context, msg *types.Message, tsk ty
|
|||||||
return nil, xerrors.Errorf("CallWithGas failed: %w", err)
|
return nil, xerrors.Errorf("CallWithGas failed: %w", err)
|
||||||
}
|
}
|
||||||
if res.MsgRct.ExitCode.IsError() {
|
if res.MsgRct.ExitCode.IsError() {
|
||||||
return nil, xerrors.Errorf("message execution failed: exit %s, msg receipt: %s, reason: %s", res.MsgRct.ExitCode, res.MsgRct.Return, res.Error)
|
reason := parseEthRevert(res.MsgRct.Return)
|
||||||
|
return nil, xerrors.Errorf("message execution failed: exit %s, revert reason: %s, vm error: %s", res.MsgRct.ExitCode, reason, res.Error)
|
||||||
}
|
}
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
@ -831,14 +909,24 @@ func (a *EthModule) EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (et
|
|||||||
msg.GasLimit = 0
|
msg.GasLimit = 0
|
||||||
|
|
||||||
ts := a.Chain.GetHeaviestTipSet()
|
ts := a.Chain.GetHeaviestTipSet()
|
||||||
msg, err = a.GasAPI.GasEstimateMessageGas(ctx, msg, nil, ts.Key())
|
gassedMsg, err := a.GasAPI.GasEstimateMessageGas(ctx, msg, nil, ts.Key())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
// On failure, GasEstimateMessageGas doesn't actually return the invocation result,
|
||||||
|
// it just returns an error. That means we can't get the revert reason.
|
||||||
|
//
|
||||||
|
// So we re-execute the message with EthCall (well, applyMessage which contains the
|
||||||
|
// guts of EthCall). This will give us an ethereum specific error with revert
|
||||||
|
// information.
|
||||||
|
msg.GasLimit = build.BlockGasLimit
|
||||||
|
if _, err2 := a.applyMessage(ctx, msg, ts.Key()); err2 != nil {
|
||||||
|
err = err2
|
||||||
|
}
|
||||||
return ethtypes.EthUint64(0), xerrors.Errorf("failed to estimate gas: %w", err)
|
return ethtypes.EthUint64(0), xerrors.Errorf("failed to estimate gas: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedGas, err := ethGasSearch(ctx, a.Chain, a.Stmgr, a.Mpool, msg, ts)
|
expectedGas, err := ethGasSearch(ctx, a.Chain, a.Stmgr, a.Mpool, gassedMsg, ts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorw("expected gas", "err", err)
|
return 0, xerrors.Errorf("gas search failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ethtypes.EthUint64(expectedGas), nil
|
return ethtypes.EthUint64(expectedGas), nil
|
||||||
@ -976,7 +1064,7 @@ func (a *EthModule) EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam s
|
|||||||
|
|
||||||
invokeResult, err := a.applyMessage(ctx, msg, ts.Key())
|
invokeResult, err := a.applyMessage(ctx, msg, ts.Key())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to apply message: %w", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
|
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
|
||||||
@ -1246,8 +1334,9 @@ func (e *EthEvent) uninstallFilter(ctx context.Context, f filter.Filter) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
EthSubscribeEventTypeHeads = "newHeads"
|
EthSubscribeEventTypeHeads = "newHeads"
|
||||||
EthSubscribeEventTypeLogs = "logs"
|
EthSubscribeEventTypeLogs = "logs"
|
||||||
|
EthSubscribeEventTypePendingTransactions = "newPendingTransactions"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *EthEvent) EthSubscribe(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {
|
func (e *EthEvent) EthSubscribe(ctx context.Context, p jsonrpc.RawParams) (ethtypes.EthSubscriptionID, error) {
|
||||||
@ -1309,6 +1398,15 @@ func (e *EthEvent) EthSubscribe(ctx context.Context, p jsonrpc.RawParams) (ethty
|
|||||||
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
||||||
return ethtypes.EthSubscriptionID{}, err
|
return ethtypes.EthSubscriptionID{}, err
|
||||||
}
|
}
|
||||||
|
sub.addFilter(ctx, f)
|
||||||
|
case EthSubscribeEventTypePendingTransactions:
|
||||||
|
f, err := e.MemPoolFilterManager.Install(ctx)
|
||||||
|
if err != nil {
|
||||||
|
// clean up any previous filters added and stop the sub
|
||||||
|
_, _ = e.EthUnsubscribe(ctx, sub.id)
|
||||||
|
return ethtypes.EthSubscriptionID{}, err
|
||||||
|
}
|
||||||
|
|
||||||
sub.addFilter(ctx, f)
|
sub.addFilter(ctx, f)
|
||||||
default:
|
default:
|
||||||
return ethtypes.EthSubscriptionID{}, xerrors.Errorf("unsupported event type: %s", params.EventType)
|
return ethtypes.EthSubscriptionID{}, xerrors.Errorf("unsupported event type: %s", params.EventType)
|
||||||
@ -1629,6 +1727,15 @@ func (e *ethSubscription) start(ctx context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
e.send(ctx, ev)
|
e.send(ctx, ev)
|
||||||
|
case *types.SignedMessage: // mpool txid
|
||||||
|
evs, err := ethFilterResultFromMessages([]*types.SignedMessage{vt}, e.StateAPI)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, r := range evs.Results {
|
||||||
|
e.send(ctx, r)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
log.Warnf("unexpected subscription value type: %T", vt)
|
log.Warnf("unexpected subscription value type: %T", vt)
|
||||||
}
|
}
|
||||||
@ -2081,11 +2188,13 @@ func (m *EthTxHashManager) ProcessSignedMessage(ctx context.Context, msg *types.
|
|||||||
ethTx, err := newEthTxFromSignedMessage(ctx, msg, m.StateAPI)
|
ethTx, err := newEthTxFromSignedMessage(ctx, msg, m.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)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = m.TransactionHashLookup.UpsertHash(ethTx.Hash, msg.Cid())
|
err = m.TransactionHashLookup.UpsertHash(ethTx.Hash, msg.Cid())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("error inserting tx mapping to db: %s", err)
|
log.Errorf("error inserting tx mapping to db: %s", err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2135,3 +2244,129 @@ func parseEthTopics(topics ethtypes.EthTopicSpec) (map[string][][]byte, error) {
|
|||||||
}
|
}
|
||||||
return keys, nil
|
return keys, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const errorFunctionSelector = "\x08\xc3\x79\xa0" // Error(string)
|
||||||
|
const panicFunctionSelector = "\x4e\x48\x7b\x71" // Panic(uint256)
|
||||||
|
// Eth ABI (solidity) panic codes.
|
||||||
|
var panicErrorCodes map[uint64]string = map[uint64]string{
|
||||||
|
0x00: "Panic()",
|
||||||
|
0x01: "Assert()",
|
||||||
|
0x11: "ArithmeticOverflow()",
|
||||||
|
0x12: "DivideByZero()",
|
||||||
|
0x21: "InvalidEnumVariant()",
|
||||||
|
0x22: "InvalidStorageArray()",
|
||||||
|
0x31: "PopEmptyArray()",
|
||||||
|
0x32: "ArrayIndexOutOfBounds()",
|
||||||
|
0x41: "OutOfMemory()",
|
||||||
|
0x51: "CalledUninitializedFunction()",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse an ABI encoded revert reason. This reason should be encoded as if it were the parameters to
|
||||||
|
// an `Error(string)` function call.
|
||||||
|
//
|
||||||
|
// See https://docs.soliditylang.org/en/latest/control-structures.html#panic-via-assert-and-error-via-require
|
||||||
|
func parseEthRevert(ret []byte) string {
|
||||||
|
if len(ret) == 0 {
|
||||||
|
return "none"
|
||||||
|
}
|
||||||
|
var cbytes abi.CborBytes
|
||||||
|
if err := cbytes.UnmarshalCBOR(bytes.NewReader(ret)); err != nil {
|
||||||
|
return "ERROR: revert reason is not cbor encoded bytes"
|
||||||
|
}
|
||||||
|
if len(cbytes) == 0 {
|
||||||
|
return "none"
|
||||||
|
}
|
||||||
|
// If it's not long enough to contain an ABI encoded response, return immediately.
|
||||||
|
if len(cbytes) < 4+32 {
|
||||||
|
return ethtypes.EthBytes(cbytes).String()
|
||||||
|
}
|
||||||
|
switch string(cbytes[:4]) {
|
||||||
|
case panicFunctionSelector:
|
||||||
|
cbytes := cbytes[4 : 4+32]
|
||||||
|
// Read the and check the code.
|
||||||
|
code, err := ethtypes.EthUint64FromBytes(cbytes)
|
||||||
|
if err != nil {
|
||||||
|
// If it's too big, just return the raw value.
|
||||||
|
codeInt := big.PositiveFromUnsignedBytes(cbytes)
|
||||||
|
return fmt.Sprintf("Panic(%s)", ethtypes.EthBigInt(codeInt).String())
|
||||||
|
}
|
||||||
|
if s, ok := panicErrorCodes[uint64(code)]; ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Panic(0x%x)", code)
|
||||||
|
case errorFunctionSelector:
|
||||||
|
cbytes := cbytes[4:]
|
||||||
|
cbytesLen := ethtypes.EthUint64(len(cbytes))
|
||||||
|
// Read the and check the offset.
|
||||||
|
offset, err := ethtypes.EthUint64FromBytes(cbytes[:32])
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if cbytesLen < offset {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and check the length.
|
||||||
|
if cbytesLen-offset < 32 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
start := offset + 32
|
||||||
|
length, err := ethtypes.EthUint64FromBytes(cbytes[offset : offset+32])
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if cbytesLen-start < length {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Slice the error message.
|
||||||
|
return fmt.Sprintf("Error(%s)", cbytes[start:start+length])
|
||||||
|
}
|
||||||
|
return ethtypes.EthBytes(cbytes).String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func calculateRewardsAndGasUsed(rewardPercentiles []float64, txGasRewards gasRewardSorter) ([]ethtypes.EthBigInt, uint64) {
|
||||||
|
var totalGasUsed uint64
|
||||||
|
for _, tx := range txGasRewards {
|
||||||
|
totalGasUsed += tx.gas
|
||||||
|
}
|
||||||
|
|
||||||
|
rewards := make([]ethtypes.EthBigInt, len(rewardPercentiles))
|
||||||
|
for i := range rewards {
|
||||||
|
rewards[i] = ethtypes.EthBigIntZero
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(txGasRewards) == 0 {
|
||||||
|
return rewards, totalGasUsed
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Stable(txGasRewards)
|
||||||
|
|
||||||
|
var idx int
|
||||||
|
var sum uint64
|
||||||
|
for i, percentile := range rewardPercentiles {
|
||||||
|
threshold := uint64(float64(totalGasUsed) * percentile / 100)
|
||||||
|
for sum < threshold && idx < len(txGasRewards)-1 {
|
||||||
|
sum += txGasRewards[idx].gas
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
rewards[i] = txGasRewards[idx].reward
|
||||||
|
}
|
||||||
|
|
||||||
|
return rewards, totalGasUsed
|
||||||
|
}
|
||||||
|
|
||||||
|
type gasRewardTuple struct {
|
||||||
|
gas uint64
|
||||||
|
reward ethtypes.EthBigInt
|
||||||
|
}
|
||||||
|
|
||||||
|
// sorted in ascending order
|
||||||
|
type gasRewardSorter []gasRewardTuple
|
||||||
|
|
||||||
|
func (g gasRewardSorter) Len() int { return len(g) }
|
||||||
|
func (g gasRewardSorter) Swap(i, j int) {
|
||||||
|
g[i], g[j] = g[j], g[i]
|
||||||
|
}
|
||||||
|
func (g gasRewardSorter) Less(i, j int) bool {
|
||||||
|
return g[i].reward.Int.Cmp(g[j].reward.Int) == -1
|
||||||
|
}
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"github.com/ipfs/go-cid"
|
"github.com/ipfs/go-cid"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
|
||||||
"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"
|
||||||
)
|
)
|
||||||
@ -100,3 +102,65 @@ func TestEthLogFromEvent(t *testing.T) {
|
|||||||
require.Len(t, topics, 1)
|
require.Len(t, topics, 1)
|
||||||
require.Equal(t, topics[0], ethtypes.EthHash{})
|
require.Equal(t, topics[0], ethtypes.EthHash{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReward(t *testing.T) {
|
||||||
|
baseFee := big.NewInt(100)
|
||||||
|
testcases := []struct {
|
||||||
|
maxFeePerGas, maxPriorityFeePerGas big.Int
|
||||||
|
answer big.Int
|
||||||
|
}{
|
||||||
|
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(200), answer: big.NewInt(200)},
|
||||||
|
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(300), answer: big.NewInt(300)},
|
||||||
|
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(500), answer: big.NewInt(500)},
|
||||||
|
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(600), answer: big.NewInt(500)},
|
||||||
|
{maxFeePerGas: big.NewInt(600), maxPriorityFeePerGas: big.NewInt(1000), answer: big.NewInt(500)},
|
||||||
|
{maxFeePerGas: big.NewInt(50), maxPriorityFeePerGas: big.NewInt(200), answer: big.NewInt(-50)},
|
||||||
|
}
|
||||||
|
for _, tc := range testcases {
|
||||||
|
tx := ethtypes.EthTx{
|
||||||
|
MaxFeePerGas: ethtypes.EthBigInt(tc.maxFeePerGas),
|
||||||
|
MaxPriorityFeePerGas: ethtypes.EthBigInt(tc.maxPriorityFeePerGas),
|
||||||
|
}
|
||||||
|
reward := tx.Reward(baseFee)
|
||||||
|
require.Equal(t, 0, reward.Int.Cmp(tc.answer.Int), reward, tc.answer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRewardPercentiles(t *testing.T) {
|
||||||
|
testcases := []struct {
|
||||||
|
percentiles []float64
|
||||||
|
txGasRewards gasRewardSorter
|
||||||
|
answer []int64
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
percentiles: []float64{25, 50, 75},
|
||||||
|
txGasRewards: []gasRewardTuple{},
|
||||||
|
answer: []int64{0, 0, 0},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
percentiles: []float64{25, 50, 75, 100},
|
||||||
|
txGasRewards: []gasRewardTuple{
|
||||||
|
{gas: uint64(0), reward: ethtypes.EthBigInt(big.NewInt(300))},
|
||||||
|
{gas: uint64(100), reward: ethtypes.EthBigInt(big.NewInt(200))},
|
||||||
|
{gas: uint64(350), reward: ethtypes.EthBigInt(big.NewInt(100))},
|
||||||
|
{gas: uint64(500), reward: ethtypes.EthBigInt(big.NewInt(600))},
|
||||||
|
{gas: uint64(300), reward: ethtypes.EthBigInt(big.NewInt(700))},
|
||||||
|
},
|
||||||
|
answer: []int64{200, 700, 700, 700},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range testcases {
|
||||||
|
rewards, totalGasUsed := calculateRewardsAndGasUsed(tc.percentiles, tc.txGasRewards)
|
||||||
|
gasUsed := uint64(0)
|
||||||
|
for _, tx := range tc.txGasRewards {
|
||||||
|
gasUsed += tx.gas
|
||||||
|
}
|
||||||
|
ans := []ethtypes.EthBigInt{}
|
||||||
|
for _, bi := range tc.answer {
|
||||||
|
ans = append(ans, ethtypes.EthBigInt(big.NewInt(bi)))
|
||||||
|
}
|
||||||
|
require.Equal(t, totalGasUsed, gasUsed)
|
||||||
|
require.Equal(t, len(ans), len(tc.percentiles))
|
||||||
|
require.Equal(t, ans, rewards)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user