NV18: Filecoin EVM runtime + Actor Events + EthAccount + EAM + f4 addressing (#9998)
Co-authored-by: Steven Allen <steven@stebalien.com> Co-authored-by: Raul Kripalani <raulk@users.noreply.github.com> Co-authored-by: Kevin Li <ychiaoli18@users.noreply.github.com> Co-authored-by: vyzo <vyzo@hackzen.org> Co-authored-by: Ian Davis <nospam@iandavis.com> Co-authored-by: Aayush Rajasekaran <arajasek94@gmail.com> Co-authored-by: Jiaying Wang <42981373+jennijuju@users.noreply.github.com> Co-authored-by: Jennifer Wang <jiayingw703@gmail.com> Co-authored-by: Geoff Stuart <geoff.vball@gmail.com> Co-authored-by: Shrenuj Bansal <shrenuj.bansal@protocol.ai> Co-authored-by: Shrenuj Bansal <108157875+shrenujbansal@users.noreply.github.com> Co-authored-by: Geoff Stuart <geoffrey.stuart@protocol.ai> Co-authored-by: Aayush Rajasekaran <aayushrajasekaran@Aayushs-MacBook-Pro.local> Co-authored-by: ZenGround0 <5515260+ZenGround0@users.noreply.github.com> Co-authored-by: zenground0 <ZenGround0@users.noreply.github.com>
This commit is contained in:
parent
048ccc71bb
commit
cdf3812e40
@ -720,6 +720,46 @@ workflows:
|
||||
suite: itest-dup_mpool_messages
|
||||
target: "./itests/dup_mpool_messages_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_account_abstraction
|
||||
suite: itest-eth_account_abstraction
|
||||
target: "./itests/eth_account_abstraction_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_balance
|
||||
suite: itest-eth_balance
|
||||
target: "./itests/eth_balance_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_deploy
|
||||
suite: itest-eth_deploy
|
||||
target: "./itests/eth_deploy_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_filter
|
||||
suite: itest-eth_filter
|
||||
target: "./itests/eth_filter_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-eth_transactions
|
||||
suite: itest-eth_transactions
|
||||
target: "./itests/eth_transactions_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-fevm_address
|
||||
suite: itest-fevm_address
|
||||
target: "./itests/fevm_address_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-fevm_events
|
||||
suite: itest-fevm_events
|
||||
target: "./itests/fevm_events_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-fevm
|
||||
suite: itest-fevm
|
||||
target: "./itests/fevm_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-gas_estimation
|
||||
suite: itest-gas_estimation
|
||||
@ -755,6 +795,11 @@ workflows:
|
||||
suite: itest-migration_nv17
|
||||
target: "./itests/migration_nv17_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-migration_nv18
|
||||
suite: itest-migration_nv18
|
||||
target: "./itests/migration_nv18_test.go"
|
||||
|
||||
- test:
|
||||
name: test-itest-mpool_msg_uuid
|
||||
suite: itest-mpool_msg_uuid
|
||||
|
6
Makefile
6
Makefile
@ -84,6 +84,12 @@ butterflynet: build-devnets
|
||||
interopnet: GOFLAGS+=-tags=interopnet
|
||||
interopnet: build-devnets
|
||||
|
||||
wallabynet: GOFLAGS+=-tags=wallabynet
|
||||
wallabynet: build-devnets
|
||||
|
||||
hyperspacenet: GOFLAGS+=-tags=hyperspacenet
|
||||
hyperspacenet: build-devnets
|
||||
|
||||
lotus: $(BUILD_DEPS)
|
||||
rm -f lotus
|
||||
$(GOCC) build $(GOFLAGS) -o lotus ./cmd/lotus
|
||||
|
109
api/api_full.go
109
api/api_full.go
@ -31,6 +31,7 @@ import (
|
||||
lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin/power"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/repo/imports"
|
||||
)
|
||||
@ -151,7 +152,7 @@ type FullNode interface {
|
||||
|
||||
// ChainGetPath returns a set of revert/apply operations needed to get from
|
||||
// one tipset to another, for example:
|
||||
//```
|
||||
// ```
|
||||
// to
|
||||
// ^
|
||||
// from tAA
|
||||
@ -160,7 +161,7 @@ type FullNode interface {
|
||||
// ^---*--^
|
||||
// ^
|
||||
// tRR
|
||||
//```
|
||||
// ```
|
||||
// Would return `[revert(tBA), apply(tAB), apply(tAA)]`
|
||||
ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*HeadChange, error) //perm:read
|
||||
|
||||
@ -182,6 +183,9 @@ type FullNode interface {
|
||||
// ChainBlockstoreInfo returns some basic information about the blockstore
|
||||
ChainBlockstoreInfo(context.Context) (map[string]interface{}, error) //perm:read
|
||||
|
||||
// ChainGetEvents returns the events under an event AMT root CID.
|
||||
ChainGetEvents(context.Context, cid.Cid) ([]types.Event, error) //perm:read
|
||||
|
||||
// GasEstimateFeeCap estimates gas fee cap
|
||||
GasEstimateFeeCap(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error) //perm:read
|
||||
|
||||
@ -388,12 +392,12 @@ type FullNode interface {
|
||||
ClientCancelRetrievalDeal(ctx context.Context, dealid retrievalmarket.DealID) error //perm:write
|
||||
|
||||
// ClientUnimport removes references to the specified file from filestore
|
||||
//ClientUnimport(path string)
|
||||
// ClientUnimport(path string)
|
||||
|
||||
// ClientListImports lists imported files and their root CIDs
|
||||
ClientListImports(ctx context.Context) ([]Import, error) //perm:write
|
||||
|
||||
//ClientListAsks() []Ask
|
||||
// ClientListAsks() []Ask
|
||||
|
||||
// MethodGroup: State
|
||||
// The State methods are used to query, inspect, and interact with chain state.
|
||||
@ -640,14 +644,14 @@ type FullNode interface {
|
||||
// It takes the following params: <multisig address>, <start epoch>, <end epoch>
|
||||
MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) //perm:read
|
||||
|
||||
//MsigGetPending returns pending transactions for the given multisig
|
||||
//wallet. Once pending transactions are fully approved, they will no longer
|
||||
//appear here.
|
||||
// MsigGetPending returns pending transactions for the given multisig
|
||||
// wallet. Once pending transactions are fully approved, they will no longer
|
||||
// appear here.
|
||||
MsigGetPending(context.Context, address.Address, types.TipSetKey) ([]*MsigTransaction, error) //perm:read
|
||||
|
||||
// MsigCreate creates a multisig wallet
|
||||
// It takes the following params: <required number of senders>, <approving addresses>, <unlock duration>
|
||||
//<initial balance>, <sender address of the create msg>, <gas price>
|
||||
// <initial balance>, <sender address of the create msg>, <gas price>
|
||||
MsigCreate(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (*MessagePrototype, error) //perm:sign
|
||||
|
||||
// MsigPropose proposes a multisig message
|
||||
@ -759,6 +763,77 @@ type FullNode interface {
|
||||
|
||||
NodeStatus(ctx context.Context, inclChainStatus bool) (NodeStatus, error) //perm:read
|
||||
|
||||
// MethodGroup: Eth
|
||||
// These methods are used for Ethereum-compatible JSON-RPC calls
|
||||
//
|
||||
// EthAccounts will always return [] since we don't expect Lotus to manage private keys
|
||||
EthAccounts(ctx context.Context) ([]ethtypes.EthAddress, error) //perm:read
|
||||
// EthBlockNumber returns the height of the latest (heaviest) TipSet
|
||||
EthBlockNumber(ctx context.Context) (ethtypes.EthUint64, error) //perm:read
|
||||
// EthGetBlockTransactionCountByNumber returns the number of messages in the TipSet
|
||||
EthGetBlockTransactionCountByNumber(ctx context.Context, blkNum ethtypes.EthUint64) (ethtypes.EthUint64, error) //perm:read
|
||||
// EthGetBlockTransactionCountByHash returns the number of messages in the TipSet
|
||||
EthGetBlockTransactionCountByHash(ctx context.Context, blkHash ethtypes.EthHash) (ethtypes.EthUint64, error) //perm:read
|
||||
|
||||
EthGetBlockByHash(ctx context.Context, blkHash ethtypes.EthHash, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
|
||||
EthGetBlockByNumber(ctx context.Context, blkNum string, fullTxInfo bool) (ethtypes.EthBlock, error) //perm:read
|
||||
EthGetTransactionByHash(ctx context.Context, txHash *ethtypes.EthHash) (*ethtypes.EthTx, error) //perm:read
|
||||
EthGetTransactionCount(ctx context.Context, sender ethtypes.EthAddress, blkOpt string) (ethtypes.EthUint64, error) //perm:read
|
||||
EthGetTransactionReceipt(ctx context.Context, txHash ethtypes.EthHash) (*EthTxReceipt, error) //perm:read
|
||||
EthGetTransactionByBlockHashAndIndex(ctx context.Context, blkHash ethtypes.EthHash, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read
|
||||
EthGetTransactionByBlockNumberAndIndex(ctx context.Context, blkNum ethtypes.EthUint64, txIndex ethtypes.EthUint64) (ethtypes.EthTx, error) //perm:read
|
||||
|
||||
EthGetCode(ctx context.Context, address ethtypes.EthAddress, blkOpt string) (ethtypes.EthBytes, error) //perm:read
|
||||
EthGetStorageAt(ctx context.Context, address ethtypes.EthAddress, position ethtypes.EthBytes, blkParam string) (ethtypes.EthBytes, error) //perm:read
|
||||
EthGetBalance(ctx context.Context, address ethtypes.EthAddress, blkParam string) (ethtypes.EthBigInt, error) //perm:read
|
||||
EthChainId(ctx context.Context) (ethtypes.EthUint64, error) //perm:read
|
||||
NetVersion(ctx context.Context) (string, error) //perm:read
|
||||
NetListening(ctx context.Context) (bool, error) //perm:read
|
||||
EthProtocolVersion(ctx context.Context) (ethtypes.EthUint64, error) //perm:read
|
||||
EthGasPrice(ctx context.Context) (ethtypes.EthBigInt, error) //perm:read
|
||||
EthFeeHistory(ctx context.Context, blkCount ethtypes.EthUint64, newestBlk string, rewardPercentiles []float64) (ethtypes.EthFeeHistory, error) //perm:read
|
||||
|
||||
EthMaxPriorityFeePerGas(ctx context.Context) (ethtypes.EthBigInt, error) //perm:read
|
||||
EthEstimateGas(ctx context.Context, tx ethtypes.EthCall) (ethtypes.EthUint64, error) //perm:read
|
||||
EthCall(ctx context.Context, tx ethtypes.EthCall, blkParam string) (ethtypes.EthBytes, error) //perm:read
|
||||
|
||||
EthSendRawTransaction(ctx context.Context, rawTx ethtypes.EthBytes) (ethtypes.EthHash, error) //perm:read
|
||||
|
||||
// Returns event logs matching given filter spec.
|
||||
EthGetLogs(ctx context.Context, filter *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) //perm:read
|
||||
|
||||
// Polling method for a filter, returns event logs which occurred since last poll.
|
||||
// (requires write perm since timestamp of last filter execution will be written)
|
||||
EthGetFilterChanges(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) //perm:write
|
||||
|
||||
// Returns event logs matching filter with given id.
|
||||
// (requires write perm since timestamp of last filter execution will be written)
|
||||
EthGetFilterLogs(ctx context.Context, id ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) //perm:write
|
||||
|
||||
// Installs a persistent filter based on given filter spec.
|
||||
EthNewFilter(ctx context.Context, filter *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) //perm:write
|
||||
|
||||
// Installs a persistent filter to notify when a new block arrives.
|
||||
EthNewBlockFilter(ctx context.Context) (ethtypes.EthFilterID, error) //perm:write
|
||||
|
||||
// Installs a persistent filter to notify when new messages arrive in the message pool.
|
||||
EthNewPendingTransactionFilter(ctx context.Context) (ethtypes.EthFilterID, error) //perm:write
|
||||
|
||||
// Uninstalls a filter with given id.
|
||||
EthUninstallFilter(ctx context.Context, id ethtypes.EthFilterID) (bool, error) //perm:write
|
||||
|
||||
// Subscribe to different event types using websockets
|
||||
// eventTypes is one or more of:
|
||||
// - newHeads: notify when new blocks arrive.
|
||||
// - pendingTransactions: notify when new messages arrive in the message pool.
|
||||
// - logs: notify new event logs that match a criteria
|
||||
// params contains additional parameters used with the log event type
|
||||
// The client will receive a stream of EthSubscriptionResponse values until EthUnsubscribe is called.
|
||||
EthSubscribe(ctx context.Context, eventType string, params *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) //perm:write
|
||||
|
||||
// Unsubscribe from a websocket subscription
|
||||
EthUnsubscribe(ctx context.Context, id ethtypes.EthSubscriptionID) (bool, error) //perm:write
|
||||
|
||||
// CreateBackup creates node backup onder the specified file name. The
|
||||
// method requires that the lotus daemon is running with the
|
||||
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that
|
||||
@ -1252,3 +1327,21 @@ type PruneOpts struct {
|
||||
MovingGC bool
|
||||
RetainState int64
|
||||
}
|
||||
|
||||
type EthTxReceipt struct {
|
||||
TransactionHash ethtypes.EthHash `json:"transactionHash"`
|
||||
TransactionIndex ethtypes.EthUint64 `json:"transactionIndex"`
|
||||
BlockHash ethtypes.EthHash `json:"blockHash"`
|
||||
BlockNumber ethtypes.EthUint64 `json:"blockNumber"`
|
||||
From ethtypes.EthAddress `json:"from"`
|
||||
To *ethtypes.EthAddress `json:"to"`
|
||||
StateRoot ethtypes.EthHash `json:"root"`
|
||||
Status ethtypes.EthUint64 `json:"status"`
|
||||
ContractAddress *ethtypes.EthAddress `json:"contractAddress"`
|
||||
CumulativeGasUsed ethtypes.EthUint64 `json:"cumulativeGasUsed"`
|
||||
GasUsed ethtypes.EthUint64 `json:"gasUsed"`
|
||||
EffectiveGasPrice ethtypes.EthBigInt `json:"effectiveGasPrice"`
|
||||
LogsBloom ethtypes.EthBytes `json:"logsBloom"`
|
||||
Logs []ethtypes.EthLog `json:"logs"`
|
||||
Type ethtypes.EthUint64 `json:"type"`
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/builtin/v9/miner"
|
||||
abinetwork "github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/storage/pipeline/sealiface"
|
||||
"github.com/filecoin-project/lotus/storage/sealer/fsutil"
|
||||
@ -152,7 +152,7 @@ type StorageMiner interface {
|
||||
WorkerStats(context.Context) (map[uuid.UUID]storiface.WorkerStats, error) //perm:admin
|
||||
WorkerJobs(context.Context) (map[uuid.UUID][]storiface.WorkerJob, error) //perm:admin
|
||||
|
||||
//storiface.WorkerReturn
|
||||
// storiface.WorkerReturn
|
||||
ReturnDataCid(ctx context.Context, callID storiface.CallID, pi abi.PieceInfo, err *storiface.CallError) error //perm:admin retry:true
|
||||
ReturnAddPiece(ctx context.Context, callID storiface.CallID, pi abi.PieceInfo, err *storiface.CallError) error //perm:admin retry:true
|
||||
ReturnSealPreCommit1(ctx context.Context, callID storiface.CallID, p1o storiface.PreCommit1Out, err *storiface.CallError) error //perm:admin retry:true
|
||||
@ -175,7 +175,7 @@ type StorageMiner interface {
|
||||
// SealingSchedDiag dumps internal sealing scheduler state
|
||||
SealingSchedDiag(ctx context.Context, doSched bool) (interface{}, error) //perm:admin
|
||||
SealingAbort(ctx context.Context, call storiface.CallID) error //perm:admin
|
||||
//SealingSchedRemove removes a request from sealing pipeline
|
||||
// SealingSchedRemove removes a request from sealing pipeline
|
||||
SealingRemoveRequest(ctx context.Context, schedId uuid.UUID) error //perm:admin
|
||||
|
||||
// paths.SectorIndex
|
||||
@ -322,7 +322,7 @@ type StorageMiner interface {
|
||||
|
||||
CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storiface.SectorRef) (map[abi.SectorNumber]string, error) //perm:admin
|
||||
|
||||
ComputeProof(ctx context.Context, ssi []builtin.ExtendedSectorInfo, rand abi.PoStRandomness, poStEpoch abi.ChainEpoch, nv abinetwork.Version) ([]builtin.PoStProof, error) //perm:read
|
||||
ComputeProof(ctx context.Context, ssi []builtinactors.ExtendedSectorInfo, rand abi.PoStRandomness, poStEpoch abi.ChainEpoch, nv abinetwork.Version) ([]builtinactors.PoStProof, error) //perm:read
|
||||
|
||||
// RecoverFault can be used to declare recoveries manually. It sends messages
|
||||
// to the miner actor with details of recovered sectors and returns the CID of messages. It honors the
|
||||
|
@ -41,6 +41,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/api/v0api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/repo/imports"
|
||||
sealing "github.com/filecoin-project/lotus/storage/pipeline"
|
||||
@ -68,6 +69,7 @@ func init() {
|
||||
}
|
||||
|
||||
ExampleValues[reflect.TypeOf(c)] = c
|
||||
ExampleValues[reflect.TypeOf(&c)] = &c
|
||||
|
||||
c2, err := cid.Decode("bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve")
|
||||
if err != nil {
|
||||
@ -298,7 +300,8 @@ func init() {
|
||||
"title": "Lotus RPC API",
|
||||
"version": "1.2.1/generated=2020-11-22T08:22:42-06:00",
|
||||
},
|
||||
"methods": []interface{}{}},
|
||||
"methods": []interface{}{},
|
||||
},
|
||||
)
|
||||
|
||||
addExample(api.CheckStatusCode(0))
|
||||
@ -335,7 +338,8 @@ func init() {
|
||||
NumConnsInbound: 3,
|
||||
NumConnsOutbound: 4,
|
||||
NumFD: 5,
|
||||
}})
|
||||
},
|
||||
})
|
||||
addExample(api.NetLimit{
|
||||
Memory: 123,
|
||||
StreamsInbound: 1,
|
||||
@ -346,6 +350,7 @@ func init() {
|
||||
Conns: 4,
|
||||
FD: 5,
|
||||
})
|
||||
|
||||
addExample(map[string]bitfield.BitField{
|
||||
"": bitfield.NewFromSet([]uint64{5, 6, 7, 10}),
|
||||
})
|
||||
@ -365,11 +370,40 @@ func init() {
|
||||
Headers: nil,
|
||||
},
|
||||
})
|
||||
|
||||
ethint := ethtypes.EthUint64(5)
|
||||
addExample(ethint)
|
||||
addExample(ðint)
|
||||
|
||||
ethaddr, _ := ethtypes.ParseEthAddress("0x5CbEeCF99d3fDB3f25E309Cc264f240bb0664031")
|
||||
addExample(ethaddr)
|
||||
addExample(ðaddr)
|
||||
|
||||
ethhash, _ := ethtypes.EthHashFromCid(c)
|
||||
addExample(ethhash)
|
||||
addExample(ðhash)
|
||||
|
||||
ethFeeHistoryReward := [][]ethtypes.EthBigInt{}
|
||||
addExample(ðFeeHistoryReward)
|
||||
|
||||
addExample(&uuid.UUID{})
|
||||
|
||||
filterid := ethtypes.EthFilterID(ethhash)
|
||||
addExample(filterid)
|
||||
addExample(&filterid)
|
||||
|
||||
subid := ethtypes.EthSubscriptionID(ethhash)
|
||||
addExample(subid)
|
||||
addExample(&subid)
|
||||
|
||||
pstring := func(s string) *string { return &s }
|
||||
addExample(ðtypes.EthFilterSpec{
|
||||
FromBlock: pstring("2301220"),
|
||||
Address: []ethtypes.EthAddress{ethaddr},
|
||||
})
|
||||
}
|
||||
|
||||
func GetAPIType(name, pkg string) (i interface{}, t reflect.Type, permStruct []reflect.Type) {
|
||||
|
||||
switch pkg {
|
||||
case "api": // latest
|
||||
switch name {
|
||||
@ -439,7 +473,7 @@ func ExampleValue(method string, t, parent reflect.Type) interface{} {
|
||||
case reflect.Ptr:
|
||||
if t.Elem().Kind() == reflect.Struct {
|
||||
es := exampleStruct(method, t.Elem(), t)
|
||||
//ExampleValues[t] = es
|
||||
ExampleValues[t] = es
|
||||
return es
|
||||
}
|
||||
case reflect.Interface:
|
||||
|
@ -37,6 +37,7 @@ import (
|
||||
apitypes "github.com/filecoin-project/lotus/api/types"
|
||||
miner0 "github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
types "github.com/filecoin-project/lotus/chain/types"
|
||||
ethtypes "github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
alerting "github.com/filecoin-project/lotus/journal/alerting"
|
||||
dtypes "github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
imports "github.com/filecoin-project/lotus/node/repo/imports"
|
||||
@ -183,6 +184,21 @@ func (mr *MockFullNodeMockRecorder) ChainGetBlockMessages(arg0, arg1 interface{}
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetBlockMessages", reflect.TypeOf((*MockFullNode)(nil).ChainGetBlockMessages), arg0, arg1)
|
||||
}
|
||||
|
||||
// ChainGetEvents mocks base method.
|
||||
func (m *MockFullNode) ChainGetEvents(arg0 context.Context, arg1 cid.Cid) ([]types.Event, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ChainGetEvents", arg0, arg1)
|
||||
ret0, _ := ret[0].([]types.Event)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ChainGetEvents indicates an expected call of ChainGetEvents.
|
||||
func (mr *MockFullNodeMockRecorder) ChainGetEvents(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ChainGetEvents", reflect.TypeOf((*MockFullNode)(nil).ChainGetEvents), arg0, arg1)
|
||||
}
|
||||
|
||||
// ChainGetGenesis mocks base method.
|
||||
func (m *MockFullNode) ChainGetGenesis(arg0 context.Context) (*types.TipSet, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -921,6 +937,471 @@ func (mr *MockFullNodeMockRecorder) Discover(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Discover", reflect.TypeOf((*MockFullNode)(nil).Discover), arg0)
|
||||
}
|
||||
|
||||
// EthAccounts mocks base method.
|
||||
func (m *MockFullNode) EthAccounts(arg0 context.Context) ([]ethtypes.EthAddress, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthAccounts", arg0)
|
||||
ret0, _ := ret[0].([]ethtypes.EthAddress)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthAccounts indicates an expected call of EthAccounts.
|
||||
func (mr *MockFullNodeMockRecorder) EthAccounts(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthAccounts", reflect.TypeOf((*MockFullNode)(nil).EthAccounts), arg0)
|
||||
}
|
||||
|
||||
// EthBlockNumber mocks base method.
|
||||
func (m *MockFullNode) EthBlockNumber(arg0 context.Context) (ethtypes.EthUint64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthBlockNumber", arg0)
|
||||
ret0, _ := ret[0].(ethtypes.EthUint64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthBlockNumber indicates an expected call of EthBlockNumber.
|
||||
func (mr *MockFullNodeMockRecorder) EthBlockNumber(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthBlockNumber", reflect.TypeOf((*MockFullNode)(nil).EthBlockNumber), arg0)
|
||||
}
|
||||
|
||||
// EthCall mocks base method.
|
||||
func (m *MockFullNode) EthCall(arg0 context.Context, arg1 ethtypes.EthCall, arg2 string) (ethtypes.EthBytes, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthCall", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(ethtypes.EthBytes)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthCall indicates an expected call of EthCall.
|
||||
func (mr *MockFullNodeMockRecorder) EthCall(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthCall", reflect.TypeOf((*MockFullNode)(nil).EthCall), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthChainId mocks base method.
|
||||
func (m *MockFullNode) EthChainId(arg0 context.Context) (ethtypes.EthUint64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthChainId", arg0)
|
||||
ret0, _ := ret[0].(ethtypes.EthUint64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthChainId indicates an expected call of EthChainId.
|
||||
func (mr *MockFullNodeMockRecorder) EthChainId(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthChainId", reflect.TypeOf((*MockFullNode)(nil).EthChainId), arg0)
|
||||
}
|
||||
|
||||
// EthEstimateGas mocks base method.
|
||||
func (m *MockFullNode) EthEstimateGas(arg0 context.Context, arg1 ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthEstimateGas", arg0, arg1)
|
||||
ret0, _ := ret[0].(ethtypes.EthUint64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthEstimateGas indicates an expected call of EthEstimateGas.
|
||||
func (mr *MockFullNodeMockRecorder) EthEstimateGas(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthEstimateGas", reflect.TypeOf((*MockFullNode)(nil).EthEstimateGas), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthFeeHistory mocks base method.
|
||||
func (m *MockFullNode) EthFeeHistory(arg0 context.Context, arg1 ethtypes.EthUint64, arg2 string, arg3 []float64) (ethtypes.EthFeeHistory, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthFeeHistory", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(ethtypes.EthFeeHistory)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthFeeHistory indicates an expected call of EthFeeHistory.
|
||||
func (mr *MockFullNodeMockRecorder) EthFeeHistory(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthFeeHistory", reflect.TypeOf((*MockFullNode)(nil).EthFeeHistory), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// EthGasPrice mocks base method.
|
||||
func (m *MockFullNode) EthGasPrice(arg0 context.Context) (ethtypes.EthBigInt, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGasPrice", arg0)
|
||||
ret0, _ := ret[0].(ethtypes.EthBigInt)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGasPrice indicates an expected call of EthGasPrice.
|
||||
func (mr *MockFullNodeMockRecorder) EthGasPrice(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGasPrice", reflect.TypeOf((*MockFullNode)(nil).EthGasPrice), arg0)
|
||||
}
|
||||
|
||||
// EthGetBalance mocks base method.
|
||||
func (m *MockFullNode) EthGetBalance(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 string) (ethtypes.EthBigInt, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetBalance", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(ethtypes.EthBigInt)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetBalance indicates an expected call of EthGetBalance.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetBalance(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBalance", reflect.TypeOf((*MockFullNode)(nil).EthGetBalance), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthGetBlockByHash mocks base method.
|
||||
func (m *MockFullNode) EthGetBlockByHash(arg0 context.Context, arg1 ethtypes.EthHash, arg2 bool) (ethtypes.EthBlock, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetBlockByHash", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(ethtypes.EthBlock)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetBlockByHash indicates an expected call of EthGetBlockByHash.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetBlockByHash(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBlockByHash", reflect.TypeOf((*MockFullNode)(nil).EthGetBlockByHash), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthGetBlockByNumber mocks base method.
|
||||
func (m *MockFullNode) EthGetBlockByNumber(arg0 context.Context, arg1 string, arg2 bool) (ethtypes.EthBlock, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetBlockByNumber", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(ethtypes.EthBlock)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetBlockByNumber indicates an expected call of EthGetBlockByNumber.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetBlockByNumber(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBlockByNumber", reflect.TypeOf((*MockFullNode)(nil).EthGetBlockByNumber), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthGetBlockTransactionCountByHash mocks base method.
|
||||
func (m *MockFullNode) EthGetBlockTransactionCountByHash(arg0 context.Context, arg1 ethtypes.EthHash) (ethtypes.EthUint64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetBlockTransactionCountByHash", arg0, arg1)
|
||||
ret0, _ := ret[0].(ethtypes.EthUint64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetBlockTransactionCountByHash indicates an expected call of EthGetBlockTransactionCountByHash.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetBlockTransactionCountByHash(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBlockTransactionCountByHash", reflect.TypeOf((*MockFullNode)(nil).EthGetBlockTransactionCountByHash), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthGetBlockTransactionCountByNumber mocks base method.
|
||||
func (m *MockFullNode) EthGetBlockTransactionCountByNumber(arg0 context.Context, arg1 ethtypes.EthUint64) (ethtypes.EthUint64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetBlockTransactionCountByNumber", arg0, arg1)
|
||||
ret0, _ := ret[0].(ethtypes.EthUint64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetBlockTransactionCountByNumber indicates an expected call of EthGetBlockTransactionCountByNumber.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetBlockTransactionCountByNumber(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetBlockTransactionCountByNumber", reflect.TypeOf((*MockFullNode)(nil).EthGetBlockTransactionCountByNumber), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthGetCode mocks base method.
|
||||
func (m *MockFullNode) EthGetCode(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 string) (ethtypes.EthBytes, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetCode", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(ethtypes.EthBytes)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetCode indicates an expected call of EthGetCode.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetCode(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetCode", reflect.TypeOf((*MockFullNode)(nil).EthGetCode), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthGetFilterChanges mocks base method.
|
||||
func (m *MockFullNode) EthGetFilterChanges(arg0 context.Context, arg1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetFilterChanges", arg0, arg1)
|
||||
ret0, _ := ret[0].(*ethtypes.EthFilterResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetFilterChanges indicates an expected call of EthGetFilterChanges.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetFilterChanges(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetFilterChanges", reflect.TypeOf((*MockFullNode)(nil).EthGetFilterChanges), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthGetFilterLogs mocks base method.
|
||||
func (m *MockFullNode) EthGetFilterLogs(arg0 context.Context, arg1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetFilterLogs", arg0, arg1)
|
||||
ret0, _ := ret[0].(*ethtypes.EthFilterResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetFilterLogs indicates an expected call of EthGetFilterLogs.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetFilterLogs(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetFilterLogs", reflect.TypeOf((*MockFullNode)(nil).EthGetFilterLogs), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthGetLogs mocks base method.
|
||||
func (m *MockFullNode) EthGetLogs(arg0 context.Context, arg1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetLogs", arg0, arg1)
|
||||
ret0, _ := ret[0].(*ethtypes.EthFilterResult)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetLogs indicates an expected call of EthGetLogs.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetLogs(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetLogs", reflect.TypeOf((*MockFullNode)(nil).EthGetLogs), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthGetStorageAt mocks base method.
|
||||
func (m *MockFullNode) EthGetStorageAt(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 ethtypes.EthBytes, arg3 string) (ethtypes.EthBytes, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetStorageAt", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(ethtypes.EthBytes)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetStorageAt indicates an expected call of EthGetStorageAt.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetStorageAt(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetStorageAt", reflect.TypeOf((*MockFullNode)(nil).EthGetStorageAt), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// EthGetTransactionByBlockHashAndIndex mocks base method.
|
||||
func (m *MockFullNode) EthGetTransactionByBlockHashAndIndex(arg0 context.Context, arg1 ethtypes.EthHash, arg2 ethtypes.EthUint64) (ethtypes.EthTx, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetTransactionByBlockHashAndIndex", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(ethtypes.EthTx)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetTransactionByBlockHashAndIndex indicates an expected call of EthGetTransactionByBlockHashAndIndex.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetTransactionByBlockHashAndIndex(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionByBlockHashAndIndex", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionByBlockHashAndIndex), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthGetTransactionByBlockNumberAndIndex mocks base method.
|
||||
func (m *MockFullNode) EthGetTransactionByBlockNumberAndIndex(arg0 context.Context, arg1, arg2 ethtypes.EthUint64) (ethtypes.EthTx, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetTransactionByBlockNumberAndIndex", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(ethtypes.EthTx)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetTransactionByBlockNumberAndIndex indicates an expected call of EthGetTransactionByBlockNumberAndIndex.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetTransactionByBlockNumberAndIndex(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionByBlockNumberAndIndex", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionByBlockNumberAndIndex), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthGetTransactionByHash mocks base method.
|
||||
func (m *MockFullNode) EthGetTransactionByHash(arg0 context.Context, arg1 *ethtypes.EthHash) (*ethtypes.EthTx, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetTransactionByHash", arg0, arg1)
|
||||
ret0, _ := ret[0].(*ethtypes.EthTx)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetTransactionByHash indicates an expected call of EthGetTransactionByHash.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetTransactionByHash(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionByHash", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionByHash), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthGetTransactionCount mocks base method.
|
||||
func (m *MockFullNode) EthGetTransactionCount(arg0 context.Context, arg1 ethtypes.EthAddress, arg2 string) (ethtypes.EthUint64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetTransactionCount", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(ethtypes.EthUint64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetTransactionCount indicates an expected call of EthGetTransactionCount.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetTransactionCount(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionCount", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionCount), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthGetTransactionReceipt mocks base method.
|
||||
func (m *MockFullNode) EthGetTransactionReceipt(arg0 context.Context, arg1 ethtypes.EthHash) (*api.EthTxReceipt, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthGetTransactionReceipt", arg0, arg1)
|
||||
ret0, _ := ret[0].(*api.EthTxReceipt)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthGetTransactionReceipt indicates an expected call of EthGetTransactionReceipt.
|
||||
func (mr *MockFullNodeMockRecorder) EthGetTransactionReceipt(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthGetTransactionReceipt", reflect.TypeOf((*MockFullNode)(nil).EthGetTransactionReceipt), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthMaxPriorityFeePerGas mocks base method.
|
||||
func (m *MockFullNode) EthMaxPriorityFeePerGas(arg0 context.Context) (ethtypes.EthBigInt, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthMaxPriorityFeePerGas", arg0)
|
||||
ret0, _ := ret[0].(ethtypes.EthBigInt)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthMaxPriorityFeePerGas indicates an expected call of EthMaxPriorityFeePerGas.
|
||||
func (mr *MockFullNodeMockRecorder) EthMaxPriorityFeePerGas(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthMaxPriorityFeePerGas", reflect.TypeOf((*MockFullNode)(nil).EthMaxPriorityFeePerGas), arg0)
|
||||
}
|
||||
|
||||
// EthNewBlockFilter mocks base method.
|
||||
func (m *MockFullNode) EthNewBlockFilter(arg0 context.Context) (ethtypes.EthFilterID, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthNewBlockFilter", arg0)
|
||||
ret0, _ := ret[0].(ethtypes.EthFilterID)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthNewBlockFilter indicates an expected call of EthNewBlockFilter.
|
||||
func (mr *MockFullNodeMockRecorder) EthNewBlockFilter(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthNewBlockFilter", reflect.TypeOf((*MockFullNode)(nil).EthNewBlockFilter), arg0)
|
||||
}
|
||||
|
||||
// EthNewFilter mocks base method.
|
||||
func (m *MockFullNode) EthNewFilter(arg0 context.Context, arg1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthNewFilter", arg0, arg1)
|
||||
ret0, _ := ret[0].(ethtypes.EthFilterID)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthNewFilter indicates an expected call of EthNewFilter.
|
||||
func (mr *MockFullNodeMockRecorder) EthNewFilter(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthNewFilter", reflect.TypeOf((*MockFullNode)(nil).EthNewFilter), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthNewPendingTransactionFilter mocks base method.
|
||||
func (m *MockFullNode) EthNewPendingTransactionFilter(arg0 context.Context) (ethtypes.EthFilterID, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthNewPendingTransactionFilter", arg0)
|
||||
ret0, _ := ret[0].(ethtypes.EthFilterID)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthNewPendingTransactionFilter indicates an expected call of EthNewPendingTransactionFilter.
|
||||
func (mr *MockFullNodeMockRecorder) EthNewPendingTransactionFilter(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthNewPendingTransactionFilter", reflect.TypeOf((*MockFullNode)(nil).EthNewPendingTransactionFilter), arg0)
|
||||
}
|
||||
|
||||
// EthProtocolVersion mocks base method.
|
||||
func (m *MockFullNode) EthProtocolVersion(arg0 context.Context) (ethtypes.EthUint64, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthProtocolVersion", arg0)
|
||||
ret0, _ := ret[0].(ethtypes.EthUint64)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthProtocolVersion indicates an expected call of EthProtocolVersion.
|
||||
func (mr *MockFullNodeMockRecorder) EthProtocolVersion(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthProtocolVersion", reflect.TypeOf((*MockFullNode)(nil).EthProtocolVersion), arg0)
|
||||
}
|
||||
|
||||
// EthSendRawTransaction mocks base method.
|
||||
func (m *MockFullNode) EthSendRawTransaction(arg0 context.Context, arg1 ethtypes.EthBytes) (ethtypes.EthHash, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthSendRawTransaction", arg0, arg1)
|
||||
ret0, _ := ret[0].(ethtypes.EthHash)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthSendRawTransaction indicates an expected call of EthSendRawTransaction.
|
||||
func (mr *MockFullNodeMockRecorder) EthSendRawTransaction(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthSendRawTransaction", reflect.TypeOf((*MockFullNode)(nil).EthSendRawTransaction), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthSubscribe mocks base method.
|
||||
func (m *MockFullNode) EthSubscribe(arg0 context.Context, arg1 string, arg2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthSubscribe", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(<-chan ethtypes.EthSubscriptionResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthSubscribe indicates an expected call of EthSubscribe.
|
||||
func (mr *MockFullNodeMockRecorder) EthSubscribe(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthSubscribe", reflect.TypeOf((*MockFullNode)(nil).EthSubscribe), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// EthUninstallFilter mocks base method.
|
||||
func (m *MockFullNode) EthUninstallFilter(arg0 context.Context, arg1 ethtypes.EthFilterID) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthUninstallFilter", arg0, arg1)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthUninstallFilter indicates an expected call of EthUninstallFilter.
|
||||
func (mr *MockFullNodeMockRecorder) EthUninstallFilter(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthUninstallFilter", reflect.TypeOf((*MockFullNode)(nil).EthUninstallFilter), arg0, arg1)
|
||||
}
|
||||
|
||||
// EthUnsubscribe mocks base method.
|
||||
func (m *MockFullNode) EthUnsubscribe(arg0 context.Context, arg1 ethtypes.EthSubscriptionID) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EthUnsubscribe", arg0, arg1)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// EthUnsubscribe indicates an expected call of EthUnsubscribe.
|
||||
func (mr *MockFullNodeMockRecorder) EthUnsubscribe(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EthUnsubscribe", reflect.TypeOf((*MockFullNode)(nil).EthUnsubscribe), arg0, arg1)
|
||||
}
|
||||
|
||||
// GasEstimateFeeCap mocks base method.
|
||||
func (m *MockFullNode) GasEstimateFeeCap(arg0 context.Context, arg1 *types.Message, arg2 int64, arg3 types.TipSetKey) (big.Int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -1843,6 +2324,21 @@ func (mr *MockFullNodeMockRecorder) NetLimit(arg0, arg1 interface{}) *gomock.Cal
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetLimit", reflect.TypeOf((*MockFullNode)(nil).NetLimit), arg0, arg1)
|
||||
}
|
||||
|
||||
// NetListening mocks base method.
|
||||
func (m *MockFullNode) NetListening(arg0 context.Context) (bool, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "NetListening", arg0)
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// NetListening indicates an expected call of NetListening.
|
||||
func (mr *MockFullNodeMockRecorder) NetListening(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetListening", reflect.TypeOf((*MockFullNode)(nil).NetListening), arg0)
|
||||
}
|
||||
|
||||
// NetPeerInfo mocks base method.
|
||||
func (m *MockFullNode) NetPeerInfo(arg0 context.Context, arg1 peer.ID) (*api.ExtendedPeerInfo, error) {
|
||||
m.ctrl.T.Helper()
|
||||
@ -1975,6 +2471,21 @@ func (mr *MockFullNodeMockRecorder) NetStat(arg0, arg1 interface{}) *gomock.Call
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetStat", reflect.TypeOf((*MockFullNode)(nil).NetStat), arg0, arg1)
|
||||
}
|
||||
|
||||
// NetVersion mocks base method.
|
||||
func (m *MockFullNode) NetVersion(arg0 context.Context) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "NetVersion", arg0)
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// NetVersion indicates an expected call of NetVersion.
|
||||
func (mr *MockFullNodeMockRecorder) NetVersion(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NetVersion", reflect.TypeOf((*MockFullNode)(nil).NetVersion), arg0)
|
||||
}
|
||||
|
||||
// NodeStatus mocks base method.
|
||||
func (m *MockFullNode) NodeStatus(arg0 context.Context, arg1 bool) (api.NodeStatus, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
455
api/proxy_gen.go
455
api/proxy_gen.go
@ -33,9 +33,10 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/proof"
|
||||
|
||||
apitypes "github.com/filecoin-project/lotus/api/types"
|
||||
"github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
builtinactors "github.com/filecoin-project/lotus/chain/actors/builtin"
|
||||
lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
"github.com/filecoin-project/lotus/journal/alerting"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
"github.com/filecoin-project/lotus/node/repo/imports"
|
||||
@ -122,6 +123,8 @@ type FullNodeStruct struct {
|
||||
|
||||
ChainGetBlockMessages func(p0 context.Context, p1 cid.Cid) (*BlockMessages, error) `perm:"read"`
|
||||
|
||||
ChainGetEvents func(p0 context.Context, p1 cid.Cid) ([]types.Event, error) `perm:"read"`
|
||||
|
||||
ChainGetGenesis func(p0 context.Context) (*types.TipSet, error) `perm:"read"`
|
||||
|
||||
ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, error) `perm:"read"`
|
||||
@ -218,6 +221,68 @@ type FullNodeStruct struct {
|
||||
|
||||
CreateBackup func(p0 context.Context, p1 string) error `perm:"admin"`
|
||||
|
||||
EthAccounts func(p0 context.Context) ([]ethtypes.EthAddress, 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"`
|
||||
|
||||
EthChainId func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"`
|
||||
|
||||
EthEstimateGas func(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) `perm:"read"`
|
||||
|
||||
EthFeeHistory func(p0 context.Context, p1 ethtypes.EthUint64, p2 string, p3 []float64) (ethtypes.EthFeeHistory, error) `perm:"read"`
|
||||
|
||||
EthGasPrice func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"`
|
||||
|
||||
EthGetBalance func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) `perm:"read"`
|
||||
|
||||
EthGetBlockByHash func(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) `perm:"read"`
|
||||
|
||||
EthGetBlockByNumber func(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) `perm:"read"`
|
||||
|
||||
EthGetBlockTransactionCountByHash func(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) `perm:"read"`
|
||||
|
||||
EthGetBlockTransactionCountByNumber func(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) `perm:"read"`
|
||||
|
||||
EthGetCode func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) `perm:"read"`
|
||||
|
||||
EthGetFilterChanges func(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) `perm:"write"`
|
||||
|
||||
EthGetFilterLogs func(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) `perm:"write"`
|
||||
|
||||
EthGetLogs func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) `perm:"read"`
|
||||
|
||||
EthGetStorageAt func(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionByBlockHashAndIndex func(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionByBlockNumberAndIndex func(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionByHash func(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionCount func(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) `perm:"read"`
|
||||
|
||||
EthGetTransactionReceipt func(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) `perm:"read"`
|
||||
|
||||
EthMaxPriorityFeePerGas func(p0 context.Context) (ethtypes.EthBigInt, error) `perm:"read"`
|
||||
|
||||
EthNewBlockFilter func(p0 context.Context) (ethtypes.EthFilterID, error) `perm:"write"`
|
||||
|
||||
EthNewFilter func(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) `perm:"write"`
|
||||
|
||||
EthNewPendingTransactionFilter func(p0 context.Context) (ethtypes.EthFilterID, error) `perm:"write"`
|
||||
|
||||
EthProtocolVersion func(p0 context.Context) (ethtypes.EthUint64, error) `perm:"read"`
|
||||
|
||||
EthSendRawTransaction func(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) `perm:"read"`
|
||||
|
||||
EthSubscribe func(p0 context.Context, p1 string, p2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) `perm:"write"`
|
||||
|
||||
EthUninstallFilter func(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) `perm:"write"`
|
||||
|
||||
EthUnsubscribe func(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) `perm:"write"`
|
||||
|
||||
GasEstimateFeeCap func(p0 context.Context, p1 *types.Message, p2 int64, p3 types.TipSetKey) (types.BigInt, error) `perm:"read"`
|
||||
|
||||
GasEstimateGasLimit func(p0 context.Context, p1 *types.Message, p2 types.TipSetKey) (int64, error) `perm:"read"`
|
||||
@ -306,6 +371,10 @@ type FullNodeStruct struct {
|
||||
|
||||
MsigSwapPropose func(p0 context.Context, p1 address.Address, p2 address.Address, p3 address.Address, p4 address.Address) (*MessagePrototype, error) `perm:"sign"`
|
||||
|
||||
NetListening func(p0 context.Context) (bool, error) `perm:"read"`
|
||||
|
||||
NetVersion func(p0 context.Context) (string, error) `perm:"read"`
|
||||
|
||||
NodeStatus func(p0 context.Context, p1 bool) (NodeStatus, error) `perm:"read"`
|
||||
|
||||
PaychAllocateLane func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"sign"`
|
||||
@ -687,7 +756,7 @@ type StorageMinerStruct struct {
|
||||
|
||||
ComputeDataCid func(p0 context.Context, p1 abi.UnpaddedPieceSize, p2 storiface.Data) (abi.PieceInfo, error) `perm:"admin"`
|
||||
|
||||
ComputeProof func(p0 context.Context, p1 []builtin.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtin.PoStProof, error) `perm:"read"`
|
||||
ComputeProof func(p0 context.Context, p1 []builtinactors.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtinactors.PoStProof, error) `perm:"read"`
|
||||
|
||||
ComputeWindowPoSt func(p0 context.Context, p1 uint64, p2 types.TipSetKey) ([]miner.SubmitWindowedPoStParams, error) `perm:"admin"`
|
||||
|
||||
@ -1267,6 +1336,17 @@ func (s *FullNodeStub) ChainGetBlockMessages(p0 context.Context, p1 cid.Cid) (*B
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ChainGetEvents(p0 context.Context, p1 cid.Cid) ([]types.Event, error) {
|
||||
if s.Internal.ChainGetEvents == nil {
|
||||
return *new([]types.Event), ErrNotSupported
|
||||
}
|
||||
return s.Internal.ChainGetEvents(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) ChainGetEvents(p0 context.Context, p1 cid.Cid) ([]types.Event, error) {
|
||||
return *new([]types.Event), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) ChainGetGenesis(p0 context.Context) (*types.TipSet, error) {
|
||||
if s.Internal.ChainGetGenesis == nil {
|
||||
return nil, ErrNotSupported
|
||||
@ -1795,6 +1875,347 @@ func (s *FullNodeStub) CreateBackup(p0 context.Context, p1 string) error {
|
||||
return ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, error) {
|
||||
if s.Internal.EthAccounts == nil {
|
||||
return *new([]ethtypes.EthAddress), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthAccounts(p0)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthAccounts(p0 context.Context) ([]ethtypes.EthAddress, error) {
|
||||
return *new([]ethtypes.EthAddress), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) {
|
||||
if s.Internal.EthBlockNumber == nil {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthBlockNumber(p0)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthBlockNumber(p0 context.Context) (ethtypes.EthUint64, error) {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) {
|
||||
if s.Internal.EthCall == nil {
|
||||
return *new(ethtypes.EthBytes), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthCall(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthCall(p0 context.Context, p1 ethtypes.EthCall, p2 string) (ethtypes.EthBytes, error) {
|
||||
return *new(ethtypes.EthBytes), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthChainId(p0 context.Context) (ethtypes.EthUint64, error) {
|
||||
if s.Internal.EthChainId == nil {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthChainId(p0)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthChainId(p0 context.Context) (ethtypes.EthUint64, error) {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
if s.Internal.EthEstimateGas == nil {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthEstimateGas(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthEstimateGas(p0 context.Context, p1 ethtypes.EthCall) (ethtypes.EthUint64, error) {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthFeeHistory(p0 context.Context, p1 ethtypes.EthUint64, p2 string, p3 []float64) (ethtypes.EthFeeHistory, error) {
|
||||
if s.Internal.EthFeeHistory == nil {
|
||||
return *new(ethtypes.EthFeeHistory), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthFeeHistory(p0, p1, p2, p3)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthFeeHistory(p0 context.Context, p1 ethtypes.EthUint64, p2 string, p3 []float64) (ethtypes.EthFeeHistory, error) {
|
||||
return *new(ethtypes.EthFeeHistory), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, error) {
|
||||
if s.Internal.EthGasPrice == nil {
|
||||
return *new(ethtypes.EthBigInt), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGasPrice(p0)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGasPrice(p0 context.Context) (ethtypes.EthBigInt, error) {
|
||||
return *new(ethtypes.EthBigInt), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) {
|
||||
if s.Internal.EthGetBalance == nil {
|
||||
return *new(ethtypes.EthBigInt), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetBalance(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetBalance(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBigInt, error) {
|
||||
return *new(ethtypes.EthBigInt), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetBlockByHash(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) {
|
||||
if s.Internal.EthGetBlockByHash == nil {
|
||||
return *new(ethtypes.EthBlock), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetBlockByHash(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetBlockByHash(p0 context.Context, p1 ethtypes.EthHash, p2 bool) (ethtypes.EthBlock, error) {
|
||||
return *new(ethtypes.EthBlock), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetBlockByNumber(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) {
|
||||
if s.Internal.EthGetBlockByNumber == nil {
|
||||
return *new(ethtypes.EthBlock), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetBlockByNumber(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetBlockByNumber(p0 context.Context, p1 string, p2 bool) (ethtypes.EthBlock, error) {
|
||||
return *new(ethtypes.EthBlock), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetBlockTransactionCountByHash(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) {
|
||||
if s.Internal.EthGetBlockTransactionCountByHash == nil {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetBlockTransactionCountByHash(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetBlockTransactionCountByHash(p0 context.Context, p1 ethtypes.EthHash) (ethtypes.EthUint64, error) {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) {
|
||||
if s.Internal.EthGetBlockTransactionCountByNumber == nil {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetBlockTransactionCountByNumber(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetBlockTransactionCountByNumber(p0 context.Context, p1 ethtypes.EthUint64) (ethtypes.EthUint64, error) {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) {
|
||||
if s.Internal.EthGetCode == nil {
|
||||
return *new(ethtypes.EthBytes), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetCode(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetCode(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthBytes, error) {
|
||||
return *new(ethtypes.EthBytes), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetFilterChanges(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {
|
||||
if s.Internal.EthGetFilterChanges == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetFilterChanges(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetFilterChanges(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetFilterLogs(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {
|
||||
if s.Internal.EthGetFilterLogs == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetFilterLogs(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetFilterLogs(p0 context.Context, p1 ethtypes.EthFilterID) (*ethtypes.EthFilterResult, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) {
|
||||
if s.Internal.EthGetLogs == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetLogs(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetLogs(p0 context.Context, p1 *ethtypes.EthFilterSpec) (*ethtypes.EthFilterResult, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) {
|
||||
if s.Internal.EthGetStorageAt == nil {
|
||||
return *new(ethtypes.EthBytes), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetStorageAt(p0, p1, p2, p3)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetStorageAt(p0 context.Context, p1 ethtypes.EthAddress, p2 ethtypes.EthBytes, p3 string) (ethtypes.EthBytes, error) {
|
||||
return *new(ethtypes.EthBytes), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetTransactionByBlockHashAndIndex(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) {
|
||||
if s.Internal.EthGetTransactionByBlockHashAndIndex == nil {
|
||||
return *new(ethtypes.EthTx), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetTransactionByBlockHashAndIndex(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetTransactionByBlockHashAndIndex(p0 context.Context, p1 ethtypes.EthHash, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) {
|
||||
return *new(ethtypes.EthTx), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetTransactionByBlockNumberAndIndex(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) {
|
||||
if s.Internal.EthGetTransactionByBlockNumberAndIndex == nil {
|
||||
return *new(ethtypes.EthTx), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetTransactionByBlockNumberAndIndex(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetTransactionByBlockNumberAndIndex(p0 context.Context, p1 ethtypes.EthUint64, p2 ethtypes.EthUint64) (ethtypes.EthTx, error) {
|
||||
return *new(ethtypes.EthTx), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetTransactionByHash(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) {
|
||||
if s.Internal.EthGetTransactionByHash == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetTransactionByHash(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetTransactionByHash(p0 context.Context, p1 *ethtypes.EthHash) (*ethtypes.EthTx, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) {
|
||||
if s.Internal.EthGetTransactionCount == nil {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetTransactionCount(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetTransactionCount(p0 context.Context, p1 ethtypes.EthAddress, p2 string) (ethtypes.EthUint64, error) {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) {
|
||||
if s.Internal.EthGetTransactionReceipt == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthGetTransactionReceipt(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthGetTransactionReceipt(p0 context.Context, p1 ethtypes.EthHash) (*EthTxReceipt, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthMaxPriorityFeePerGas(p0 context.Context) (ethtypes.EthBigInt, error) {
|
||||
if s.Internal.EthMaxPriorityFeePerGas == nil {
|
||||
return *new(ethtypes.EthBigInt), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthMaxPriorityFeePerGas(p0)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthMaxPriorityFeePerGas(p0 context.Context) (ethtypes.EthBigInt, error) {
|
||||
return *new(ethtypes.EthBigInt), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthNewBlockFilter(p0 context.Context) (ethtypes.EthFilterID, error) {
|
||||
if s.Internal.EthNewBlockFilter == nil {
|
||||
return *new(ethtypes.EthFilterID), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthNewBlockFilter(p0)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthNewBlockFilter(p0 context.Context) (ethtypes.EthFilterID, error) {
|
||||
return *new(ethtypes.EthFilterID), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthNewFilter(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) {
|
||||
if s.Internal.EthNewFilter == nil {
|
||||
return *new(ethtypes.EthFilterID), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthNewFilter(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthNewFilter(p0 context.Context, p1 *ethtypes.EthFilterSpec) (ethtypes.EthFilterID, error) {
|
||||
return *new(ethtypes.EthFilterID), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthNewPendingTransactionFilter(p0 context.Context) (ethtypes.EthFilterID, error) {
|
||||
if s.Internal.EthNewPendingTransactionFilter == nil {
|
||||
return *new(ethtypes.EthFilterID), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthNewPendingTransactionFilter(p0)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthNewPendingTransactionFilter(p0 context.Context) (ethtypes.EthFilterID, error) {
|
||||
return *new(ethtypes.EthFilterID), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthProtocolVersion(p0 context.Context) (ethtypes.EthUint64, error) {
|
||||
if s.Internal.EthProtocolVersion == nil {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthProtocolVersion(p0)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthProtocolVersion(p0 context.Context) (ethtypes.EthUint64, error) {
|
||||
return *new(ethtypes.EthUint64), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthSendRawTransaction(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) {
|
||||
if s.Internal.EthSendRawTransaction == nil {
|
||||
return *new(ethtypes.EthHash), ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthSendRawTransaction(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthSendRawTransaction(p0 context.Context, p1 ethtypes.EthBytes) (ethtypes.EthHash, error) {
|
||||
return *new(ethtypes.EthHash), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthSubscribe(p0 context.Context, p1 string, p2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) {
|
||||
if s.Internal.EthSubscribe == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthSubscribe(p0, p1, p2)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthSubscribe(p0 context.Context, p1 string, p2 *ethtypes.EthSubscriptionParams) (<-chan ethtypes.EthSubscriptionResponse, error) {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) {
|
||||
if s.Internal.EthUninstallFilter == nil {
|
||||
return false, ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthUninstallFilter(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthUninstallFilter(p0 context.Context, p1 ethtypes.EthFilterID) (bool, error) {
|
||||
return false, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) EthUnsubscribe(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) {
|
||||
if s.Internal.EthUnsubscribe == nil {
|
||||
return false, ErrNotSupported
|
||||
}
|
||||
return s.Internal.EthUnsubscribe(p0, p1)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) EthUnsubscribe(p0 context.Context, p1 ethtypes.EthSubscriptionID) (bool, error) {
|
||||
return false, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) GasEstimateFeeCap(p0 context.Context, p1 *types.Message, p2 int64, p3 types.TipSetKey) (types.BigInt, error) {
|
||||
if s.Internal.GasEstimateFeeCap == nil {
|
||||
return *new(types.BigInt), ErrNotSupported
|
||||
@ -2279,6 +2700,28 @@ func (s *FullNodeStub) MsigSwapPropose(p0 context.Context, p1 address.Address, p
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) NetListening(p0 context.Context) (bool, error) {
|
||||
if s.Internal.NetListening == nil {
|
||||
return false, ErrNotSupported
|
||||
}
|
||||
return s.Internal.NetListening(p0)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) NetListening(p0 context.Context) (bool, error) {
|
||||
return false, ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) NetVersion(p0 context.Context) (string, error) {
|
||||
if s.Internal.NetVersion == nil {
|
||||
return "", ErrNotSupported
|
||||
}
|
||||
return s.Internal.NetVersion(p0)
|
||||
}
|
||||
|
||||
func (s *FullNodeStub) NetVersion(p0 context.Context) (string, error) {
|
||||
return "", ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *FullNodeStruct) NodeStatus(p0 context.Context, p1 bool) (NodeStatus, error) {
|
||||
if s.Internal.NodeStatus == nil {
|
||||
return *new(NodeStatus), ErrNotSupported
|
||||
@ -4182,15 +4625,15 @@ func (s *StorageMinerStub) ComputeDataCid(p0 context.Context, p1 abi.UnpaddedPie
|
||||
return *new(abi.PieceInfo), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *StorageMinerStruct) ComputeProof(p0 context.Context, p1 []builtin.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtin.PoStProof, error) {
|
||||
func (s *StorageMinerStruct) ComputeProof(p0 context.Context, p1 []builtinactors.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtinactors.PoStProof, error) {
|
||||
if s.Internal.ComputeProof == nil {
|
||||
return *new([]builtin.PoStProof), ErrNotSupported
|
||||
return *new([]builtinactors.PoStProof), ErrNotSupported
|
||||
}
|
||||
return s.Internal.ComputeProof(p0, p1, p2, p3, p4)
|
||||
}
|
||||
|
||||
func (s *StorageMinerStub) ComputeProof(p0 context.Context, p1 []builtin.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtin.PoStProof, error) {
|
||||
return *new([]builtin.PoStProof), ErrNotSupported
|
||||
func (s *StorageMinerStub) ComputeProof(p0 context.Context, p1 []builtinactors.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtinactors.PoStProof, error) {
|
||||
return *new([]builtinactors.PoStProof), ErrNotSupported
|
||||
}
|
||||
|
||||
func (s *StorageMinerStruct) ComputeWindowPoSt(p0 context.Context, p1 uint64, p2 types.TipSetKey) ([]miner.SubmitWindowedPoStParams, error) {
|
||||
|
@ -338,6 +338,7 @@ type ForkUpgradeParams struct {
|
||||
UpgradeOhSnapHeight abi.ChainEpoch
|
||||
UpgradeSkyrHeight abi.ChainEpoch
|
||||
UpgradeSharkHeight abi.ChainEpoch
|
||||
UpgradeHyggeHeight abi.ChainEpoch
|
||||
}
|
||||
|
||||
type NonceMapType map[address.Address]uint64
|
||||
|
@ -141,7 +141,7 @@ type FullNode interface {
|
||||
|
||||
// ChainGetPath returns a set of revert/apply operations needed to get from
|
||||
// one tipset to another, for example:
|
||||
//```
|
||||
// ```
|
||||
// to
|
||||
// ^
|
||||
// from tAA
|
||||
@ -150,7 +150,7 @@ type FullNode interface {
|
||||
// ^---*--^
|
||||
// ^
|
||||
// tRR
|
||||
//```
|
||||
// ```
|
||||
// Would return `[revert(tBA), apply(tAB), apply(tAA)]`
|
||||
ChainGetPath(ctx context.Context, from types.TipSetKey, to types.TipSetKey) ([]*api.HeadChange, error) //perm:read
|
||||
|
||||
@ -367,12 +367,12 @@ type FullNode interface {
|
||||
ClientCancelRetrievalDeal(ctx context.Context, dealid retrievalmarket.DealID) error //perm:write
|
||||
|
||||
// ClientUnimport removes references to the specified file from filestore
|
||||
//ClientUnimport(path string)
|
||||
// ClientUnimport(path string)
|
||||
|
||||
// ClientListImports lists imported files and their root CIDs
|
||||
ClientListImports(ctx context.Context) ([]api.Import, error) //perm:write
|
||||
|
||||
//ClientListAsks() []Ask
|
||||
// ClientListAsks() []Ask
|
||||
|
||||
// MethodGroup: State
|
||||
// The State methods are used to query, inspect, and interact with chain state.
|
||||
@ -641,14 +641,14 @@ type FullNode interface {
|
||||
// It takes the following params: <multisig address>, <start epoch>, <end epoch>
|
||||
MsigGetVested(context.Context, address.Address, types.TipSetKey, types.TipSetKey) (types.BigInt, error) //perm:read
|
||||
|
||||
//MsigGetPending returns pending transactions for the given multisig
|
||||
//wallet. Once pending transactions are fully approved, they will no longer
|
||||
//appear here.
|
||||
// MsigGetPending returns pending transactions for the given multisig
|
||||
// wallet. Once pending transactions are fully approved, they will no longer
|
||||
// appear here.
|
||||
MsigGetPending(context.Context, address.Address, types.TipSetKey) ([]*api.MsigTransaction, error) //perm:read
|
||||
|
||||
// MsigCreate creates a multisig wallet
|
||||
// It takes the following params: <required number of senders>, <approving addresses>, <unlock duration>
|
||||
//<initial balance>, <sender address of the create msg>, <gas price>
|
||||
// <initial balance>, <sender address of the create msg>, <gas price>
|
||||
MsigCreate(context.Context, uint64, []address.Address, abi.ChainEpoch, types.BigInt, address.Address, types.BigInt) (cid.Cid, error) //perm:sign
|
||||
// MsigPropose proposes a multisig message
|
||||
// It takes the following params: <multisig address>, <recipient address>, <value to transfer>,
|
||||
|
@ -905,6 +905,10 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp
|
||||
walkCnt := new(int64)
|
||||
scanCnt := new(int64)
|
||||
|
||||
tsRef := func(blkCids []cid.Cid) (cid.Cid, error) {
|
||||
return types.NewTipSetKey(blkCids...).Cid()
|
||||
}
|
||||
|
||||
stopWalk := func(_ cid.Cid) error { return errStopWalk }
|
||||
|
||||
walkBlock := func(c cid.Cid) error {
|
||||
@ -926,11 +930,19 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp
|
||||
err = s.view(c, func(data []byte) error {
|
||||
return hdr.UnmarshalCBOR(bytes.NewBuffer(data))
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error unmarshaling block header (cid: %s): %w", c, err)
|
||||
}
|
||||
|
||||
// tipset CID references are retained
|
||||
pRef, err := tsRef(hdr.Parents)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error computing cid reference to parent tipset")
|
||||
}
|
||||
if err := s.walkObjectIncomplete(pRef, visitor, fHot, stopWalk); err != nil {
|
||||
return xerrors.Errorf("error walking parent tipset cid reference")
|
||||
}
|
||||
|
||||
// message are retained if within the inclMsgs boundary
|
||||
if hdr.Height >= inclMsgs && hdr.Height > 0 {
|
||||
if inclMsgs < inclState {
|
||||
@ -981,6 +993,15 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp
|
||||
return nil
|
||||
}
|
||||
|
||||
// retain ref to chain head
|
||||
hRef, err := tsRef(ts.Cids())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error computing cid reference to parent tipset")
|
||||
}
|
||||
if err := s.walkObjectIncomplete(hRef, visitor, fHot, stopWalk); err != nil {
|
||||
return xerrors.Errorf("error walking parent tipset cid reference")
|
||||
}
|
||||
|
||||
for len(toWalk) > 0 {
|
||||
// walking can take a while, so check this with every opportunity
|
||||
if err := s.checkClosing(); err != nil {
|
||||
|
@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
NETWORKS=(devnet mainnet caterpillarnet butterflynet testing testing-fake-proofs calibrationnet)
|
||||
NETWORKS=(devnet mainnet caterpillarnet butterflynet testing testing-fake-proofs calibrationnet hyperspace)
|
||||
|
||||
set -e
|
||||
|
||||
|
Binary file not shown.
4
build/bootstrap/wallabynet.pi
Normal file
4
build/bootstrap/wallabynet.pi
Normal file
@ -0,0 +1,4 @@
|
||||
/dns4/de0.bootstrap.wallaby.network/tcp/1337/p2p/12D3KooWHAvUVk5XuxSwi2dNLWbTDDRSGeHxMuWdQ3SQpRuNHbLz
|
||||
/dns4/de1.bootstrap.wallaby.network/tcp/1337/p2p/12D3KooWBRqtxhJCtiLmCwKgAQozJtdGinEDdJGoS5oHw7vCjMGc
|
||||
/dns4/ca0.bootstrap.wallaby.network/tcp/1337/p2p/12D3KooWCApBpUk7EX9pmEfyky1gKC6N2KJ74S1AwFfvnkDqw3pK
|
||||
/dns4/sg0.bootstrap.wallaby.network/tcp/1337/p2p/12D3KooWLnYqr4hRoNHBJQVXsFGkDoKuoVfw5R2ASw1bHzrWU5Px
|
@ -44,23 +44,24 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
||||
}, {
|
||||
Network: "butterflynet",
|
||||
Version: 10,
|
||||
ManifestCid: MustParseCid("bafy2bzaceciz4ytt5gnn6gc4epez7v6xeg6efkgbvwfxkoa34o2gj3hp5f7zc"),
|
||||
ManifestCid: MustParseCid("bafy2bzaceav7txndea2xt6kvaosokp42vyjkhtplbb67tpkov3jbsvbwplnz4"),
|
||||
Actors: map[string]cid.Cid{
|
||||
"account": MustParseCid("bafk2bzacedavorwsriewoddjlaganjpsk3o7zfts2wyid3clv5xnctacg37j2"),
|
||||
"cron": MustParseCid("bafk2bzacebtauucwaewxuzgxfpjtmn6xt3kya4om4ugyprlkhhkde76h7fkqg"),
|
||||
"datacap": MustParseCid("bafk2bzacebzdjapqwasq6woxkgq2nm2nre3v7cl2754xwiuo2cfhvsceq4cba"),
|
||||
"eam": MustParseCid("bafk2bzacecmr4zdbpfnemvgo446qby7x4y4v5cbfespt3f6ousv2hxnflyrlk"),
|
||||
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"),
|
||||
"evm": MustParseCid("bafk2bzacebuewexvig54cuvsvwn4k4zr36tm2q5fel4ezq4v7363n2lmn362k"),
|
||||
"init": MustParseCid("bafk2bzacebww5gsctsk5hack2alkt4kh55bmpb4ywzbyyhoaskryymjj3snj6"),
|
||||
"multisig": MustParseCid("bafk2bzacec5k4wxvou34pyjd5kcsrbsfnlk4k753kkscg3ron2r7tsxollfsq"),
|
||||
"paymentchannel": MustParseCid("bafk2bzacebzdeaxglaqpmegalakmxr6secjd24mu5llo4ctoy7pvom5upyuvs"),
|
||||
"reward": MustParseCid("bafk2bzaceb4hyabxnyrrsno5erqqwk5ynnjibblzfcaq3aotlz3ek4uu6dyla"),
|
||||
"storagemarket": MustParseCid("bafk2bzacedpocbf2lg2x2jg6arw2argnwmvo2hyjqvpkrgfu4khz5mtlzxz2o"),
|
||||
"storageminer": MustParseCid("bafk2bzaceacrumah7jdfc62bmvemob4lsh5yiohwodest2cgxakgnn24cenlk"),
|
||||
"storagepower": MustParseCid("bafk2bzaceaxz6n5nywermfptnz6dc53vqsa42lic4rf66l4irm3mqfj4ak5ps"),
|
||||
"system": MustParseCid("bafk2bzaceb4w5bblgyu25ylytpmfrixjsk2ra6emd44j4mv42xfxbwnqloyzi"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzacedbz2koeb6teewobcjdpgfv7qdae7utgoka6wzlkf6gronnis2nn2"),
|
||||
"account": MustParseCid("bafk2bzacec34ox7drngorgal3ujxat2a2dlsh7eissgiisrv2uubuub2avbe2"),
|
||||
"cron": MustParseCid("bafk2bzaceb77n6gkytpkn2wguemnpfqfaynv7u6ci4j247leg2w3dhcoxa5ns"),
|
||||
"datacap": MustParseCid("bafk2bzacebj2ztqmlb7mmkggaqf66sv7gao5722vzmpnngiuncu4efpsjyhy4"),
|
||||
"eam": MustParseCid("bafk2bzacecvl6xpmldfk5oyehqhmuasp7cbx3kh3y425curdy65hlmhovc4oi"),
|
||||
"ethaccount": MustParseCid("bafk2bzacec2wy3fknb63r5zili7qojvt4f3rvstweqvnjne5adarx3lskgz5m"),
|
||||
"evm": MustParseCid("bafk2bzacebtoqzucrh7kvtxpo4ruzisey67z6t3z5cbff4c36du3dlm3aj4l6"),
|
||||
"init": MustParseCid("bafk2bzacebvc5t5u3opeyx4rxbeinshjsghjhttdbsyqifb4ikzpa2ic5mkhu"),
|
||||
"multisig": MustParseCid("bafk2bzaceckmb2bcw2m5o4hifhodrq2j6ow5nhouj5wpqsxpzntgveft3hplu"),
|
||||
"paymentchannel": MustParseCid("bafk2bzacebsvkpbavcdjguev4dxfnjx5j5bqzeeyk3petwbkmfptoej5bqlqc"),
|
||||
"placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
|
||||
"reward": MustParseCid("bafk2bzacea3rkyhzmugj6ap3uv5m5jnhxt64y2775vo6vemdi5aafzxty3nmq"),
|
||||
"storagemarket": MustParseCid("bafk2bzacebfacbnuauxhq63f5jbchoi2xwc5ljrxnwgj2xulkx4yzfu6i4lhg"),
|
||||
"storageminer": MustParseCid("bafk2bzaceal4ct6gwlzl3owu6d4iiudf4ioxth5gn6cvm37enl465px2bhznk"),
|
||||
"storagepower": MustParseCid("bafk2bzaceb5pdkt55d7wxjgmhvzvnlkuw5r6eamypgqm5kem5tz3sxddwtizw"),
|
||||
"system": MustParseCid("bafk2bzacecuu2y5b6r4jrj64w5yuh3klnoevrcnbdxozmtagdcyfve7oe27ri"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzacediez3q42tjeit7hbsglv33ltfeamoa43lftwsxh2nyov5ijhuihm"),
|
||||
},
|
||||
}, {
|
||||
Network: "calibrationnet",
|
||||
@ -100,23 +101,24 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
||||
}, {
|
||||
Network: "calibrationnet",
|
||||
Version: 10,
|
||||
ManifestCid: MustParseCid("bafy2bzaced7wbd43lvgc55xb37mkoo4ppev6ig4jj4j7dtswtjfjq4u5qmpck"),
|
||||
ManifestCid: MustParseCid("bafy2bzacebb4qaymahytofcakf3vcyuv4tnu4zsgxp4iikc6kkmfagtaierro"),
|
||||
Actors: map[string]cid.Cid{
|
||||
"account": MustParseCid("bafk2bzacecq4owv5begvryvpsy4atfb2jnf7g7o4hxovtdb5a4jfkzacownli"),
|
||||
"cron": MustParseCid("bafk2bzaced4uz5w5h5wksx4end27lphd4qc4kh7q336uyt46lba5ddynwftya"),
|
||||
"datacap": MustParseCid("bafk2bzacedoc7y4s5n3p2zo4bcmafcrellkakn2e3uyf5wb3mtbuqhvwqn2l4"),
|
||||
"eam": MustParseCid("bafk2bzacealpqjgz5qmucm3v6z6hn36igx7zijixhqrxwoj3g4bdgvyml3adi"),
|
||||
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"),
|
||||
"evm": MustParseCid("bafk2bzacedmlmyy2efbt4qk5ighawiychklhzc6pzyiwvpijwvxoq3xyxlgxw"),
|
||||
"init": MustParseCid("bafk2bzaceaqcfmfylwdemq5bdcelydpf6iqfct4p7b2zwtmqyhuxn522yvic2"),
|
||||
"multisig": MustParseCid("bafk2bzacebuh55hkbkobmmoaoduruss5nsh6e2gtqtdbqsmw6e7k5vg6heyrm"),
|
||||
"paymentchannel": MustParseCid("bafk2bzacedcpzw7prdoxnaclcvmtwr6yf54zi4bzzwe5w3xknh72ji6p3qfc6"),
|
||||
"reward": MustParseCid("bafk2bzaced74ym6j424zzbr6millasfcyl3r4zm5fnauasrwn3ti6fdarbkym"),
|
||||
"storagemarket": MustParseCid("bafk2bzacec7delr2q42yj4wu3daa5xjz4zezeivphtx3xwyvpgwpdnfoevhh2"),
|
||||
"storageminer": MustParseCid("bafk2bzaced7isnew5lhu237pdtwaqmbv65qqvfmmnve2c5yfobtfqw2fptuvc"),
|
||||
"storagepower": MustParseCid("bafk2bzacebe5frk6gcgzcvzkxavhhbs3id3iyacybn7y7gxwzgl5t6zawzswg"),
|
||||
"system": MustParseCid("bafk2bzacectivaezqijucle5s2f7xeui5uxig7bnk7fe4vsvz3xu7agjtb2ge"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzaceczgwckte4exultjxyzgzoo6m6r5coyphnlappi4clethhhybslxc"),
|
||||
"account": MustParseCid("bafk2bzaceakcix46r7hh4wjhzaksnha6f5elbg62ld6dklz6ttkhisnppmoe2"),
|
||||
"cron": MustParseCid("bafk2bzaceb5ezi5dlgxjmxffecrmgiajwseiblgivho5qnfejivuqxfclooma"),
|
||||
"datacap": MustParseCid("bafk2bzaceag4j2myqvwevm3mdtvmqoeguwtjheyezodjcpq5ugibjx6gtz65u"),
|
||||
"eam": MustParseCid("bafk2bzacedwnuqthwpl3si5gs27xnxq7bcr5ucg3vg4utltfhnytaqzwlk33g"),
|
||||
"ethaccount": MustParseCid("bafk2bzacechx3zdc4yw7ehtelecwsp6hb2iguefusfccqxfmdinjjoa64ado4"),
|
||||
"evm": MustParseCid("bafk2bzaceaqtomr2odeyjabgkwnwfgm54b44cpshpkssn7nq35umzogkqqbee"),
|
||||
"init": MustParseCid("bafk2bzacebtqjmdudvfl5cq6yqswortlc46cjpz36qj5igzfglu55kppuovyw"),
|
||||
"multisig": MustParseCid("bafk2bzaceb2hlrmljz26gecv7zj5ymeleiuebf6mnvc7vng3qbcxvxagrlc22"),
|
||||
"paymentchannel": MustParseCid("bafk2bzacecbn4m6evxxoalujyt4wnas3hdttffzjee5qjp62w7dsjdoeuhzka"),
|
||||
"placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
|
||||
"reward": MustParseCid("bafk2bzaceds2kn4fn27nwlxx2raawldkytlro6i2qeh6rdtmme6ybd4otpwqq"),
|
||||
"storagemarket": MustParseCid("bafk2bzacec35rrhgiqqrwqjtuhoseg7e4g67sqaa74b2x2p7f37ylfulc672i"),
|
||||
"storageminer": MustParseCid("bafk2bzaceaiwkboswmk4kmzctnzd5txf2axdvladlf6x5as7ey7avxa5dgfd4"),
|
||||
"storagepower": MustParseCid("bafk2bzaceb2nlgx5aw2psgiedc7oqefs6mttwcloczsbucxtit55zzpbgr4fc"),
|
||||
"system": MustParseCid("bafk2bzacecki2gyvfguathvwva4ilovedftfuxvk3rhuw4y2t4aawkm2e5ttq"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzacebvicauwopayihp5jjegtma26nuhubauya73tkhpdfs27xwjutn4w"),
|
||||
},
|
||||
}, {
|
||||
Network: "caterpillarnet",
|
||||
@ -156,23 +158,24 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
||||
}, {
|
||||
Network: "caterpillarnet",
|
||||
Version: 10,
|
||||
ManifestCid: MustParseCid("bafy2bzacea5csj2os7h76a6yvf6shgpwkysawijxemk5uvvzejxrwjo6ir4yg"),
|
||||
ManifestCid: MustParseCid("bafy2bzacedktxutlehqmx2uryphph6dln4wbgy6yfsj7un36b2u7l7a32n3km"),
|
||||
Actors: map[string]cid.Cid{
|
||||
"account": MustParseCid("bafk2bzacea7tpruyxdgyz4xa7curiphwdw4abmspft3ee24puruazdcl3tq5c"),
|
||||
"cron": MustParseCid("bafk2bzacebc6kkj7kzsicm5baszjgd37b4b3kijsffqmmkhhjlyd7zhkwfcqm"),
|
||||
"datacap": MustParseCid("bafk2bzaceddcmwl6po2jd3tfkkgv4zvub7i47gsx33pkqdspqhgvhe4npc4as"),
|
||||
"eam": MustParseCid("bafk2bzaceccsvcww2rmqnh4plkq6oapqaeqbhydrtup54z4dwunolz5tpgtb4"),
|
||||
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"),
|
||||
"evm": MustParseCid("bafk2bzacea5sig3zpxfkqppoj3t344cvuhzvkx6ge2isgdzc34rfpng2ogdje"),
|
||||
"init": MustParseCid("bafk2bzacedtby353aho7itoyoj7w6moydmigjm3sgy6djgnfxqehlpae4vcc2"),
|
||||
"multisig": MustParseCid("bafk2bzacedyguvwz5zfveqoqicn3j6lkdzipf247nhvdi6dvmahulr7nzgox6"),
|
||||
"paymentchannel": MustParseCid("bafk2bzaceavaatmmnsz3v3ksopcbu6jx4iq7u7nnmqbclsiabsfkfu3zfpmka"),
|
||||
"reward": MustParseCid("bafk2bzacecrphs4avteik4yejsqwkpy5bcqramdhnzykbfq3uu2qalj2p26ti"),
|
||||
"storagemarket": MustParseCid("bafk2bzaceajby2jb5m3fenzarum374zxdzuyrpkspfljwovu7c3hvyceqd5sa"),
|
||||
"storageminer": MustParseCid("bafk2bzacebqtn7jdvk756ighri5ajro6gjepnef3c6rxupbbgkth62zytiy5s"),
|
||||
"storagepower": MustParseCid("bafk2bzacedwlo32brlalpovfkkk7qwo3ou2kpgv2bf7fioy5srn7uejmn7n46"),
|
||||
"system": MustParseCid("bafk2bzacebbt63h26x5vw5fdo2pmdb4q65u3t6lilkugvmjar6zfsc7ethxsi"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzacecr5kbyypdxnxlepzk5sji2k72t454vto5ok4owfcuwfpeyivjtu4"),
|
||||
"account": MustParseCid("bafk2bzaceaoina2vmmq24ij5kqbgawjrlnxkmj6arzucoigabt25ch6cdvbyc"),
|
||||
"cron": MustParseCid("bafk2bzaceancnphwoym4pmzatrzfxo3bac72gk4bjgaqxedrigfrua62an3n2"),
|
||||
"datacap": MustParseCid("bafk2bzaceaoebtmqyqvyv7oq7ehdkhl6fxjamz5fjdje7axslxsc7rhqchcdm"),
|
||||
"eam": MustParseCid("bafk2bzaceazfxudfagmhdmwx46sjeyqoba3quy7cllqv2nuksh3ikc6gw63yg"),
|
||||
"ethaccount": MustParseCid("bafk2bzaceblsm6aaymb2ua64eqbe32uyxdoyqzger5recw6k4p43yeu2oyigi"),
|
||||
"evm": MustParseCid("bafk2bzacea7jveqmq5u6ijabkbuujtgqzmy3p5zl5x45frnygio3hqqnabbso"),
|
||||
"init": MustParseCid("bafk2bzacecdewh4goftyp2cmuq3zpkyjinv6faysksjgqxtbk2j5dljv75rgq"),
|
||||
"multisig": MustParseCid("bafk2bzacecpscu24o2fwlspi64k3fiaufeh3nnrv6wgumvaeco2jduhposcf4"),
|
||||
"paymentchannel": MustParseCid("bafk2bzacedxc3fy436wlebsusgwcwqf6lzo7yv5iugy75z5hwrdt33pq2rhho"),
|
||||
"placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
|
||||
"reward": MustParseCid("bafk2bzacebzvjtzzuo6ijkbx2yx3ly6vlrgw37fymasdwcdymlxc26znib2og"),
|
||||
"storagemarket": MustParseCid("bafk2bzaceabdr5l4qluc4rgxjxo4xnoyc5e6slp7s3fojhnv4ng3swu7qv556"),
|
||||
"storageminer": MustParseCid("bafk2bzaceclwbgfqr7wqepi6xkpoqz2bl6p22mlbmsgs4zarxki2cub5rspxy"),
|
||||
"storagepower": MustParseCid("bafk2bzacean3trpjoxvwztrmbw7lx6osapicxzclyz2cgou4upq432norjnaq"),
|
||||
"system": MustParseCid("bafk2bzacedeexlnmp677eauba76trar47p2zddbspiodri5aof6ccasyicxxo"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzaceayctmu2avbckz4scuep3ocxsw5r3eqxz7wu27volaxnvfvoxjhbq"),
|
||||
},
|
||||
}, {
|
||||
Network: "devnet",
|
||||
@ -212,23 +215,46 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
||||
}, {
|
||||
Network: "devnet",
|
||||
Version: 10,
|
||||
ManifestCid: MustParseCid("bafy2bzacea73thrlpfejrswlcu5uhe7rcgdewvmrcwoef6jzngsba3i4v5ibi"),
|
||||
ManifestCid: MustParseCid("bafy2bzacea2wblucgi2tztgk52fap2wsjddrrobito5zdklqdhpdwhmyr7lbk"),
|
||||
Actors: map[string]cid.Cid{
|
||||
"account": MustParseCid("bafk2bzaceau2o55aripm7kqrbzzog72zcduv5psnxzpohx5rdkykepc4z7aag"),
|
||||
"cron": MustParseCid("bafk2bzacec5qc5xluwikf4lolfa4oe356iwep25tiezbxfdyg5jib54rhlh6q"),
|
||||
"datacap": MustParseCid("bafk2bzacebo47u6q3xou5exsecjpa4rpfqjfm7vyhz4qlr3nk7p46trsk4occ"),
|
||||
"eam": MustParseCid("bafk2bzacea6yeptevserd7ayf4ahokor4sdpizpxpbqwkuvvhzdkon672shsm"),
|
||||
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"),
|
||||
"evm": MustParseCid("bafk2bzacebi46zgjili4luu3nqy6mno5k4skvo4cvs7genhkdfaukhtw7xirw"),
|
||||
"init": MustParseCid("bafk2bzacedvf2bij6jovem2dfzkz347yvmydxj7vlgaiagosz5t3c5jyy43zu"),
|
||||
"multisig": MustParseCid("bafk2bzacecukolwx6y5pcajnxg2aawiubgxo5zyj24a23zg5t4qu3k4qbofh4"),
|
||||
"paymentchannel": MustParseCid("bafk2bzacecwyih7nodrwsw5vyl5zk7fapklje76jpowqjr6x6br2bm55smqqy"),
|
||||
"reward": MustParseCid("bafk2bzacea6vfrcprxg2i4l5qnigf4c6pyvnjxpzfqr4pmph3elif7sfidrei"),
|
||||
"storagemarket": MustParseCid("bafk2bzaceahradb3od4ahs46x6yriwvm36iabgtohhoiolubsumto5eravzbu"),
|
||||
"storageminer": MustParseCid("bafk2bzacedekivqgvqapbepvzn6jte3xyymyg5yjuwy42xvboa6rcqnzgo74u"),
|
||||
"storagepower": MustParseCid("bafk2bzacedkmiosllqqqarmr53twspyswdvsm7givwczgo3qqsxzpad4hzjma"),
|
||||
"system": MustParseCid("bafk2bzaceagdymtxb4lxqqjgmnphbgdtdgveuuqaouswpzagj4bpbon3ptop4"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzacec556wsqldm22k2abshvvnsrawlm3bbqkwzht6ubcj76m2jsy3azi"),
|
||||
"account": MustParseCid("bafk2bzacealrkumvvuyeefrnedyh2ilgozgrdp5canubuakp723pczjdcogvw"),
|
||||
"cron": MustParseCid("bafk2bzacedcfqpqgwj4tgtccliqzwnjbxiceyc3lzylnf6owu54etiv3udjxi"),
|
||||
"datacap": MustParseCid("bafk2bzacear73heimtdso2qnw77gx6lzqmnr5f5etlggwevut5di6d7nzaoqu"),
|
||||
"eam": MustParseCid("bafk2bzacecff4dgsqjcele3zejp77weofbqkef57r2tcy4alkx7e7n3kbkmyy"),
|
||||
"ethaccount": MustParseCid("bafk2bzacec75pm3q66lsex2mqpm7fax7h6bfbkpwodf4o5gzgnrc2cdifbvfw"),
|
||||
"evm": MustParseCid("bafk2bzaceacbkauvu7ia3euoz5jfdrkw5s7mk4ga5byf3oqndxeaxyxhgnk4m"),
|
||||
"init": MustParseCid("bafk2bzacebtc7p3fq4d7m76jphagzpav2kfxfok7d56wrkek4zqyfqvtpihwm"),
|
||||
"multisig": MustParseCid("bafk2bzaceci3czx4l42u22iozsgg6zkls5wdtrztekmzy4qnybg4qlv4b3qli"),
|
||||
"paymentchannel": MustParseCid("bafk2bzacea54hgf2czdhlxvn66pyoon5cw3fwdlwx4kp4fwftv2tat4r4nnqg"),
|
||||
"placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
|
||||
"reward": MustParseCid("bafk2bzacebd7ia2qfpxob2enuazpy3yc2wpach5rq2qbm7uwgknyzqqruefmm"),
|
||||
"storagemarket": MustParseCid("bafk2bzaceam7ns7axlv3sghrwdo7kriw2hrlblim2pingllnvatqu2xfjfhgs"),
|
||||
"storageminer": MustParseCid("bafk2bzacecbfmgzg5unc3ia7yme75psji2j6uhalt5jco6niu6wcn3pdufavy"),
|
||||
"storagepower": MustParseCid("bafk2bzacedxzvoqa3a4lzajoke75q2ujhmazm4inb7robfikgtywr4sp6mgcy"),
|
||||
"system": MustParseCid("bafk2bzaceb5wpgomztoaxfv2hhgb5xtbmq4t53wev6mg4yonax5glbi4dtcoe"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzacedf2f53g4cuvt6efwlga2sbovuy3tzcc2rhjh5eaa5f2ivri25ehc"),
|
||||
},
|
||||
}, {
|
||||
Network: "hyperspace",
|
||||
Version: 10,
|
||||
ManifestCid: MustParseCid("bafy2bzacearfqpg6omcyjot2zc5yynkb4bsfkykqacmwaiwiodvhlin4j4xta"),
|
||||
Actors: map[string]cid.Cid{
|
||||
"account": MustParseCid("bafk2bzacec63ehicn6roe4hwtktiqjdpn7buw4vewix2fshvk7ruk6bg54bga"),
|
||||
"cron": MustParseCid("bafk2bzacedgz5736vxapicnbdrk5yrbgwbjizhr5hjglxwkb6sonqpoyaid4u"),
|
||||
"datacap": MustParseCid("bafk2bzacedmuhap3ephpwcvyqxry54irmw5zaz74abhmnjlwrf6ioihrzcqgu"),
|
||||
"eam": MustParseCid("bafk2bzacedx5iw3jyrdfkvgqcas244e6hqotli72uinwiy74ae7s4imax6agc"),
|
||||
"ethaccount": MustParseCid("bafk2bzacectie3kbxquentwvrlcwoqzfisfcqfgngzgyndhjgclmg7cyf6zwa"),
|
||||
"evm": MustParseCid("bafk2bzacedtbvq77pb4vd7rx2inklizjeipt7myb7tim5hms2vzzmuareekrw"),
|
||||
"init": MustParseCid("bafk2bzacebcmb4nwbhambosg2xcfhifkqnaoxsotfwekmxeq7phgqgxzzxnts"),
|
||||
"multisig": MustParseCid("bafk2bzacedw73tmdl7stykyycxmhsb3iom7notxmx24b2647g3vwmrg2brgqu"),
|
||||
"paymentchannel": MustParseCid("bafk2bzaced5frgcp6bszhis5kxtm6uko5jlgbuzyczqsj7uavovkayrbizg4s"),
|
||||
"placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
|
||||
"reward": MustParseCid("bafk2bzaceddc5c45lnbo7i3uknk5zi3qbq6k4rocfoq3n7x3qerehyevjl7ja"),
|
||||
"storagemarket": MustParseCid("bafk2bzaceafqt55lykve6ex5bw65ueuec6bjcwfmq6vbhwbgjmpt4cztldzle"),
|
||||
"storageminer": MustParseCid("bafk2bzacebongyek6ijaqzup6fe2kplq24dr3dtvweu5fmfjl236rjhyqv3gs"),
|
||||
"storagepower": MustParseCid("bafk2bzaceapgnms6ldjpewmniaqawu5sflssycjbwydqvilja66y5wm4lulwq"),
|
||||
"system": MustParseCid("bafk2bzaceaki4yktxjcaxuj4be4q2ybrjiqcqq7orgzqgmidcavn3dzxyo7ds"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzacedrd4uxho6tpksyullgb6lofudlwntjwt7sqrtdgzjoj6eu7onwnc"),
|
||||
},
|
||||
}, {
|
||||
Network: "mainnet",
|
||||
@ -268,23 +294,24 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
||||
}, {
|
||||
Network: "mainnet",
|
||||
Version: 10,
|
||||
ManifestCid: MustParseCid("bafy2bzaceduyggnyqhlr346hfw32tbobzrvhzhill33zhe7jw64pmwjci2xoc"),
|
||||
ManifestCid: MustParseCid("bafy2bzacedjq47v3yxxptl3vvtpin4optnhoe7ynxjncuhpak2ifdvff2mrfy"),
|
||||
Actors: map[string]cid.Cid{
|
||||
"account": MustParseCid("bafk2bzacedmr3wxl7qmhquageorrt3aavbzqfpm7eymxidakwuhaobu7dseqs"),
|
||||
"cron": MustParseCid("bafk2bzaceblekxapm5nnqnxmw3mk27236iyutvbhhpsc3fyde7zi7guccn7cc"),
|
||||
"datacap": MustParseCid("bafk2bzacedu4jevyvqsilq7bq4uhegbkm75muwebc5ifqpfaojwhexf2j4i6a"),
|
||||
"eam": MustParseCid("bafk2bzacedc7224twbolvdq6iwc7ybdpah2ywe3ueo33jv67ecimndinle374"),
|
||||
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"),
|
||||
"evm": MustParseCid("bafk2bzaceaggldo6wmkvp5innv4pnjv4xnpedspzofvma3dhu7vk45hh5djoq"),
|
||||
"init": MustParseCid("bafk2bzacedutlaebaczkdi4vqvt3xim24u3whleqk2r4lufjd5jnmxcosea6q"),
|
||||
"multisig": MustParseCid("bafk2bzaceatiqxjwtugpzus3s52zoggnrftxqn7kiw3obvjgkjvtd6zr3636q"),
|
||||
"paymentchannel": MustParseCid("bafk2bzacebyviac6i43gtsvmjfg6mzcp6rwgz44axidc7m432btbmvt7i2m2g"),
|
||||
"reward": MustParseCid("bafk2bzacecbcnlvk2izojpfoaksitqenhzaofn6ynxx5pegl4y45wjlouexdi"),
|
||||
"storagemarket": MustParseCid("bafk2bzacebobteeoz2jycplgtydfyltzughegz2sopn6pzy2udjfvuo77joyk"),
|
||||
"storageminer": MustParseCid("bafk2bzacecwcypas3y6u4rya7qolfwmou437xgrjxh7mnnim7bo3nhk4dscxw"),
|
||||
"storagepower": MustParseCid("bafk2bzacec62kids6rcrdmdeqhwiz3s5rs35s5gn25ilwemgmm6jqnr2rnaaq"),
|
||||
"system": MustParseCid("bafk2bzacecj3c4bjbs2xfttn7zqle7yocqh47u2s7hwuxrsn7fi5h74tcyxoc"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzacedgf7zbnlste5ukzueduemkimiit64scz7lvebztufx5jxtx6gkz2"),
|
||||
"account": MustParseCid("bafk2bzaceb7wftmnoa5zbeu6jsrzvqpjfd7kudhueve6duwxcflcaqeagqg6g"),
|
||||
"cron": MustParseCid("bafk2bzacean2xecc6kfbrueglsujjqswz5nvjstmtvdq2zc5vk4cbh6gvgxcq"),
|
||||
"datacap": MustParseCid("bafk2bzacear4esja4asfsdeqto6o5cjn5dbgxmzvu2uel36tzdp2s26fkte4y"),
|
||||
"eam": MustParseCid("bafk2bzacectduzxzk23xffgohmsmq4gisl4etaguq2xe6h52y7aiaaibmi2pg"),
|
||||
"ethaccount": MustParseCid("bafk2bzacecqoxzy2p3i46ncuvw6wzlesaw5iobqpp7nmjtkbxyiwblg4frzmg"),
|
||||
"evm": MustParseCid("bafk2bzacecgz6klga2lwjp3d3iyzkzm4td5aefeaymmn3rmixgg7a4vwoewcu"),
|
||||
"init": MustParseCid("bafk2bzacebzrlucqk23kkjv26srpzjgztx7qjm23suqbyzu2qdto5jbpifm7y"),
|
||||
"multisig": MustParseCid("bafk2bzacedls4tgmkfkasgcsfrtnkjoi6yoze5yq4cafqzbjvbty5gfeut4n4"),
|
||||
"paymentchannel": MustParseCid("bafk2bzaceazuokt65n3hqjgmwmgoi6gpcvete2b46nlecnynjkgrzp4wnl4ii"),
|
||||
"placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
|
||||
"reward": MustParseCid("bafk2bzacecqjpnbxravwqb7liwxowb5bdml4x2qboo5vqxk7slprq3eo4ujp2"),
|
||||
"storagemarket": MustParseCid("bafk2bzacecuedinzm256nup2pbsdrnxerfk33hqxhakupb3c26fwk576ehgiw"),
|
||||
"storageminer": MustParseCid("bafk2bzaceb4c7iqlmk4lgnkccpdvzdv6kbwqz2leyluuehh2ino2m6e5cd7d6"),
|
||||
"storagepower": MustParseCid("bafk2bzacedkwcuzvlx43nbwdwms5smerdaeja45rh7d646k4nc4s5toyryuxi"),
|
||||
"system": MustParseCid("bafk2bzacedexhpixywvxk37jyp3sehcqmomyq4kpxu3wjhrehawyjhv6grav2"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzacebsnm343frbrfted3vbia4to7iiav4qm3tvpkcbsgkd5fynop3q7s"),
|
||||
},
|
||||
}, {
|
||||
Network: "testing",
|
||||
@ -324,23 +351,24 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
||||
}, {
|
||||
Network: "testing",
|
||||
Version: 10,
|
||||
ManifestCid: MustParseCid("bafy2bzacearlgbespxi2zdrybtp2rrbwscmtbyou5qa2egbdvcz6v2yjjqvjo"),
|
||||
ManifestCid: MustParseCid("bafy2bzacececfnvx4hay5b6yhtkxdqgkauupeqpwnlgainug6blp2isihwtww"),
|
||||
Actors: map[string]cid.Cid{
|
||||
"account": MustParseCid("bafk2bzaceba6me5ipkcijuhyypnzjydhv3ebi2ctailar7mtzlk4vk3rbxfee"),
|
||||
"cron": MustParseCid("bafk2bzacea6k2mai2xnakygqvbigivfrvv5q7d34qrzjv2crkqtwbjxnxmkbe"),
|
||||
"datacap": MustParseCid("bafk2bzaceah4oxcgck6bcfkzctm2klpvmltyidq7uxnlkcap6ypi3lnkcvrqk"),
|
||||
"eam": MustParseCid("bafk2bzacedjtkvocrnkrot2oztsfrxtpwl32wwbmbkrjfbbm4xipwzrhhxn5c"),
|
||||
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"),
|
||||
"evm": MustParseCid("bafk2bzaced6vhabkr2ojpjzsybrq5yvksjzpjk6yei6fwobkwwydlj5f473pw"),
|
||||
"init": MustParseCid("bafk2bzaceaib3o5e7wop7kwjirgpferqarmngrgjkur2yhdnwplctidpxsgme"),
|
||||
"multisig": MustParseCid("bafk2bzaced4z3awacxumq6yr33a3adu2legb7colahgvqpmigs3fvvjxs3byc"),
|
||||
"paymentchannel": MustParseCid("bafk2bzaceb6mfi24mpzt7qlkratj2tdtqo7aia67zcztuslrxcjaycz6fnai6"),
|
||||
"reward": MustParseCid("bafk2bzacebngh5kwtem4ncarpjtxhs4rwyoficttkgxlsjtiz5ucdi4p3czoc"),
|
||||
"storagemarket": MustParseCid("bafk2bzacecnsibyil62jfq2gbkoe6c2epehfcrxzjmqjnwz7kxab2hkbu3lks"),
|
||||
"storageminer": MustParseCid("bafk2bzacedzw4vkrt3sdkhagpvn62pknyyjkcrzewncvtvae5qgwe6ulzx4a4"),
|
||||
"storagepower": MustParseCid("bafk2bzacedxgadibot6nzvripqt3z5shvjsoscupinejnsvswq4cbeskblwyy"),
|
||||
"system": MustParseCid("bafk2bzacedm24avrmp5o5odhpad43qeglooflygwh4ah7qnzbij2h4c3v6cge"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzaceapq3j6ww3ofytwq3pz3obumaqsyg3wrm6tksdh7op23a72co3rya"),
|
||||
"account": MustParseCid("bafk2bzaceb56iceglbwg3s2skdjj5vhak7j6srlaxvd7v6hzvxpccwsrvfaxi"),
|
||||
"cron": MustParseCid("bafk2bzacearjb3buxy4jwhcn4jeqbof3dinsh52zyj74djkfghmjdoxbsvjkq"),
|
||||
"datacap": MustParseCid("bafk2bzacec2dghsnwhyhquwkbsfcct53pgglxzgmw7j66y3keniklbiq4q7ti"),
|
||||
"eam": MustParseCid("bafk2bzacedojoymbgz275lzvtlpaf2thoydz7fb274mhvadbpk2thbgpye72s"),
|
||||
"ethaccount": MustParseCid("bafk2bzaceddhvqqkwc4p7exdgv2bwefkk3lnq2rw6chvar7hdeowahtjdmznw"),
|
||||
"evm": MustParseCid("bafk2bzacecgzk3ompisq5n7oualijioce6nhsm6zwil7p5p57nojuyrdckti2"),
|
||||
"init": MustParseCid("bafk2bzaceacdto7l5qp65ukclc3qqlfpv3tdio7u5lxufg2uc3hrx5hpqt2x2"),
|
||||
"multisig": MustParseCid("bafk2bzacebw6ujt54gyhxvo5jmimg3z54crmfzbbcr677ljqmmb2ejh6srlsm"),
|
||||
"paymentchannel": MustParseCid("bafk2bzacebfht4drwm5aagcx4kvuiwclldd6rnosce42474u4asnurjqyxhna"),
|
||||
"placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
|
||||
"reward": MustParseCid("bafk2bzacedqmiebckz7xqs7f7gcj67wzzpko2q3jhom6rwtopogv7iz5bnwlu"),
|
||||
"storagemarket": MustParseCid("bafk2bzaceam3n2xjbvkyyifw7jvkc4z4lxvblnbmx4ruzr5lpesgmpuhbmb2w"),
|
||||
"storageminer": MustParseCid("bafk2bzacebcbyuzniiqksk47v7zyfc56noblbsmlqblv3n6s7l5un3heigdwk"),
|
||||
"storagepower": MustParseCid("bafk2bzacechzbqmunxv6o2zgp4uicswapmgexc3uejco2n2r7cirbijrbgewc"),
|
||||
"system": MustParseCid("bafk2bzaceb6obdybgoyjvdfxvxg5uxhrpnoixtbof663dllo2eelcuvsfycew"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzacedlogwaofqaqou4pckoatwei2ulbz3ucjmbsm3lfwuw3tr7g5opjc"),
|
||||
},
|
||||
}, {
|
||||
Network: "testing-fake-proofs",
|
||||
@ -380,22 +408,23 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
|
||||
}, {
|
||||
Network: "testing-fake-proofs",
|
||||
Version: 10,
|
||||
ManifestCid: MustParseCid("bafy2bzacea4irr2oxhclwt4mvtrevbzb7mbqddcebjz7bkqjq6eoflpfhencc"),
|
||||
ManifestCid: MustParseCid("bafy2bzacec4yawvg2rbdvzlez4lyf4e7ysjfjdrg5mpclvvwxt7texyeeletg"),
|
||||
Actors: map[string]cid.Cid{
|
||||
"account": MustParseCid("bafk2bzaceba6me5ipkcijuhyypnzjydhv3ebi2ctailar7mtzlk4vk3rbxfee"),
|
||||
"cron": MustParseCid("bafk2bzacea6k2mai2xnakygqvbigivfrvv5q7d34qrzjv2crkqtwbjxnxmkbe"),
|
||||
"datacap": MustParseCid("bafk2bzaceah4oxcgck6bcfkzctm2klpvmltyidq7uxnlkcap6ypi3lnkcvrqk"),
|
||||
"eam": MustParseCid("bafk2bzacedjtkvocrnkrot2oztsfrxtpwl32wwbmbkrjfbbm4xipwzrhhxn5c"),
|
||||
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"),
|
||||
"evm": MustParseCid("bafk2bzaced6vhabkr2ojpjzsybrq5yvksjzpjk6yei6fwobkwwydlj5f473pw"),
|
||||
"init": MustParseCid("bafk2bzaceaib3o5e7wop7kwjirgpferqarmngrgjkur2yhdnwplctidpxsgme"),
|
||||
"multisig": MustParseCid("bafk2bzaced4z3awacxumq6yr33a3adu2legb7colahgvqpmigs3fvvjxs3byc"),
|
||||
"paymentchannel": MustParseCid("bafk2bzaceb6mfi24mpzt7qlkratj2tdtqo7aia67zcztuslrxcjaycz6fnai6"),
|
||||
"reward": MustParseCid("bafk2bzacebngh5kwtem4ncarpjtxhs4rwyoficttkgxlsjtiz5ucdi4p3czoc"),
|
||||
"storagemarket": MustParseCid("bafk2bzacecnsibyil62jfq2gbkoe6c2epehfcrxzjmqjnwz7kxab2hkbu3lks"),
|
||||
"storageminer": MustParseCid("bafk2bzaceb4grddnw54gczgcdak5a2gqvwed66mhibbug6qu4jy35bf45jltg"),
|
||||
"storagepower": MustParseCid("bafk2bzacedp2dnbk4bg3hhaeztre4q3jv7eqs267rlafszpggb2njjn3x5eru"),
|
||||
"system": MustParseCid("bafk2bzacedm24avrmp5o5odhpad43qeglooflygwh4ah7qnzbij2h4c3v6cge"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzaceapq3j6ww3ofytwq3pz3obumaqsyg3wrm6tksdh7op23a72co3rya"),
|
||||
"account": MustParseCid("bafk2bzaceb56iceglbwg3s2skdjj5vhak7j6srlaxvd7v6hzvxpccwsrvfaxi"),
|
||||
"cron": MustParseCid("bafk2bzacearjb3buxy4jwhcn4jeqbof3dinsh52zyj74djkfghmjdoxbsvjkq"),
|
||||
"datacap": MustParseCid("bafk2bzacec2dghsnwhyhquwkbsfcct53pgglxzgmw7j66y3keniklbiq4q7ti"),
|
||||
"eam": MustParseCid("bafk2bzacedojoymbgz275lzvtlpaf2thoydz7fb274mhvadbpk2thbgpye72s"),
|
||||
"ethaccount": MustParseCid("bafk2bzaceddhvqqkwc4p7exdgv2bwefkk3lnq2rw6chvar7hdeowahtjdmznw"),
|
||||
"evm": MustParseCid("bafk2bzacecgzk3ompisq5n7oualijioce6nhsm6zwil7p5p57nojuyrdckti2"),
|
||||
"init": MustParseCid("bafk2bzaceacdto7l5qp65ukclc3qqlfpv3tdio7u5lxufg2uc3hrx5hpqt2x2"),
|
||||
"multisig": MustParseCid("bafk2bzacebw6ujt54gyhxvo5jmimg3z54crmfzbbcr677ljqmmb2ejh6srlsm"),
|
||||
"paymentchannel": MustParseCid("bafk2bzacebfht4drwm5aagcx4kvuiwclldd6rnosce42474u4asnurjqyxhna"),
|
||||
"placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
|
||||
"reward": MustParseCid("bafk2bzacedqmiebckz7xqs7f7gcj67wzzpko2q3jhom6rwtopogv7iz5bnwlu"),
|
||||
"storagemarket": MustParseCid("bafk2bzaceam3n2xjbvkyyifw7jvkc4z4lxvblnbmx4ruzr5lpesgmpuhbmb2w"),
|
||||
"storageminer": MustParseCid("bafk2bzaceataoi4vlifq2roanrfjt2f2cql2dq4osjs5i3nt4v76462mtrcm2"),
|
||||
"storagepower": MustParseCid("bafk2bzacede4nq6cbym2z7p5vc2gwbxhnd34qxtd7sy4rmwula3kk6yhbqtve"),
|
||||
"system": MustParseCid("bafk2bzaceb6obdybgoyjvdfxvxg5uxhrpnoixtbof663dllo2eelcuvsfycew"),
|
||||
"verifiedregistry": MustParseCid("bafk2bzacedlogwaofqaqou4pckoatwei2ulbz3ucjmbsm3lfwuw3tr7g5opjc"),
|
||||
},
|
||||
}}
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -21,6 +21,7 @@ const GenesisFile = ""
|
||||
|
||||
var NetworkBundle = "devnet"
|
||||
var BundleOverrides map[actorstypes.Version]string
|
||||
var ActorDebugging = true
|
||||
|
||||
const GenesisNetworkVersion = network.Version18
|
||||
|
||||
@ -58,6 +59,8 @@ var UpgradeSkyrHeight = abi.ChainEpoch(-19)
|
||||
|
||||
var UpgradeSharkHeight = abi.ChainEpoch(-20)
|
||||
|
||||
var UpgradeHyggeHeight = abi.ChainEpoch(-21)
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
}
|
||||
@ -110,6 +113,7 @@ func init() {
|
||||
UpgradeOhSnapHeight = getUpgradeHeight("LOTUS_OHSNAP_HEIGHT", UpgradeOhSnapHeight)
|
||||
UpgradeSkyrHeight = getUpgradeHeight("LOTUS_SKYR_HEIGHT", UpgradeSkyrHeight)
|
||||
UpgradeSharkHeight = getUpgradeHeight("LOTUS_SHARK_HEIGHT", UpgradeSharkHeight)
|
||||
UpgradeHyggeHeight = getUpgradeHeight("LOTUS_HYGGE_HEIGHT", UpgradeHyggeHeight)
|
||||
|
||||
BuildType |= Build2k
|
||||
|
||||
@ -130,4 +134,8 @@ const InteractivePoRepConfidence = 6
|
||||
|
||||
const BootstrapPeerThreshold = 1
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 31415926
|
||||
|
||||
var WhitelistedBlock = cid.Undef
|
||||
|
@ -23,6 +23,7 @@ const GenesisNetworkVersion = network.Version16
|
||||
|
||||
var NetworkBundle = "butterflynet"
|
||||
var BundleOverrides map[actorstypes.Version]string
|
||||
var ActorDebugging = false
|
||||
|
||||
const BootstrappersFile = "butterflynet.pi"
|
||||
const GenesisFile = "butterflynet.car"
|
||||
@ -49,7 +50,8 @@ const UpgradeHyperdriveHeight = -16
|
||||
const UpgradeChocolateHeight = -17
|
||||
const UpgradeOhSnapHeight = -18
|
||||
const UpgradeSkyrHeight = -19
|
||||
const UpgradeSharkHeight = abi.ChainEpoch(600)
|
||||
const UpgradeSharkHeight = abi.ChainEpoch(-20)
|
||||
const UpgradeHyggeHeight = abi.ChainEpoch(600)
|
||||
|
||||
var SupportedProofTypes = []abi.RegisteredSealProof{
|
||||
abi.RegisteredSealProof_StackedDrg512MiBV1,
|
||||
@ -80,4 +82,8 @@ const PropagationDelaySecs = uint64(6)
|
||||
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
|
||||
const BootstrapPeerThreshold = 2
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 3141592
|
||||
|
||||
var WhitelistedBlock = cid.Undef
|
||||
|
@ -4,6 +4,7 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"math"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
@ -26,6 +27,7 @@ const GenesisNetworkVersion = network.Version0
|
||||
|
||||
var NetworkBundle = "calibrationnet"
|
||||
var BundleOverrides map[actorstypes.Version]string
|
||||
var ActorDebugging = false
|
||||
|
||||
const BootstrappersFile = "calibnet.pi"
|
||||
const GenesisFile = "calibnet.car"
|
||||
@ -69,6 +71,8 @@ const UpgradeSkyrHeight = 510
|
||||
|
||||
const UpgradeSharkHeight = 16800 // 6 days after genesis
|
||||
|
||||
const UpgradeHyggeHeight = math.MaxInt64
|
||||
|
||||
var SupportedProofTypes = []abi.RegisteredSealProof{
|
||||
abi.RegisteredSealProof_StackedDrg32GiBV1,
|
||||
abi.RegisteredSealProof_StackedDrg64GiBV1,
|
||||
@ -113,4 +117,8 @@ var PropagationDelaySecs = uint64(10)
|
||||
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
|
||||
const BootstrapPeerThreshold = 4
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 314159
|
||||
|
||||
var WhitelistedBlock = cid.Undef
|
||||
|
98
build/params_hyperspace.go
Normal file
98
build/params_hyperspace.go
Normal file
@ -0,0 +1,98 @@
|
||||
//go:build hyperspace
|
||||
// +build hyperspace
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
actorstypes "github.com/filecoin-project/go-state-types/actors"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
)
|
||||
|
||||
var NetworkBundle = "hyperspace"
|
||||
var BundleOverrides map[actorstypes.Version]string
|
||||
var ActorDebugging = true
|
||||
|
||||
const BootstrappersFile = "hyperspace.pi"
|
||||
const GenesisFile = "hyperspace.car"
|
||||
|
||||
const GenesisNetworkVersion = network.Version18
|
||||
|
||||
var NetworkBundle = "hyperspacenet"
|
||||
var BundleOverrides map[actorstypes.Version]string
|
||||
var ActorDebugging = false
|
||||
|
||||
var UpgradeBreezeHeight = abi.ChainEpoch(-1)
|
||||
|
||||
const BreezeGasTampingDuration = 120
|
||||
|
||||
var UpgradeSmokeHeight = abi.ChainEpoch(-1)
|
||||
var UpgradeIgnitionHeight = abi.ChainEpoch(-2)
|
||||
var UpgradeRefuelHeight = abi.ChainEpoch(-3)
|
||||
var UpgradeTapeHeight = abi.ChainEpoch(-4)
|
||||
|
||||
var UpgradeAssemblyHeight = abi.ChainEpoch(-5)
|
||||
var UpgradeLiftoffHeight = abi.ChainEpoch(-6)
|
||||
|
||||
var UpgradeKumquatHeight = abi.ChainEpoch(-7)
|
||||
var UpgradeCalicoHeight = abi.ChainEpoch(-9)
|
||||
var UpgradePersianHeight = abi.ChainEpoch(-10)
|
||||
var UpgradeOrangeHeight = abi.ChainEpoch(-11)
|
||||
var UpgradeClausHeight = abi.ChainEpoch(-12)
|
||||
|
||||
var UpgradeTrustHeight = abi.ChainEpoch(-13)
|
||||
|
||||
var UpgradeNorwegianHeight = abi.ChainEpoch(-14)
|
||||
|
||||
var UpgradeTurboHeight = abi.ChainEpoch(-15)
|
||||
|
||||
var UpgradeHyperdriveHeight = abi.ChainEpoch(-16)
|
||||
var UpgradeChocolateHeight = abi.ChainEpoch(-17)
|
||||
var UpgradeOhSnapHeight = abi.ChainEpoch(-18)
|
||||
var UpgradeSkyrHeight = abi.ChainEpoch(-19)
|
||||
var UpgradeSharkHeight = abi.ChainEpoch(-20)
|
||||
var UpgradeHyggeHeight = abi.ChainEpoch(-21)
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
}
|
||||
|
||||
var SupportedProofTypes = []abi.RegisteredSealProof{
|
||||
abi.RegisteredSealProof_StackedDrg512MiBV1,
|
||||
abi.RegisteredSealProof_StackedDrg32GiBV1,
|
||||
abi.RegisteredSealProof_StackedDrg64GiBV1,
|
||||
}
|
||||
var ConsensusMinerMinPower = abi.NewStoragePower(16 << 30)
|
||||
var MinVerifiedDealSize = abi.NewStoragePower(1 << 20)
|
||||
var PreCommitChallengeDelay = abi.ChainEpoch(10)
|
||||
|
||||
func init() {
|
||||
policy.SetSupportedProofTypes(SupportedProofTypes...)
|
||||
policy.SetConsensusMinerMinPower(ConsensusMinerMinPower)
|
||||
policy.SetMinVerifiedDealSize(MinVerifiedDealSize)
|
||||
policy.SetPreCommitChallengeDelay(PreCommitChallengeDelay)
|
||||
|
||||
BuildType = BuildHyperspacenet
|
||||
SetAddressNetwork(address.Testnet)
|
||||
Devnet = true
|
||||
|
||||
}
|
||||
|
||||
const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds)
|
||||
|
||||
const PropagationDelaySecs = uint64(6)
|
||||
|
||||
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
|
||||
const BootstrapPeerThreshold = 2
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 3141
|
||||
|
||||
var WhitelistedBlock = cid.Undef
|
@ -20,6 +20,7 @@ import (
|
||||
|
||||
var NetworkBundle = "caterpillarnet"
|
||||
var BundleOverrides map[actorstypes.Version]string
|
||||
var ActorDebugging = false
|
||||
|
||||
const BootstrappersFile = "interopnet.pi"
|
||||
const GenesisFile = "interopnet.car"
|
||||
@ -49,7 +50,9 @@ var UpgradeChocolateHeight = abi.ChainEpoch(-17)
|
||||
var UpgradeOhSnapHeight = abi.ChainEpoch(-18)
|
||||
var UpgradeSkyrHeight = abi.ChainEpoch(-19)
|
||||
|
||||
const UpgradeSharkHeight = abi.ChainEpoch(99999999999999)
|
||||
const UpgradeSharkHeight = abi.ChainEpoch(-20)
|
||||
|
||||
const UpgradeHyggeHeight = abi.ChainEpoch(99999999999999)
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
@ -104,6 +107,7 @@ func init() {
|
||||
UpgradeOhSnapHeight = getUpgradeHeight("LOTUS_OHSNAP_HEIGHT", UpgradeOhSnapHeight)
|
||||
UpgradeSkyrHeight = getUpgradeHeight("LOTUS_SKYR_HEIGHT", UpgradeSkyrHeight)
|
||||
UpgradeSharkHeight = getUpgradeHeight("LOTUS_SHARK_HEIGHT", UpgradeSharkHeight)
|
||||
UpgradeHyggeHeight = getUpgradeHeight("LOTUS_HYGGE_HEIGHT", UpgradeHyggeHeight)
|
||||
|
||||
BuildType |= BuildInteropnet
|
||||
SetAddressNetwork(address.Testnet)
|
||||
@ -118,4 +122,9 @@ const PropagationDelaySecs = uint64(6)
|
||||
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
|
||||
const BootstrapPeerThreshold = 2
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
// TODO same as butterfly for now, as we didn't submit an assignment for interopnet.
|
||||
const Eip155ChainId = 3141592
|
||||
|
||||
var WhitelistedBlock = cid.Undef
|
||||
|
@ -1,5 +1,5 @@
|
||||
//go:build !debug && !2k && !testground && !calibnet && !butterflynet && !interopnet
|
||||
// +build !debug,!2k,!testground,!calibnet,!butterflynet,!interopnet
|
||||
//go:build !debug && !2k && !testground && !calibnet && !butterflynet && !interopnet && !wallabynet && !hyperspacenet
|
||||
// +build !debug,!2k,!testground,!calibnet,!butterflynet,!interopnet,!wallabynet,!hyperspacenet
|
||||
|
||||
package build
|
||||
|
||||
@ -25,6 +25,9 @@ var NetworkBundle = "mainnet"
|
||||
// NOTE: DO NOT change this unless you REALLY know what you're doing. This is consensus critical.
|
||||
var BundleOverrides map[actorstypes.Version]string
|
||||
|
||||
// NOTE: DO NOT change this unless you REALLY know what you're doing. This is consensus critical.
|
||||
const ActorDebugging = false
|
||||
|
||||
const GenesisNetworkVersion = network.Version0
|
||||
|
||||
const BootstrappersFile = "mainnet.pi"
|
||||
@ -56,6 +59,7 @@ const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 60)
|
||||
const UpgradeOrangeHeight = 336458
|
||||
|
||||
// 2020-12-22T02:00:00Z
|
||||
// var because of wdpost_test.go
|
||||
var UpgradeClausHeight = abi.ChainEpoch(343200)
|
||||
|
||||
// 2021-03-04T00:00:30Z
|
||||
@ -80,7 +84,10 @@ const UpgradeOhSnapHeight = 1594680
|
||||
const UpgradeSkyrHeight = 1960320
|
||||
|
||||
// 2022-11-30T14:00:00Z
|
||||
var UpgradeSharkHeight = abi.ChainEpoch(2383680)
|
||||
const UpgradeSharkHeight = 2383680
|
||||
|
||||
// ??????????????
|
||||
var UpgradeHyggeHeight = abi.ChainEpoch(math.MaxInt64)
|
||||
|
||||
var SupportedProofTypes = []abi.RegisteredSealProof{
|
||||
abi.RegisteredSealProof_StackedDrg32GiBV1,
|
||||
@ -95,8 +102,8 @@ func init() {
|
||||
SetAddressNetwork(address.Mainnet)
|
||||
}
|
||||
|
||||
if os.Getenv("LOTUS_DISABLE_SHARK") == "1" {
|
||||
UpgradeSharkHeight = math.MaxInt64
|
||||
if os.Getenv("LOTUS_DISABLE_HYGGE") == "1" {
|
||||
UpgradeHyggeHeight = math.MaxInt64
|
||||
}
|
||||
|
||||
// NOTE: DO NOT change this unless you REALLY know what you're doing. This is not consensus critical, however,
|
||||
@ -124,5 +131,9 @@ const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds)
|
||||
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
|
||||
const BootstrapPeerThreshold = 4
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 314
|
||||
|
||||
// we skip checks on message validity in this block to sidestep the zero-bls signature
|
||||
var WhitelistedBlock = MustParseCid("bafy2bzaceapyg2uyzk7vueh3xccxkuwbz3nxewjyguoxvhx77malc2lzn2ybi")
|
||||
|
@ -108,6 +108,7 @@ var (
|
||||
UpgradeOhSnapHeight abi.ChainEpoch = -17
|
||||
UpgradeSkyrHeight abi.ChainEpoch = -18
|
||||
UpgradeSharkHeight abi.ChainEpoch = -19
|
||||
UpgradeHyggeHeight abi.ChainEpoch = -20
|
||||
|
||||
DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
@ -116,6 +117,7 @@ var (
|
||||
GenesisNetworkVersion = network.Version0
|
||||
NetworkBundle = "devnet"
|
||||
BundleOverrides map[actorstypes.Version]string
|
||||
ActorDebugging = true
|
||||
|
||||
NewestNetworkVersion = network.Version16
|
||||
ActorUpgradeNetworkVersion = network.Version16
|
||||
@ -129,3 +131,7 @@ var (
|
||||
)
|
||||
|
||||
const BootstrapPeerThreshold = 1
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 31415926
|
||||
|
94
build/params_wallaby.go
Normal file
94
build/params_wallaby.go
Normal file
@ -0,0 +1,94 @@
|
||||
//go:build wallabynet
|
||||
// +build wallabynet
|
||||
|
||||
package build
|
||||
|
||||
import (
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
actorstypes "github.com/filecoin-project/go-state-types/actors"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
builtin2 "github.com/filecoin-project/specs-actors/v2/actors/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors/policy"
|
||||
)
|
||||
|
||||
var NetworkBundle = "wallaby"
|
||||
var BundleOverrides map[actorstypes.Version]string
|
||||
var ActorDebugging = true
|
||||
|
||||
const BootstrappersFile = "wallabynet.pi"
|
||||
const GenesisFile = "wallabynet.car"
|
||||
|
||||
const GenesisNetworkVersion = network.Version18
|
||||
|
||||
var UpgradeBreezeHeight = abi.ChainEpoch(-1)
|
||||
|
||||
const BreezeGasTampingDuration = 120
|
||||
|
||||
var UpgradeSmokeHeight = abi.ChainEpoch(-1)
|
||||
var UpgradeIgnitionHeight = abi.ChainEpoch(-2)
|
||||
var UpgradeRefuelHeight = abi.ChainEpoch(-3)
|
||||
var UpgradeTapeHeight = abi.ChainEpoch(-4)
|
||||
|
||||
var UpgradeAssemblyHeight = abi.ChainEpoch(-5)
|
||||
var UpgradeLiftoffHeight = abi.ChainEpoch(-6)
|
||||
|
||||
var UpgradeKumquatHeight = abi.ChainEpoch(-7)
|
||||
var UpgradeCalicoHeight = abi.ChainEpoch(-9)
|
||||
var UpgradePersianHeight = abi.ChainEpoch(-10)
|
||||
var UpgradeOrangeHeight = abi.ChainEpoch(-11)
|
||||
var UpgradeClausHeight = abi.ChainEpoch(-12)
|
||||
|
||||
var UpgradeTrustHeight = abi.ChainEpoch(-13)
|
||||
|
||||
var UpgradeNorwegianHeight = abi.ChainEpoch(-14)
|
||||
|
||||
var UpgradeTurboHeight = abi.ChainEpoch(-15)
|
||||
|
||||
var UpgradeHyperdriveHeight = abi.ChainEpoch(-16)
|
||||
var UpgradeChocolateHeight = abi.ChainEpoch(-17)
|
||||
var UpgradeOhSnapHeight = abi.ChainEpoch(-18)
|
||||
var UpgradeSkyrHeight = abi.ChainEpoch(-19)
|
||||
var UpgradeSharkHeight = abi.ChainEpoch(-20)
|
||||
var UpgradeHyggeHeight = abi.ChainEpoch(-21)
|
||||
|
||||
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
|
||||
0: DrandMainnet,
|
||||
}
|
||||
|
||||
var SupportedProofTypes = []abi.RegisteredSealProof{
|
||||
abi.RegisteredSealProof_StackedDrg512MiBV1,
|
||||
abi.RegisteredSealProof_StackedDrg32GiBV1,
|
||||
abi.RegisteredSealProof_StackedDrg64GiBV1,
|
||||
}
|
||||
var ConsensusMinerMinPower = abi.NewStoragePower(16 << 30)
|
||||
var MinVerifiedDealSize = abi.NewStoragePower(1 << 20)
|
||||
var PreCommitChallengeDelay = abi.ChainEpoch(10)
|
||||
|
||||
func init() {
|
||||
policy.SetSupportedProofTypes(SupportedProofTypes...)
|
||||
policy.SetConsensusMinerMinPower(ConsensusMinerMinPower)
|
||||
policy.SetMinVerifiedDealSize(MinVerifiedDealSize)
|
||||
policy.SetPreCommitChallengeDelay(PreCommitChallengeDelay)
|
||||
|
||||
BuildType = BuildWallabynet
|
||||
SetAddressNetwork(address.Testnet)
|
||||
Devnet = true
|
||||
|
||||
}
|
||||
|
||||
const BlockDelaySecs = uint64(builtin2.EpochDurationSeconds)
|
||||
|
||||
const PropagationDelaySecs = uint64(6)
|
||||
|
||||
// BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
|
||||
const BootstrapPeerThreshold = 2
|
||||
|
||||
// ChainId defines the chain ID used in the Ethereum JSON-RPC endpoint.
|
||||
// As per https://github.com/ethereum-lists/chains
|
||||
const Eip155ChainId = 31415
|
||||
|
||||
var WhitelistedBlock = cid.Undef
|
@ -13,6 +13,8 @@ const (
|
||||
BuildCalibnet = 0x4
|
||||
BuildInteropnet = 0x5
|
||||
BuildButterflynet = 0x7
|
||||
BuildWallabynet = 0x8
|
||||
BuildHyperspacenet = 0x9
|
||||
)
|
||||
|
||||
func BuildTypeString() string {
|
||||
@ -31,6 +33,10 @@ func BuildTypeString() string {
|
||||
return "+interopnet"
|
||||
case BuildButterflynet:
|
||||
return "+butterflynet"
|
||||
case BuildWallabynet:
|
||||
return "+wallabynet"
|
||||
case BuildHyperspacenet:
|
||||
return "+hyperspacenet"
|
||||
default:
|
||||
return "+huh?"
|
||||
}
|
||||
|
@ -274,6 +274,33 @@ func IsPaymentChannelActor(c cid.Cid) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func IsPlaceholderActor(c cid.Cid) bool {
|
||||
name, _, ok := actors.GetActorMetaByCode(c)
|
||||
if ok {
|
||||
return name == manifest.PlaceholderKey
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func IsEvmActor(c cid.Cid) bool {
|
||||
name, _, ok := actors.GetActorMetaByCode(c)
|
||||
if ok {
|
||||
return name == manifest.EvmKey
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func IsEthAccountActor(c cid.Cid) bool {
|
||||
name, _, ok := actors.GetActorMetaByCode(c)
|
||||
if ok {
|
||||
return name == manifest.EthAccountKey
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func makeAddress(addr string) address.Address {
|
||||
ret, err := address.NewFromString(addr)
|
||||
if err != nil {
|
||||
|
@ -153,6 +153,33 @@ func IsPaymentChannelActor(c cid.Cid) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func IsPlaceholderActor(c cid.Cid) bool {
|
||||
name, _, ok := actors.GetActorMetaByCode(c)
|
||||
if ok {
|
||||
return name == manifest.PlaceholderKey
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func IsEvmActor(c cid.Cid) bool {
|
||||
name, _, ok := actors.GetActorMetaByCode(c)
|
||||
if ok {
|
||||
return name == manifest.EvmKey
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func IsEthAccountActor(c cid.Cid) bool {
|
||||
name, _, ok := actors.GetActorMetaByCode(c)
|
||||
if ok {
|
||||
return name == manifest.EthAccountKey
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func makeAddress(addr string) address.Address {
|
||||
ret, err := address.NewFromString(addr)
|
||||
if err != nil {
|
||||
|
@ -13,11 +13,15 @@ import (
|
||||
account10 "github.com/filecoin-project/go-state-types/builtin/v10/account"
|
||||
cron10 "github.com/filecoin-project/go-state-types/builtin/v10/cron"
|
||||
datacap10 "github.com/filecoin-project/go-state-types/builtin/v10/datacap"
|
||||
eam10 "github.com/filecoin-project/go-state-types/builtin/v10/eam"
|
||||
ethaccount10 "github.com/filecoin-project/go-state-types/builtin/v10/ethaccount"
|
||||
evm10 "github.com/filecoin-project/go-state-types/builtin/v10/evm"
|
||||
_init10 "github.com/filecoin-project/go-state-types/builtin/v10/init"
|
||||
market10 "github.com/filecoin-project/go-state-types/builtin/v10/market"
|
||||
miner10 "github.com/filecoin-project/go-state-types/builtin/v10/miner"
|
||||
multisig10 "github.com/filecoin-project/go-state-types/builtin/v10/multisig"
|
||||
paych10 "github.com/filecoin-project/go-state-types/builtin/v10/paych"
|
||||
placeholder10 "github.com/filecoin-project/go-state-types/builtin/v10/placeholder"
|
||||
power10 "github.com/filecoin-project/go-state-types/builtin/v10/power"
|
||||
reward10 "github.com/filecoin-project/go-state-types/builtin/v10/reward"
|
||||
system10 "github.com/filecoin-project/go-state-types/builtin/v10/system"
|
||||
@ -265,6 +269,7 @@ func MakeRegistry(av actorstypes.Version) []RegistryEntry {
|
||||
methods: datacap9.Methods,
|
||||
state: new(datacap9.State),
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -343,6 +348,32 @@ func MakeRegistry(av actorstypes.Version) []RegistryEntry {
|
||||
methods: datacap10.Methods,
|
||||
state: new(datacap10.State),
|
||||
})
|
||||
|
||||
case manifest.EvmKey:
|
||||
registry = append(registry, RegistryEntry{
|
||||
code: codeID,
|
||||
methods: evm10.Methods,
|
||||
state: new(evm10.State),
|
||||
})
|
||||
case manifest.EamKey:
|
||||
registry = append(registry, RegistryEntry{
|
||||
code: codeID,
|
||||
methods: eam10.Methods,
|
||||
state: nil,
|
||||
})
|
||||
case manifest.PlaceholderKey:
|
||||
registry = append(registry, RegistryEntry{
|
||||
code: codeID,
|
||||
methods: placeholder10.Methods,
|
||||
state: nil,
|
||||
})
|
||||
case manifest.EthAccountKey:
|
||||
registry = append(registry, RegistryEntry{
|
||||
code: codeID,
|
||||
methods: ethaccount10.Methods,
|
||||
state: nil,
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,12 @@ import (
|
||||
{{if (ge . 9)}}
|
||||
datacap{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/datacap"
|
||||
{{end}}
|
||||
{{if (ge . 10)}}
|
||||
evm{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/evm"
|
||||
eam{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/eam"
|
||||
placeholder{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/placeholder"
|
||||
ethaccount{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/ethaccount"
|
||||
{{end}}
|
||||
{{end}}
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
rtt "github.com/filecoin-project/go-state-types/rt"
|
||||
@ -174,6 +180,32 @@ func MakeRegistry(av actorstypes.Version) []RegistryEntry {
|
||||
methods: datacap{{.}}.Methods,
|
||||
state: new(datacap{{.}}.State),
|
||||
}){{end}}
|
||||
{{if (ge . 10)}}
|
||||
case manifest.EvmKey:
|
||||
registry = append(registry, RegistryEntry{
|
||||
code: codeID,
|
||||
methods: evm{{.}}.Methods,
|
||||
state: new(evm{{.}}.State),
|
||||
})
|
||||
case manifest.EamKey:
|
||||
registry = append(registry, RegistryEntry{
|
||||
code: codeID,
|
||||
methods: eam{{.}}.Methods,
|
||||
state: nil,
|
||||
})
|
||||
case manifest.PlaceholderKey:
|
||||
registry = append(registry, RegistryEntry{
|
||||
code: codeID,
|
||||
methods: placeholder{{.}}.Methods,
|
||||
state: nil,
|
||||
})
|
||||
case manifest.EthAccountKey:
|
||||
registry = append(registry, RegistryEntry{
|
||||
code: codeID,
|
||||
methods: ethaccount{{.}}.Methods,
|
||||
state: nil,
|
||||
})
|
||||
{{end}}
|
||||
}
|
||||
}
|
||||
{{end}}
|
||||
|
@ -93,6 +93,7 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: base,
|
||||
Epoch: e,
|
||||
Timestamp: ts.MinTimestamp(),
|
||||
Rand: r,
|
||||
Bstore: sm.ChainStore().StateBlockstore(),
|
||||
Actors: NewActorRegistry(),
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
pubsub "github.com/libp2p/go-libp2p-pubsub"
|
||||
"github.com/multiformats/go-varint"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/trace"
|
||||
@ -21,6 +22,7 @@ import (
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
@ -433,6 +435,39 @@ func (filec *FilecoinEC) VerifyWinningPoStProof(ctx context.Context, nv network.
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsValidForSending(nv network.Version, act *types.Actor) bool {
|
||||
// Before nv18 (Hygge), we only supported built-in account actors as senders.
|
||||
//
|
||||
// Note: this gate is probably superfluous, since:
|
||||
// 1. Placeholder actors cannot be created before nv18.
|
||||
// 2. EthAccount actors cannot be created before nv18.
|
||||
// 3. Delegated addresses cannot be created before nv18.
|
||||
//
|
||||
// But it's a safeguard.
|
||||
//
|
||||
// Note 2: ad-hoc checks for network versions like this across the codebase
|
||||
// will be problematic with networks with diverging version lineages
|
||||
// (e.g. Hyperspace). We need to revisit this strategy entirely.
|
||||
if nv < network.Version18 {
|
||||
return builtin.IsAccountActor(act.Code)
|
||||
}
|
||||
|
||||
// After nv18, we also support other kinds of senders.
|
||||
if builtin.IsAccountActor(act.Code) || builtin.IsEthAccountActor(act.Code) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Allow placeholder actors with a delegated address and nonce 0 to send a message.
|
||||
// These will be converted to an EthAccount actor on first send.
|
||||
if !builtin.IsPlaceholderActor(act.Code) || act.Nonce != 0 || act.Address == nil || act.Address.Protocol() != address.Delegated {
|
||||
return false
|
||||
}
|
||||
|
||||
// Only allow such actors to send if their delegated address is in the EAM's namespace.
|
||||
id, _, err := varint.FromUvarint(act.Address.Payload())
|
||||
return err == nil && id == builtintypes.EthereumAddressManagerActorID
|
||||
}
|
||||
|
||||
// TODO: We should extract this somewhere else and make the message pool and miner use the same logic
|
||||
func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBlock, baseTs *types.TipSet) error {
|
||||
{
|
||||
@ -505,7 +540,7 @@ func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBl
|
||||
return xerrors.Errorf("failed to get actor: %w", err)
|
||||
}
|
||||
|
||||
if !builtin.IsAccountActor(act.Code) {
|
||||
if !IsValidForSending(nv, act) {
|
||||
return xerrors.New("Sender must be an account actor")
|
||||
}
|
||||
nonces[sender] = act.Nonce
|
||||
@ -542,25 +577,23 @@ func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBl
|
||||
|
||||
smArr := blockadt.MakeEmptyArray(tmpstore)
|
||||
for i, m := range b.SecpkMessages {
|
||||
if filec.sm.GetNetworkVersion(ctx, b.Header.Height) >= network.Version14 {
|
||||
if m.Signature.Type != crypto.SigTypeSecp256k1 {
|
||||
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
|
||||
}
|
||||
if nv >= network.Version14 && !chain.IsValidSecpkSigType(nv, m.Signature.Type) {
|
||||
return xerrors.Errorf("block had invalid signed message at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
if err := checkMsg(m); err != nil {
|
||||
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
|
||||
}
|
||||
|
||||
// `From` being an account actor is only validated inside the `vm.ResolveToKeyAddr` call
|
||||
// in `StateManager.ResolveToKeyAddress` here (and not in `checkMsg`).
|
||||
kaddr, err := filec.sm.ResolveToKeyAddress(ctx, m.Message.From, baseTs)
|
||||
// `From` being an account actor is only validated inside the `vm.ResolveToDeterministicAddr` call
|
||||
// in `StateManager.ResolveToDeterministicAddress` here (and not in `checkMsg`).
|
||||
kaddr, err := filec.sm.ResolveToDeterministicAddress(ctx, m.Message.From, baseTs)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to resolve key addr: %w", err)
|
||||
}
|
||||
|
||||
if err := sigs.Verify(&m.Signature, kaddr, m.Message.Cid().Bytes()); err != nil {
|
||||
return xerrors.Errorf("secpk message %s has invalid signature: %w", m.Cid(), err)
|
||||
if err := chain.AuthenticateMessage(m, kaddr); err != nil {
|
||||
return xerrors.Errorf("failed to validate signature: %w", err)
|
||||
}
|
||||
|
||||
c, err := store.PutMessage(ctx, tmpbs, m)
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain"
|
||||
"github.com/filecoin-project/lotus/chain/consensus"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
@ -54,6 +55,7 @@ func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api.
|
||||
|
||||
var blsMsgCids, secpkMsgCids []cid.Cid
|
||||
var blsSigs []crypto.Signature
|
||||
nv := filec.sm.GetNetworkVersion(ctx, bt.Epoch)
|
||||
for _, msg := range bt.Messages {
|
||||
if msg.Signature.Type == crypto.SigTypeBLS {
|
||||
blsSigs = append(blsSigs, msg.Signature)
|
||||
@ -65,7 +67,7 @@ func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api.
|
||||
}
|
||||
|
||||
blsMsgCids = append(blsMsgCids, c)
|
||||
} else if msg.Signature.Type == crypto.SigTypeSecp256k1 {
|
||||
} else if chain.IsValidSecpkSigType(nv, msg.Signature.Type) {
|
||||
c, err := filec.sm.ChainStore().PutMessage(ctx, msg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -18,8 +18,10 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
actorstypes "github.com/filecoin-project/go-state-types/actors"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
nv18 "github.com/filecoin-project/go-state-types/builtin/v10/migration"
|
||||
nv17 "github.com/filecoin-project/go-state-types/builtin/v9/migration"
|
||||
"github.com/filecoin-project/go-state-types/manifest"
|
||||
"github.com/filecoin-project/go-state-types/migration"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/go-state-types/rt"
|
||||
gstStore "github.com/filecoin-project/go-state-types/store"
|
||||
@ -232,8 +234,18 @@ func DefaultUpgradeSchedule() stmgr.UpgradeSchedule {
|
||||
StopWithin: 5,
|
||||
}},
|
||||
Expensive: true,
|
||||
}, {
|
||||
Height: build.UpgradeHyggeHeight,
|
||||
Network: network.Version18,
|
||||
Migration: UpgradeActorsV10,
|
||||
PreMigrations: []stmgr.PreMigration{{
|
||||
PreMigration: PreUpgradeActorsV10,
|
||||
StartWithin: 180,
|
||||
DontStartWithin: 60,
|
||||
StopWithin: 5,
|
||||
}},
|
||||
Expensive: true,
|
||||
},
|
||||
// TODO v10 upgrade
|
||||
}
|
||||
|
||||
for _, u := range updates {
|
||||
@ -1580,11 +1592,110 @@ func upgradeActorsV9Common(
|
||||
|
||||
func UpgradeActorsV10(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor,
|
||||
root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) (cid.Cid, error) {
|
||||
// Use all the CPUs except 3.
|
||||
workerCount := MigrationMaxWorkerCount - 3
|
||||
if workerCount <= 0 {
|
||||
workerCount = 1
|
||||
}
|
||||
|
||||
// TODO migration
|
||||
// - the init actor state to include the (empty) installed actors field
|
||||
// - state tree migration to v5
|
||||
return cid.Undef, fmt.Errorf("IMPLEMENTME: v10 migration")
|
||||
config := migration.Config{
|
||||
MaxWorkers: uint(workerCount),
|
||||
JobQueueSize: 1000,
|
||||
ResultQueueSize: 100,
|
||||
ProgressLogPeriod: 10 * time.Second,
|
||||
}
|
||||
|
||||
newRoot, err := upgradeActorsV10Common(ctx, sm, cache, root, epoch, ts, config)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("migrating actors v10 state: %w", err)
|
||||
}
|
||||
|
||||
return newRoot, nil
|
||||
}
|
||||
|
||||
func PreUpgradeActorsV10(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet) error {
|
||||
// Use half the CPUs for pre-migration, but leave at least 3.
|
||||
workerCount := MigrationMaxWorkerCount
|
||||
if workerCount <= 4 {
|
||||
workerCount = 1
|
||||
} else {
|
||||
workerCount /= 2
|
||||
}
|
||||
|
||||
lbts, lbRoot, err := stmgr.GetLookbackTipSetForRound(ctx, sm, ts, epoch)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error getting lookback ts for premigration: %w", err)
|
||||
}
|
||||
|
||||
config := migration.Config{
|
||||
MaxWorkers: uint(workerCount),
|
||||
ProgressLogPeriod: time.Minute * 5,
|
||||
}
|
||||
|
||||
_, err = upgradeActorsV10Common(ctx, sm, cache, lbRoot, epoch, lbts, config)
|
||||
return err
|
||||
}
|
||||
|
||||
func upgradeActorsV10Common(
|
||||
ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache,
|
||||
root cid.Cid, epoch abi.ChainEpoch, ts *types.TipSet,
|
||||
config migration.Config,
|
||||
) (cid.Cid, error) {
|
||||
buf := blockstore.NewTieredBstore(sm.ChainStore().StateBlockstore(), blockstore.NewMemorySync())
|
||||
store := store.ActorStore(ctx, buf)
|
||||
|
||||
// ensure that the manifest is loaded in the blockstore
|
||||
if err := bundle.LoadBundles(ctx, sm.ChainStore().StateBlockstore(), actorstypes.Version10); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to load manifest bundle: %w", err)
|
||||
}
|
||||
|
||||
// Load the state root.
|
||||
var stateRoot types.StateRoot
|
||||
if err := store.Get(ctx, root, &stateRoot); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to decode state root: %w", err)
|
||||
}
|
||||
|
||||
if stateRoot.Version != types.StateTreeVersion4 {
|
||||
return cid.Undef, xerrors.Errorf(
|
||||
"expected state root version 4 for actors v9 upgrade, got %d",
|
||||
stateRoot.Version,
|
||||
)
|
||||
}
|
||||
|
||||
manifest, ok := actors.GetManifest(actorstypes.Version10)
|
||||
if !ok {
|
||||
return cid.Undef, xerrors.Errorf("no manifest CID for v9 upgrade")
|
||||
}
|
||||
|
||||
// Perform the migration
|
||||
newHamtRoot, err := nv18.MigrateStateTree(ctx, store, manifest, stateRoot.Actors, epoch, config,
|
||||
migrationLogger{}, cache)
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("upgrading to actors v10: %w", err)
|
||||
}
|
||||
|
||||
// Persist the result.
|
||||
newRoot, err := store.Put(ctx, &types.StateRoot{
|
||||
Version: types.StateTreeVersion5,
|
||||
Actors: newHamtRoot,
|
||||
Info: stateRoot.Info,
|
||||
})
|
||||
if err != nil {
|
||||
return cid.Undef, xerrors.Errorf("failed to persist new state root: %w", err)
|
||||
}
|
||||
|
||||
// Persist the new tree.
|
||||
|
||||
{
|
||||
from := buf
|
||||
to := buf.Read()
|
||||
|
||||
if err := vm.Copy(ctx, from, to, newRoot); err != nil {
|
||||
return cid.Undef, xerrors.Errorf("copying migrated tree: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return newRoot, nil
|
||||
}
|
||||
|
||||
// Example upgrade function if upgrade requires only code changes
|
||||
|
474
chain/events/filter/event.go
Normal file
474
chain/events/filter/event.go
Normal file
@ -0,0 +1,474 @@
|
||||
package filter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
amt4 "github.com/filecoin-project/go-amt-ipld/v4"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
cstore "github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
const indexed uint8 = 0x01
|
||||
|
||||
type EventFilter struct {
|
||||
id types.FilterID
|
||||
minHeight abi.ChainEpoch // minimum epoch to apply filter or -1 if no minimum
|
||||
maxHeight abi.ChainEpoch // maximum epoch to apply filter or -1 if no maximum
|
||||
tipsetCid cid.Cid
|
||||
addresses []address.Address // list of f4 actor addresses that are extpected to emit the event
|
||||
keys map[string][][]byte // map of key names to a list of alternate values that may match
|
||||
maxResults int // maximum number of results to collect, 0 is unlimited
|
||||
|
||||
mu sync.Mutex
|
||||
collected []*CollectedEvent
|
||||
lastTaken time.Time
|
||||
ch chan<- interface{}
|
||||
}
|
||||
|
||||
var _ Filter = (*EventFilter)(nil)
|
||||
|
||||
type CollectedEvent struct {
|
||||
Entries []types.EventEntry
|
||||
EmitterAddr address.Address // f4 address of emitter
|
||||
EventIdx int // index of the event within the list of emitted events
|
||||
Reverted bool
|
||||
Height abi.ChainEpoch
|
||||
TipSetKey types.TipSetKey // tipset that contained the message
|
||||
MsgIdx int // index of the message in the tipset
|
||||
MsgCid cid.Cid // cid of message that produced event
|
||||
}
|
||||
|
||||
func (f *EventFilter) ID() types.FilterID {
|
||||
return f.id
|
||||
}
|
||||
|
||||
func (f *EventFilter) SetSubChannel(ch chan<- interface{}) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.ch = ch
|
||||
f.collected = nil
|
||||
}
|
||||
|
||||
func (f *EventFilter) ClearSubChannel() {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.ch = nil
|
||||
}
|
||||
|
||||
func (f *EventFilter) CollectEvents(ctx context.Context, te *TipSetEvents, revert bool, resolver func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool)) error {
|
||||
if !f.matchTipset(te) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// cache of lookups between actor id and f4 address
|
||||
addressLookups := make(map[abi.ActorID]address.Address)
|
||||
|
||||
ems, err := te.messages(ctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("load executed messages: %w", err)
|
||||
}
|
||||
for msgIdx, em := range ems {
|
||||
for evIdx, ev := range em.Events() {
|
||||
// lookup address corresponding to the actor id
|
||||
addr, found := addressLookups[ev.Emitter]
|
||||
if !found {
|
||||
var ok bool
|
||||
addr, ok = resolver(ctx, ev.Emitter, te.rctTs)
|
||||
if !ok {
|
||||
// not an address we will be able to match against
|
||||
continue
|
||||
}
|
||||
addressLookups[ev.Emitter] = addr
|
||||
}
|
||||
|
||||
if !f.matchAddress(addr) {
|
||||
continue
|
||||
}
|
||||
if !f.matchKeys(ev.Entries) {
|
||||
continue
|
||||
}
|
||||
|
||||
// event matches filter, so record it
|
||||
cev := &CollectedEvent{
|
||||
Entries: ev.Entries,
|
||||
EmitterAddr: addr,
|
||||
EventIdx: evIdx,
|
||||
Reverted: revert,
|
||||
Height: te.msgTs.Height(),
|
||||
TipSetKey: te.msgTs.Key(),
|
||||
MsgCid: em.Message().Cid(),
|
||||
MsgIdx: msgIdx,
|
||||
}
|
||||
|
||||
f.mu.Lock()
|
||||
// if we have a subscription channel then push event to it
|
||||
if f.ch != nil {
|
||||
f.ch <- cev
|
||||
f.mu.Unlock()
|
||||
continue
|
||||
}
|
||||
|
||||
if f.maxResults > 0 && len(f.collected) == f.maxResults {
|
||||
copy(f.collected, f.collected[1:])
|
||||
f.collected = f.collected[:len(f.collected)-1]
|
||||
}
|
||||
f.collected = append(f.collected, cev)
|
||||
f.mu.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *EventFilter) setCollectedEvents(ces []*CollectedEvent) {
|
||||
f.mu.Lock()
|
||||
f.collected = ces
|
||||
f.mu.Unlock()
|
||||
}
|
||||
|
||||
func (f *EventFilter) TakeCollectedEvents(ctx context.Context) []*CollectedEvent {
|
||||
f.mu.Lock()
|
||||
collected := f.collected
|
||||
f.collected = nil
|
||||
f.lastTaken = time.Now().UTC()
|
||||
f.mu.Unlock()
|
||||
|
||||
return collected
|
||||
}
|
||||
|
||||
func (f *EventFilter) LastTaken() time.Time {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.lastTaken
|
||||
}
|
||||
|
||||
// matchTipset reports whether this filter matches the given tipset
|
||||
func (f *EventFilter) matchTipset(te *TipSetEvents) bool {
|
||||
if f.tipsetCid != cid.Undef {
|
||||
tsCid, err := te.Cid()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return f.tipsetCid.Equals(tsCid)
|
||||
}
|
||||
|
||||
if f.minHeight >= 0 && f.minHeight > te.Height() {
|
||||
return false
|
||||
}
|
||||
if f.maxHeight >= 0 && f.maxHeight < te.Height() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (f *EventFilter) matchAddress(o address.Address) bool {
|
||||
if len(f.addresses) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
// Assume short lists of addresses
|
||||
// TODO: binary search for longer lists or restrict list length
|
||||
for _, a := range f.addresses {
|
||||
if a == o {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (f *EventFilter) matchKeys(ees []types.EventEntry) bool {
|
||||
if len(f.keys) == 0 {
|
||||
return true
|
||||
}
|
||||
// TODO: optimize this naive algorithm
|
||||
// tracked in https://github.com/filecoin-project/lotus/issues/9987
|
||||
|
||||
// Note keys names may be repeated so we may have multiple opportunities to match
|
||||
|
||||
matched := map[string]bool{}
|
||||
for _, ee := range ees {
|
||||
// Skip an entry that is not indexable
|
||||
if ee.Flags&indexed != indexed {
|
||||
continue
|
||||
}
|
||||
|
||||
keyname := ee.Key
|
||||
|
||||
// skip if we have already matched this key
|
||||
if matched[keyname] {
|
||||
continue
|
||||
}
|
||||
|
||||
wantlist, ok := f.keys[keyname]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, w := range wantlist {
|
||||
if bytes.Equal(w, ee.Value) {
|
||||
matched[keyname] = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if len(matched) == len(f.keys) {
|
||||
// all keys have been matched
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
type TipSetEvents struct {
|
||||
rctTs *types.TipSet // rctTs is the tipset containing the receipts of executed messages
|
||||
msgTs *types.TipSet // msgTs is the tipset containing the messages that have been executed
|
||||
|
||||
load func(ctx context.Context, msgTs, rctTs *types.TipSet) ([]executedMessage, error)
|
||||
|
||||
once sync.Once // for lazy population of ems
|
||||
ems []executedMessage
|
||||
err error
|
||||
}
|
||||
|
||||
func (te *TipSetEvents) Height() abi.ChainEpoch {
|
||||
return te.msgTs.Height()
|
||||
}
|
||||
|
||||
func (te *TipSetEvents) Cid() (cid.Cid, error) {
|
||||
return te.msgTs.Key().Cid()
|
||||
}
|
||||
|
||||
func (te *TipSetEvents) messages(ctx context.Context) ([]executedMessage, error) {
|
||||
te.once.Do(func() {
|
||||
// populate executed message list
|
||||
ems, err := te.load(ctx, te.msgTs, te.rctTs)
|
||||
if err != nil {
|
||||
te.err = err
|
||||
return
|
||||
}
|
||||
te.ems = ems
|
||||
})
|
||||
return te.ems, te.err
|
||||
}
|
||||
|
||||
type executedMessage struct {
|
||||
msg *types.Message
|
||||
rct *types.MessageReceipt
|
||||
// events extracted from receipt
|
||||
evs []*types.Event
|
||||
}
|
||||
|
||||
func (e *executedMessage) Message() *types.Message {
|
||||
return e.msg
|
||||
}
|
||||
|
||||
func (e *executedMessage) Receipt() *types.MessageReceipt {
|
||||
return e.rct
|
||||
}
|
||||
|
||||
func (e *executedMessage) Events() []*types.Event {
|
||||
return e.evs
|
||||
}
|
||||
|
||||
type EventFilterManager struct {
|
||||
ChainStore *cstore.ChainStore
|
||||
AddressResolver func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool)
|
||||
MaxFilterResults int
|
||||
EventIndex *EventIndex
|
||||
|
||||
mu sync.Mutex // guards mutations to filters
|
||||
filters map[types.FilterID]*EventFilter
|
||||
currentHeight abi.ChainEpoch
|
||||
}
|
||||
|
||||
func (m *EventFilterManager) Apply(ctx context.Context, from, to *types.TipSet) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.currentHeight = to.Height()
|
||||
|
||||
if len(m.filters) == 0 && m.EventIndex == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
tse := &TipSetEvents{
|
||||
msgTs: from,
|
||||
rctTs: to,
|
||||
load: m.loadExecutedMessages,
|
||||
}
|
||||
|
||||
if m.EventIndex != nil {
|
||||
if err := m.EventIndex.CollectEvents(ctx, tse, false, m.AddressResolver); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: could run this loop in parallel with errgroup if there are many filters
|
||||
for _, f := range m.filters {
|
||||
if err := f.CollectEvents(ctx, tse, false, m.AddressResolver); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *EventFilterManager) Revert(ctx context.Context, from, to *types.TipSet) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.currentHeight = to.Height()
|
||||
|
||||
if len(m.filters) == 0 && m.EventIndex == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
tse := &TipSetEvents{
|
||||
msgTs: to,
|
||||
rctTs: from,
|
||||
load: m.loadExecutedMessages,
|
||||
}
|
||||
|
||||
if m.EventIndex != nil {
|
||||
if err := m.EventIndex.CollectEvents(ctx, tse, true, m.AddressResolver); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: could run this loop in parallel with errgroup if there are many filters
|
||||
for _, f := range m.filters {
|
||||
if err := f.CollectEvents(ctx, tse, true, m.AddressResolver); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *EventFilterManager) Install(ctx context.Context, minHeight, maxHeight abi.ChainEpoch, tipsetCid cid.Cid, addresses []address.Address, keys map[string][][]byte) (*EventFilter, error) {
|
||||
m.mu.Lock()
|
||||
currentHeight := m.currentHeight
|
||||
m.mu.Unlock()
|
||||
|
||||
if m.EventIndex == nil && minHeight != -1 && minHeight < currentHeight {
|
||||
return nil, xerrors.Errorf("historic event index disabled")
|
||||
}
|
||||
|
||||
id, err := newFilterID()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("new filter id: %w", err)
|
||||
}
|
||||
|
||||
f := &EventFilter{
|
||||
id: id,
|
||||
minHeight: minHeight,
|
||||
maxHeight: maxHeight,
|
||||
tipsetCid: tipsetCid,
|
||||
addresses: addresses,
|
||||
keys: keys,
|
||||
maxResults: m.MaxFilterResults,
|
||||
}
|
||||
|
||||
if m.EventIndex != nil && minHeight != -1 && minHeight < currentHeight {
|
||||
// Filter needs historic events
|
||||
if err := m.EventIndex.PrefillFilter(ctx, f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
if m.filters == nil {
|
||||
m.filters = make(map[types.FilterID]*EventFilter)
|
||||
}
|
||||
m.filters[id] = f
|
||||
m.mu.Unlock()
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (m *EventFilterManager) Remove(ctx context.Context, id types.FilterID) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if _, found := m.filters[id]; !found {
|
||||
return ErrFilterNotFound
|
||||
}
|
||||
delete(m.filters, id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *EventFilterManager) loadExecutedMessages(ctx context.Context, msgTs, rctTs *types.TipSet) ([]executedMessage, error) {
|
||||
msgs, err := m.ChainStore.MessagesForTipset(ctx, msgTs)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("read messages: %w", err)
|
||||
}
|
||||
|
||||
st := m.ChainStore.ActorStore(ctx)
|
||||
|
||||
arr, err := blockadt.AsArray(st, rctTs.Blocks()[0].ParentMessageReceipts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("load receipts amt: %w", err)
|
||||
}
|
||||
|
||||
if uint64(len(msgs)) != arr.Length() {
|
||||
return nil, xerrors.Errorf("mismatching message and receipt counts (%d msgs, %d rcts)", len(msgs), arr.Length())
|
||||
}
|
||||
|
||||
ems := make([]executedMessage, len(msgs))
|
||||
|
||||
for i := 0; i < len(msgs); i++ {
|
||||
ems[i].msg = msgs[i].VMMessage()
|
||||
|
||||
var rct types.MessageReceipt
|
||||
found, err := arr.Get(uint64(i), &rct)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("load receipt: %w", err)
|
||||
}
|
||||
if !found {
|
||||
return nil, xerrors.Errorf("receipt %d not found", i)
|
||||
}
|
||||
ems[i].rct = &rct
|
||||
|
||||
if rct.EventsRoot == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
evtArr, err := amt4.LoadAMT(ctx, st, *rct.EventsRoot, amt4.UseTreeBitWidth(types.EventAMTBitwidth))
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("load events amt: %w", err)
|
||||
}
|
||||
|
||||
ems[i].evs = make([]*types.Event, evtArr.Len())
|
||||
var evt types.Event
|
||||
err = evtArr.ForEach(ctx, func(u uint64, deferred *cbg.Deferred) error {
|
||||
if u > math.MaxInt {
|
||||
return xerrors.Errorf("too many events")
|
||||
}
|
||||
if err := evt.UnmarshalCBOR(bytes.NewReader(deferred.Raw)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cpy := evt
|
||||
ems[i].evs[int(u)] = &cpy //nolint:scopelint
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("read events: %w", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ems, nil
|
||||
}
|
431
chain/events/filter/event_test.go
Normal file
431
chain/events/filter/event_test.go
Normal file
@ -0,0 +1,431 @@
|
||||
package filter
|
||||
|
||||
import (
|
||||
"context"
|
||||
pseudo "math/rand"
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
cbor "github.com/ipfs/go-ipld-cbor"
|
||||
mh "github.com/multiformats/go-multihash"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt"
|
||||
|
||||
"github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func TestEventFilterCollectEvents(t *testing.T) {
|
||||
rng := pseudo.New(pseudo.NewSource(299792458))
|
||||
a1 := randomF4Addr(t, rng)
|
||||
a2 := randomF4Addr(t, rng)
|
||||
|
||||
a1ID := abi.ActorID(1)
|
||||
a2ID := abi.ActorID(2)
|
||||
|
||||
addrMap := addressMap{}
|
||||
addrMap.add(a1ID, a1)
|
||||
addrMap.add(a2ID, a2)
|
||||
|
||||
ev1 := fakeEvent(
|
||||
a1ID,
|
||||
[]kv{
|
||||
{k: "type", v: []byte("approval")},
|
||||
{k: "signer", v: []byte("addr1")},
|
||||
},
|
||||
[]kv{
|
||||
{k: "amount", v: []byte("2988181")},
|
||||
},
|
||||
)
|
||||
|
||||
st := newStore()
|
||||
events := []*types.Event{ev1}
|
||||
em := executedMessage{
|
||||
msg: fakeMessage(randomF4Addr(t, rng), randomF4Addr(t, rng)),
|
||||
rct: fakeReceipt(t, rng, st, events),
|
||||
evs: events,
|
||||
}
|
||||
|
||||
events14000 := buildTipSetEvents(t, rng, 14000, em)
|
||||
cid14000, err := events14000.msgTs.Key().Cid()
|
||||
require.NoError(t, err, "tipset cid")
|
||||
|
||||
noCollectedEvents := []*CollectedEvent{}
|
||||
oneCollectedEvent := []*CollectedEvent{
|
||||
{
|
||||
Entries: ev1.Entries,
|
||||
EmitterAddr: a1,
|
||||
EventIdx: 0,
|
||||
Reverted: false,
|
||||
Height: 14000,
|
||||
TipSetKey: events14000.msgTs.Key(),
|
||||
MsgIdx: 0,
|
||||
MsgCid: em.msg.Cid(),
|
||||
},
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
filter *EventFilter
|
||||
te *TipSetEvents
|
||||
want []*CollectedEvent
|
||||
}{
|
||||
{
|
||||
name: "nomatch tipset min height",
|
||||
filter: &EventFilter{
|
||||
minHeight: 14001,
|
||||
maxHeight: -1,
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "nomatch tipset max height",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: 13999,
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "match tipset min height",
|
||||
filter: &EventFilter{
|
||||
minHeight: 14000,
|
||||
maxHeight: -1,
|
||||
},
|
||||
te: events14000,
|
||||
want: oneCollectedEvent,
|
||||
},
|
||||
{
|
||||
name: "match tipset cid",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
tipsetCid: cid14000,
|
||||
},
|
||||
te: events14000,
|
||||
want: oneCollectedEvent,
|
||||
},
|
||||
{
|
||||
name: "nomatch address",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
addresses: []address.Address{a2},
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "match address",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
addresses: []address.Address{a1},
|
||||
},
|
||||
te: events14000,
|
||||
want: oneCollectedEvent,
|
||||
},
|
||||
{
|
||||
name: "match one entry",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"type": {
|
||||
[]byte("approval"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: oneCollectedEvent,
|
||||
},
|
||||
{
|
||||
name: "match one entry with alternate values",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"type": {
|
||||
[]byte("cancel"),
|
||||
[]byte("propose"),
|
||||
[]byte("approval"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: oneCollectedEvent,
|
||||
},
|
||||
{
|
||||
name: "nomatch one entry by missing value",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"type": {
|
||||
[]byte("cancel"),
|
||||
[]byte("propose"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "nomatch one entry by missing key",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"method": {
|
||||
[]byte("approval"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "match one entry with multiple keys",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"type": {
|
||||
[]byte("approval"),
|
||||
},
|
||||
"signer": {
|
||||
[]byte("addr1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: oneCollectedEvent,
|
||||
},
|
||||
{
|
||||
name: "nomatch one entry with one mismatching key",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"type": {
|
||||
[]byte("approval"),
|
||||
},
|
||||
"approver": {
|
||||
[]byte("addr1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "nomatch one entry with one mismatching value",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"type": {
|
||||
[]byte("approval"),
|
||||
},
|
||||
"signer": {
|
||||
[]byte("addr2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "nomatch one entry with one unindexed key",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"amount": {
|
||||
[]byte("2988181"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc // appease lint
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if err := tc.filter.CollectEvents(context.Background(), tc.te, false, addrMap.ResolveAddress); err != nil {
|
||||
require.NoError(t, err, "collect events")
|
||||
}
|
||||
|
||||
coll := tc.filter.TakeCollectedEvents(context.Background())
|
||||
require.ElementsMatch(t, coll, tc.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type kv struct {
|
||||
k string
|
||||
v []byte
|
||||
}
|
||||
|
||||
func fakeEvent(emitter abi.ActorID, indexed []kv, unindexed []kv) *types.Event {
|
||||
ev := &types.Event{
|
||||
Emitter: emitter,
|
||||
}
|
||||
|
||||
for _, in := range indexed {
|
||||
ev.Entries = append(ev.Entries, types.EventEntry{
|
||||
Flags: 0x01,
|
||||
Key: in.k,
|
||||
Value: in.v,
|
||||
})
|
||||
}
|
||||
|
||||
for _, in := range unindexed {
|
||||
ev.Entries = append(ev.Entries, types.EventEntry{
|
||||
Flags: 0x00,
|
||||
Key: in.k,
|
||||
Value: in.v,
|
||||
})
|
||||
}
|
||||
|
||||
return ev
|
||||
}
|
||||
|
||||
func randomF4Addr(tb testing.TB, rng *pseudo.Rand) address.Address {
|
||||
tb.Helper()
|
||||
addr, err := address.NewDelegatedAddress(builtintypes.EthereumAddressManagerActorID, randomBytes(32, rng))
|
||||
require.NoError(tb, err)
|
||||
|
||||
return addr
|
||||
}
|
||||
|
||||
func randomIDAddr(tb testing.TB, rng *pseudo.Rand) address.Address {
|
||||
tb.Helper()
|
||||
addr, err := address.NewIDAddress(uint64(rng.Int63()))
|
||||
require.NoError(tb, err)
|
||||
return addr
|
||||
}
|
||||
|
||||
func randomCid(tb testing.TB, rng *pseudo.Rand) cid.Cid {
|
||||
tb.Helper()
|
||||
cb := cid.V1Builder{Codec: cid.Raw, MhType: mh.IDENTITY}
|
||||
c, err := cb.Sum(randomBytes(10, rng))
|
||||
require.NoError(tb, err)
|
||||
return c
|
||||
}
|
||||
|
||||
func randomBytes(n int, rng *pseudo.Rand) []byte {
|
||||
buf := make([]byte, n)
|
||||
rng.Read(buf)
|
||||
return buf
|
||||
}
|
||||
|
||||
func fakeMessage(to, from address.Address) *types.Message {
|
||||
return &types.Message{
|
||||
To: to,
|
||||
From: from,
|
||||
Nonce: 197,
|
||||
Method: 1,
|
||||
Params: []byte("some random bytes"),
|
||||
GasLimit: 126723,
|
||||
GasPremium: types.NewInt(4),
|
||||
GasFeeCap: types.NewInt(120),
|
||||
}
|
||||
}
|
||||
|
||||
func fakeReceipt(tb testing.TB, rng *pseudo.Rand, st adt.Store, events []*types.Event) *types.MessageReceipt {
|
||||
arr := blockadt.MakeEmptyArray(st)
|
||||
for _, ev := range events {
|
||||
err := arr.AppendContinuous(ev)
|
||||
require.NoError(tb, err, "append event")
|
||||
}
|
||||
eventsRoot, err := arr.Root()
|
||||
require.NoError(tb, err, "flush events amt")
|
||||
|
||||
rec := types.NewMessageReceiptV1(exitcode.Ok, randomBytes(32, rng), rng.Int63(), &eventsRoot)
|
||||
return &rec
|
||||
}
|
||||
|
||||
func fakeTipSet(tb testing.TB, rng *pseudo.Rand, h abi.ChainEpoch, parents []cid.Cid) *types.TipSet {
|
||||
tb.Helper()
|
||||
ts, err := types.NewTipSet([]*types.BlockHeader{
|
||||
{
|
||||
Height: h,
|
||||
Miner: randomIDAddr(tb, rng),
|
||||
|
||||
Parents: parents,
|
||||
|
||||
Ticket: &types.Ticket{VRFProof: []byte{byte(h % 2)}},
|
||||
|
||||
ParentStateRoot: randomCid(tb, rng),
|
||||
Messages: randomCid(tb, rng),
|
||||
ParentMessageReceipts: randomCid(tb, rng),
|
||||
|
||||
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS},
|
||||
BLSAggregate: &crypto.Signature{Type: crypto.SigTypeBLS},
|
||||
},
|
||||
{
|
||||
Height: h,
|
||||
Miner: randomIDAddr(tb, rng),
|
||||
|
||||
Parents: parents,
|
||||
|
||||
Ticket: &types.Ticket{VRFProof: []byte{byte((h + 1) % 2)}},
|
||||
|
||||
ParentStateRoot: randomCid(tb, rng),
|
||||
Messages: randomCid(tb, rng),
|
||||
ParentMessageReceipts: randomCid(tb, rng),
|
||||
|
||||
BlockSig: &crypto.Signature{Type: crypto.SigTypeBLS},
|
||||
BLSAggregate: &crypto.Signature{Type: crypto.SigTypeBLS},
|
||||
},
|
||||
})
|
||||
|
||||
require.NoError(tb, err)
|
||||
|
||||
return ts
|
||||
}
|
||||
|
||||
func newStore() adt.Store {
|
||||
ctx := context.Background()
|
||||
bs := blockstore.NewMemorySync()
|
||||
store := cbor.NewCborStore(bs)
|
||||
return adt.WrapStore(ctx, store)
|
||||
}
|
||||
|
||||
func buildTipSetEvents(tb testing.TB, rng *pseudo.Rand, h abi.ChainEpoch, em executedMessage) *TipSetEvents {
|
||||
tb.Helper()
|
||||
|
||||
msgTs := fakeTipSet(tb, rng, h, []cid.Cid{})
|
||||
rctTs := fakeTipSet(tb, rng, h+1, msgTs.Cids())
|
||||
|
||||
return &TipSetEvents{
|
||||
msgTs: msgTs,
|
||||
rctTs: rctTs,
|
||||
load: func(ctx context.Context, msgTs, rctTs *types.TipSet) ([]executedMessage, error) {
|
||||
return []executedMessage{em}, nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type addressMap map[abi.ActorID]address.Address
|
||||
|
||||
func (a addressMap) add(actorID abi.ActorID, addr address.Address) {
|
||||
a[actorID] = addr
|
||||
}
|
||||
|
||||
func (a addressMap) ResolveAddress(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool) {
|
||||
ra, ok := a[emitter]
|
||||
return ra, ok
|
||||
}
|
434
chain/events/filter/index.go
Normal file
434
chain/events/filter/index.go
Normal file
@ -0,0 +1,434 @@
|
||||
package filter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
var pragmas = []string{
|
||||
"PRAGMA synchronous = normal",
|
||||
"PRAGMA temp_store = memory",
|
||||
"PRAGMA mmap_size = 30000000000",
|
||||
"PRAGMA page_size = 32768",
|
||||
"PRAGMA auto_vacuum = NONE",
|
||||
"PRAGMA automatic_index = OFF",
|
||||
"PRAGMA journal_mode = WAL",
|
||||
"PRAGMA read_uncommitted = ON",
|
||||
}
|
||||
|
||||
var ddls = []string{
|
||||
`CREATE TABLE IF NOT EXISTS event (
|
||||
id INTEGER PRIMARY KEY,
|
||||
height INTEGER NOT NULL,
|
||||
tipset_key BLOB NOT NULL,
|
||||
tipset_key_cid BLOB NOT NULL,
|
||||
emitter_addr BLOB NOT NULL,
|
||||
event_index INTEGER NOT NULL,
|
||||
message_cid BLOB NOT NULL,
|
||||
message_index INTEGER NOT NULL,
|
||||
reverted INTEGER NOT NULL
|
||||
)`,
|
||||
|
||||
`CREATE TABLE IF NOT EXISTS event_entry (
|
||||
event_id INTEGER,
|
||||
indexed INTEGER NOT NULL,
|
||||
flags BLOB NOT NULL,
|
||||
key TEXT NOT NULL,
|
||||
value BLOB NOT NULL
|
||||
)`,
|
||||
|
||||
// metadata containing version of schema
|
||||
`CREATE TABLE IF NOT EXISTS _meta (
|
||||
version UINT64 NOT NULL UNIQUE
|
||||
)`,
|
||||
|
||||
// version 1.
|
||||
`INSERT OR IGNORE INTO _meta (version) VALUES (1)`,
|
||||
}
|
||||
|
||||
const schemaVersion = 1
|
||||
|
||||
const (
|
||||
insertEvent = `INSERT OR IGNORE INTO event
|
||||
(height, tipset_key, tipset_key_cid, emitter_addr, event_index, message_cid, message_index, reverted)
|
||||
VALUES(?, ?, ?, ?, ?, ?, ?, ?)`
|
||||
|
||||
insertEntry = `INSERT OR IGNORE INTO event_entry
|
||||
(event_id, indexed, flags, key, value)
|
||||
VALUES(?, ?, ?, ?, ?)`
|
||||
)
|
||||
|
||||
type EventIndex struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewEventIndex(path string) (*EventIndex, error) {
|
||||
db, err := sql.Open("sqlite3", path+"?mode=rwc")
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("open sqlite3 database: %w", err)
|
||||
}
|
||||
|
||||
for _, pragma := range pragmas {
|
||||
if _, err := db.Exec(pragma); err != nil {
|
||||
_ = db.Close()
|
||||
return nil, xerrors.Errorf("exec pragma %q: %w", pragma, err)
|
||||
}
|
||||
}
|
||||
|
||||
q, err := db.Query("SELECT name FROM sqlite_master WHERE type='table' AND name='_meta';")
|
||||
if err == sql.ErrNoRows || !q.Next() {
|
||||
// empty database, create the schema
|
||||
for _, ddl := range ddls {
|
||||
if _, err := db.Exec(ddl); err != nil {
|
||||
_ = db.Close()
|
||||
return nil, xerrors.Errorf("exec ddl %q: %w", ddl, err)
|
||||
}
|
||||
}
|
||||
} else if err != nil {
|
||||
_ = db.Close()
|
||||
return nil, xerrors.Errorf("looking for _meta table: %w", err)
|
||||
} else {
|
||||
// Ensure we don't open a database from a different schema version
|
||||
|
||||
row := db.QueryRow("SELECT max(version) FROM _meta")
|
||||
var version int
|
||||
err := row.Scan(&version)
|
||||
if err != nil {
|
||||
_ = db.Close()
|
||||
return nil, xerrors.Errorf("invalid database version: no version found")
|
||||
}
|
||||
if version != schemaVersion {
|
||||
_ = db.Close()
|
||||
return nil, xerrors.Errorf("invalid database version: got %d, expected %d", version, schemaVersion)
|
||||
}
|
||||
}
|
||||
|
||||
return &EventIndex{
|
||||
db: db,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ei *EventIndex) Close() error {
|
||||
if ei.db == nil {
|
||||
return nil
|
||||
}
|
||||
return ei.db.Close()
|
||||
}
|
||||
|
||||
func (ei *EventIndex) CollectEvents(ctx context.Context, te *TipSetEvents, revert bool, resolver func(ctx context.Context, emitter abi.ActorID, ts *types.TipSet) (address.Address, bool)) error {
|
||||
// cache of lookups between actor id and f4 address
|
||||
|
||||
addressLookups := make(map[abi.ActorID]address.Address)
|
||||
|
||||
ems, err := te.messages(ctx)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("load executed messages: %w", err)
|
||||
}
|
||||
|
||||
tx, err := ei.db.Begin()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("begin transaction: %w", err)
|
||||
}
|
||||
stmtEvent, err := tx.Prepare(insertEvent)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("prepare insert event: %w", err)
|
||||
}
|
||||
stmtEntry, err := tx.Prepare(insertEntry)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("prepare insert entry: %w", err)
|
||||
}
|
||||
|
||||
isIndexedValue := func(b uint8) bool {
|
||||
// currently we mark the full entry as indexed if either the key
|
||||
// or the value are indexed; in the future we will need finer-grained
|
||||
// management of indices
|
||||
return b&(types.EventFlagIndexedKey|types.EventFlagIndexedValue) > 0
|
||||
}
|
||||
|
||||
for msgIdx, em := range ems {
|
||||
for evIdx, ev := range em.Events() {
|
||||
addr, found := addressLookups[ev.Emitter]
|
||||
if !found {
|
||||
var ok bool
|
||||
addr, ok = resolver(ctx, ev.Emitter, te.rctTs)
|
||||
if !ok {
|
||||
// not an address we will be able to match against
|
||||
continue
|
||||
}
|
||||
addressLookups[ev.Emitter] = addr
|
||||
}
|
||||
|
||||
tsKeyCid, err := te.msgTs.Key().Cid()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("tipset key cid: %w", err)
|
||||
}
|
||||
|
||||
res, err := stmtEvent.Exec(
|
||||
te.msgTs.Height(), // height
|
||||
te.msgTs.Key().Bytes(), // tipset_key
|
||||
tsKeyCid.Bytes(), // tipset_key_cid
|
||||
addr.Bytes(), // emitter_addr
|
||||
evIdx, // event_index
|
||||
em.Message().Cid().Bytes(), // message_cid
|
||||
msgIdx, // message_index
|
||||
revert, // reverted
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("exec insert event: %w", err)
|
||||
}
|
||||
|
||||
lastID, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("get last row id: %w", err)
|
||||
}
|
||||
|
||||
for _, entry := range ev.Entries {
|
||||
value := decodeLogBytes(entry.Value)
|
||||
_, err := stmtEntry.Exec(
|
||||
lastID, // event_id
|
||||
isIndexedValue(entry.Flags), // indexed
|
||||
[]byte{entry.Flags}, // flags
|
||||
entry.Key, // key
|
||||
value, // value
|
||||
)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("exec insert entry: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return xerrors.Errorf("commit transaction: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// decodeLogBytes decodes a CBOR-serialized array into its original form.
|
||||
//
|
||||
// This function swallows errors and returns the original array if it failed
|
||||
// to decode.
|
||||
func decodeLogBytes(orig []byte) []byte {
|
||||
if orig == nil {
|
||||
return orig
|
||||
}
|
||||
decoded, err := cbg.ReadByteArray(bytes.NewReader(orig), uint64(len(orig)))
|
||||
if err != nil {
|
||||
return orig
|
||||
}
|
||||
return decoded
|
||||
}
|
||||
|
||||
// PrefillFilter fills a filter's collection of events from the historic index
|
||||
func (ei *EventIndex) PrefillFilter(ctx context.Context, f *EventFilter) error {
|
||||
clauses := []string{}
|
||||
values := []any{}
|
||||
joins := []string{}
|
||||
|
||||
if f.tipsetCid != cid.Undef {
|
||||
clauses = append(clauses, "event.tipset_key_cid=?")
|
||||
values = append(values, f.tipsetCid.Bytes())
|
||||
} else {
|
||||
if f.minHeight >= 0 {
|
||||
clauses = append(clauses, "event.height>=?")
|
||||
values = append(values, f.minHeight)
|
||||
}
|
||||
if f.maxHeight >= 0 {
|
||||
clauses = append(clauses, "event.height<=?")
|
||||
values = append(values, f.maxHeight)
|
||||
}
|
||||
}
|
||||
|
||||
if len(f.addresses) > 0 {
|
||||
subclauses := []string{}
|
||||
for _, addr := range f.addresses {
|
||||
subclauses = append(subclauses, "emitter_addr=?")
|
||||
values = append(values, addr.Bytes())
|
||||
}
|
||||
clauses = append(clauses, "("+strings.Join(subclauses, " OR ")+")")
|
||||
}
|
||||
|
||||
if len(f.keys) > 0 {
|
||||
join := 0
|
||||
for key, vals := range f.keys {
|
||||
if len(vals) > 0 {
|
||||
join++
|
||||
joinAlias := fmt.Sprintf("ee%d", join)
|
||||
joins = append(joins, fmt.Sprintf("event_entry %s on event.id=%[1]s.event_id", joinAlias))
|
||||
clauses = append(clauses, fmt.Sprintf("%s.indexed=1 AND %[1]s.key=?", joinAlias))
|
||||
values = append(values, key)
|
||||
subclauses := []string{}
|
||||
for _, val := range vals {
|
||||
subclauses = append(subclauses, fmt.Sprintf("%s.value=?", joinAlias))
|
||||
values = append(values, trimLeadingZeros(val))
|
||||
}
|
||||
clauses = append(clauses, "("+strings.Join(subclauses, " OR ")+")")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s := `SELECT
|
||||
event.id,
|
||||
event.height,
|
||||
event.tipset_key,
|
||||
event.tipset_key_cid,
|
||||
event.emitter_addr,
|
||||
event.event_index,
|
||||
event.message_cid,
|
||||
event.message_index,
|
||||
event.reverted,
|
||||
event_entry.flags,
|
||||
event_entry.key,
|
||||
event_entry.value
|
||||
FROM event JOIN event_entry ON event.id=event_entry.event_id`
|
||||
|
||||
if len(joins) > 0 {
|
||||
s = s + ", " + strings.Join(joins, ", ")
|
||||
}
|
||||
|
||||
if len(clauses) > 0 {
|
||||
s = s + " WHERE " + strings.Join(clauses, " AND ")
|
||||
}
|
||||
|
||||
s += " ORDER BY event.height DESC"
|
||||
|
||||
stmt, err := ei.db.Prepare(s)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("prepare prefill query: %w", err)
|
||||
}
|
||||
|
||||
q, err := stmt.QueryContext(ctx, values...)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil
|
||||
}
|
||||
return xerrors.Errorf("exec prefill query: %w", err)
|
||||
}
|
||||
|
||||
var ces []*CollectedEvent
|
||||
var currentID int64 = -1
|
||||
var ce *CollectedEvent
|
||||
|
||||
for q.Next() {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
default:
|
||||
}
|
||||
|
||||
var row struct {
|
||||
id int64
|
||||
height uint64
|
||||
tipsetKey []byte
|
||||
tipsetKeyCid []byte
|
||||
emitterAddr []byte
|
||||
eventIndex int
|
||||
messageCid []byte
|
||||
messageIndex int
|
||||
reverted bool
|
||||
flags []byte
|
||||
key string
|
||||
value []byte
|
||||
}
|
||||
|
||||
if err := q.Scan(
|
||||
&row.id,
|
||||
&row.height,
|
||||
&row.tipsetKey,
|
||||
&row.tipsetKeyCid,
|
||||
&row.emitterAddr,
|
||||
&row.eventIndex,
|
||||
&row.messageCid,
|
||||
&row.messageIndex,
|
||||
&row.reverted,
|
||||
&row.flags,
|
||||
&row.key,
|
||||
&row.value,
|
||||
); err != nil {
|
||||
return xerrors.Errorf("read prefill row: %w", err)
|
||||
}
|
||||
|
||||
if row.id != currentID {
|
||||
if ce != nil {
|
||||
ces = append(ces, ce)
|
||||
ce = nil
|
||||
// Unfortunately we can't easily incorporate the max results limit into the query due to the
|
||||
// unpredictable number of rows caused by joins
|
||||
// Break here to stop collecting rows
|
||||
if f.maxResults > 0 && len(ces) >= f.maxResults {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
currentID = row.id
|
||||
ce = &CollectedEvent{
|
||||
EventIdx: row.eventIndex,
|
||||
Reverted: row.reverted,
|
||||
Height: abi.ChainEpoch(row.height),
|
||||
MsgIdx: row.messageIndex,
|
||||
}
|
||||
|
||||
ce.EmitterAddr, err = address.NewFromBytes(row.emitterAddr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse emitter addr: %w", err)
|
||||
}
|
||||
|
||||
ce.TipSetKey, err = types.TipSetKeyFromBytes(row.tipsetKey)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse tipsetkey: %w", err)
|
||||
}
|
||||
|
||||
ce.MsgCid, err = cid.Cast(row.messageCid)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("parse message cid: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
ce.Entries = append(ce.Entries, types.EventEntry{
|
||||
Flags: row.flags[0],
|
||||
Key: row.key,
|
||||
Value: row.value,
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
if ce != nil {
|
||||
ces = append(ces, ce)
|
||||
}
|
||||
|
||||
if len(ces) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// collected event list is in inverted order since we selected only the most recent events
|
||||
// sort it into height order
|
||||
sort.Slice(ces, func(i, j int) bool { return ces[i].Height < ces[j].Height })
|
||||
f.setCollectedEvents(ces)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func trimLeadingZeros(b []byte) []byte {
|
||||
for i := range b {
|
||||
if b[i] != 0 {
|
||||
return b[i:]
|
||||
}
|
||||
}
|
||||
return []byte{}
|
||||
}
|
283
chain/events/filter/index_test.go
Normal file
283
chain/events/filter/index_test.go
Normal file
@ -0,0 +1,283 @@
|
||||
package filter
|
||||
|
||||
import (
|
||||
"context"
|
||||
pseudo "math/rand"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
func TestEventIndexPrefillFilter(t *testing.T) {
|
||||
rng := pseudo.New(pseudo.NewSource(299792458))
|
||||
a1 := randomF4Addr(t, rng)
|
||||
a2 := randomF4Addr(t, rng)
|
||||
|
||||
a1ID := abi.ActorID(1)
|
||||
a2ID := abi.ActorID(2)
|
||||
|
||||
addrMap := addressMap{}
|
||||
addrMap.add(a1ID, a1)
|
||||
addrMap.add(a2ID, a2)
|
||||
|
||||
ev1 := fakeEvent(
|
||||
a1ID,
|
||||
[]kv{
|
||||
{k: "type", v: []byte("approval")},
|
||||
{k: "signer", v: []byte("addr1")},
|
||||
},
|
||||
[]kv{
|
||||
{k: "amount", v: []byte("2988181")},
|
||||
},
|
||||
)
|
||||
|
||||
st := newStore()
|
||||
events := []*types.Event{ev1}
|
||||
em := executedMessage{
|
||||
msg: fakeMessage(randomF4Addr(t, rng), randomF4Addr(t, rng)),
|
||||
rct: fakeReceipt(t, rng, st, events),
|
||||
evs: events,
|
||||
}
|
||||
|
||||
events14000 := buildTipSetEvents(t, rng, 14000, em)
|
||||
cid14000, err := events14000.msgTs.Key().Cid()
|
||||
require.NoError(t, err, "tipset cid")
|
||||
|
||||
noCollectedEvents := []*CollectedEvent{}
|
||||
oneCollectedEvent := []*CollectedEvent{
|
||||
{
|
||||
Entries: ev1.Entries,
|
||||
EmitterAddr: a1,
|
||||
EventIdx: 0,
|
||||
Reverted: false,
|
||||
Height: 14000,
|
||||
TipSetKey: events14000.msgTs.Key(),
|
||||
MsgIdx: 0,
|
||||
MsgCid: em.msg.Cid(),
|
||||
},
|
||||
}
|
||||
|
||||
workDir, err := os.MkdirTemp("", "lotusevents")
|
||||
require.NoError(t, err, "create temporary work directory")
|
||||
|
||||
defer func() {
|
||||
_ = os.RemoveAll(workDir)
|
||||
}()
|
||||
t.Logf("using work dir %q", workDir)
|
||||
|
||||
dbPath := filepath.Join(workDir, "actorevents.db")
|
||||
|
||||
ei, err := NewEventIndex(dbPath)
|
||||
require.NoError(t, err, "create event index")
|
||||
if err := ei.CollectEvents(context.Background(), events14000, false, addrMap.ResolveAddress); err != nil {
|
||||
require.NoError(t, err, "collect events")
|
||||
}
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
filter *EventFilter
|
||||
te *TipSetEvents
|
||||
want []*CollectedEvent
|
||||
}{
|
||||
{
|
||||
name: "nomatch tipset min height",
|
||||
filter: &EventFilter{
|
||||
minHeight: 14001,
|
||||
maxHeight: -1,
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "nomatch tipset max height",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: 13999,
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "match tipset min height",
|
||||
filter: &EventFilter{
|
||||
minHeight: 14000,
|
||||
maxHeight: -1,
|
||||
},
|
||||
te: events14000,
|
||||
want: oneCollectedEvent,
|
||||
},
|
||||
{
|
||||
name: "match tipset cid",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
tipsetCid: cid14000,
|
||||
},
|
||||
te: events14000,
|
||||
want: oneCollectedEvent,
|
||||
},
|
||||
{
|
||||
name: "nomatch address",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
addresses: []address.Address{a2},
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "match address",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
addresses: []address.Address{a1},
|
||||
},
|
||||
te: events14000,
|
||||
want: oneCollectedEvent,
|
||||
},
|
||||
{
|
||||
name: "match one entry",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"type": {
|
||||
[]byte("approval"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: oneCollectedEvent,
|
||||
},
|
||||
{
|
||||
name: "match one entry with alternate values",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"type": {
|
||||
[]byte("cancel"),
|
||||
[]byte("propose"),
|
||||
[]byte("approval"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: oneCollectedEvent,
|
||||
},
|
||||
{
|
||||
name: "nomatch one entry by missing value",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"type": {
|
||||
[]byte("cancel"),
|
||||
[]byte("propose"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "nomatch one entry by missing key",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"method": {
|
||||
[]byte("approval"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "match one entry with multiple keys",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"type": {
|
||||
[]byte("approval"),
|
||||
},
|
||||
"signer": {
|
||||
[]byte("addr1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: oneCollectedEvent,
|
||||
},
|
||||
{
|
||||
name: "nomatch one entry with one mismatching key",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"type": {
|
||||
[]byte("approval"),
|
||||
},
|
||||
"approver": {
|
||||
[]byte("addr1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "nomatch one entry with one mismatching value",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"type": {
|
||||
[]byte("approval"),
|
||||
},
|
||||
"signer": {
|
||||
[]byte("addr2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
{
|
||||
name: "nomatch one entry with one unindexed key",
|
||||
filter: &EventFilter{
|
||||
minHeight: -1,
|
||||
maxHeight: -1,
|
||||
keys: map[string][][]byte{
|
||||
"amount": {
|
||||
[]byte("2988181"),
|
||||
},
|
||||
},
|
||||
},
|
||||
te: events14000,
|
||||
want: noCollectedEvents,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
tc := tc // appease lint
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
if err := ei.PrefillFilter(context.Background(), tc.filter); err != nil {
|
||||
require.NoError(t, err, "prefill filter events")
|
||||
}
|
||||
|
||||
coll := tc.filter.TakeCollectedEvents(context.Background())
|
||||
require.ElementsMatch(t, coll, tc.want)
|
||||
})
|
||||
}
|
||||
}
|
143
chain/events/filter/mempool.go
Normal file
143
chain/events/filter/mempool.go
Normal file
@ -0,0 +1,143 @@
|
||||
package filter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type MemPoolFilter struct {
|
||||
id types.FilterID
|
||||
maxResults int // maximum number of results to collect, 0 is unlimited
|
||||
ch chan<- interface{}
|
||||
|
||||
mu sync.Mutex
|
||||
collected []cid.Cid
|
||||
lastTaken time.Time
|
||||
}
|
||||
|
||||
var _ Filter = (*MemPoolFilter)(nil)
|
||||
|
||||
func (f *MemPoolFilter) ID() types.FilterID {
|
||||
return f.id
|
||||
}
|
||||
|
||||
func (f *MemPoolFilter) SetSubChannel(ch chan<- interface{}) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.ch = ch
|
||||
f.collected = nil
|
||||
}
|
||||
|
||||
func (f *MemPoolFilter) ClearSubChannel() {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.ch = nil
|
||||
}
|
||||
|
||||
func (f *MemPoolFilter) CollectMessage(ctx context.Context, msg *types.SignedMessage) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
||||
// if we have a subscription channel then push message to it
|
||||
if f.ch != nil {
|
||||
f.ch <- msg
|
||||
return
|
||||
}
|
||||
|
||||
if f.maxResults > 0 && len(f.collected) == f.maxResults {
|
||||
copy(f.collected, f.collected[1:])
|
||||
f.collected = f.collected[:len(f.collected)-1]
|
||||
}
|
||||
f.collected = append(f.collected, msg.Cid())
|
||||
}
|
||||
|
||||
func (f *MemPoolFilter) TakeCollectedMessages(context.Context) []cid.Cid {
|
||||
f.mu.Lock()
|
||||
collected := f.collected
|
||||
f.collected = nil
|
||||
f.lastTaken = time.Now().UTC()
|
||||
f.mu.Unlock()
|
||||
|
||||
return collected
|
||||
}
|
||||
|
||||
func (f *MemPoolFilter) LastTaken() time.Time {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.lastTaken
|
||||
}
|
||||
|
||||
type MemPoolFilterManager struct {
|
||||
MaxFilterResults int
|
||||
|
||||
mu sync.Mutex // guards mutations to filters
|
||||
filters map[types.FilterID]*MemPoolFilter
|
||||
}
|
||||
|
||||
func (m *MemPoolFilterManager) WaitForMpoolUpdates(ctx context.Context, ch <-chan api.MpoolUpdate) {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case u := <-ch:
|
||||
m.processUpdate(ctx, u)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MemPoolFilterManager) processUpdate(ctx context.Context, u api.MpoolUpdate) {
|
||||
// only process added messages
|
||||
if u.Type == api.MpoolRemove {
|
||||
return
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
if len(m.filters) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: could run this loop in parallel with errgroup if we expect large numbers of filters
|
||||
for _, f := range m.filters {
|
||||
f.CollectMessage(ctx, u.Message)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MemPoolFilterManager) Install(ctx context.Context) (*MemPoolFilter, error) {
|
||||
id, err := newFilterID()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("new filter id: %w", err)
|
||||
}
|
||||
|
||||
f := &MemPoolFilter{
|
||||
id: id,
|
||||
maxResults: m.MaxFilterResults,
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
if m.filters == nil {
|
||||
m.filters = make(map[types.FilterID]*MemPoolFilter)
|
||||
}
|
||||
m.filters[id] = f
|
||||
m.mu.Unlock()
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (m *MemPoolFilterManager) Remove(ctx context.Context, id types.FilterID) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if _, found := m.filters[id]; !found {
|
||||
return ErrFilterNotFound
|
||||
}
|
||||
delete(m.filters, id)
|
||||
return nil
|
||||
}
|
108
chain/events/filter/store.go
Normal file
108
chain/events/filter/store.go
Normal file
@ -0,0 +1,108 @@
|
||||
package filter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type Filter interface {
|
||||
ID() types.FilterID
|
||||
LastTaken() time.Time
|
||||
SetSubChannel(chan<- interface{})
|
||||
ClearSubChannel()
|
||||
}
|
||||
|
||||
type FilterStore interface {
|
||||
Add(context.Context, Filter) error
|
||||
Get(context.Context, types.FilterID) (Filter, error)
|
||||
Remove(context.Context, types.FilterID) error
|
||||
NotTakenSince(when time.Time) []Filter // returns a list of filters that have not had their collected results taken
|
||||
}
|
||||
|
||||
var (
|
||||
ErrFilterAlreadyRegistered = errors.New("filter already registered")
|
||||
ErrFilterNotFound = errors.New("filter not found")
|
||||
ErrMaximumNumberOfFilters = errors.New("maximum number of filters registered")
|
||||
)
|
||||
|
||||
func newFilterID() (types.FilterID, error) {
|
||||
rawid, err := uuid.NewRandom()
|
||||
if err != nil {
|
||||
return types.FilterID{}, xerrors.Errorf("new uuid: %w", err)
|
||||
}
|
||||
id := types.FilterID{}
|
||||
copy(id[:], rawid[:]) // uuid is 16 bytes, the last 16 bytes are zeroed
|
||||
return id, nil
|
||||
}
|
||||
|
||||
type memFilterStore struct {
|
||||
max int
|
||||
mu sync.Mutex
|
||||
filters map[types.FilterID]Filter
|
||||
}
|
||||
|
||||
var _ FilterStore = (*memFilterStore)(nil)
|
||||
|
||||
func NewMemFilterStore(maxFilters int) FilterStore {
|
||||
return &memFilterStore{
|
||||
max: maxFilters,
|
||||
filters: make(map[types.FilterID]Filter),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *memFilterStore) Add(_ context.Context, f Filter) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
if len(m.filters) >= m.max {
|
||||
return ErrMaximumNumberOfFilters
|
||||
}
|
||||
|
||||
if _, exists := m.filters[f.ID()]; exists {
|
||||
return ErrFilterAlreadyRegistered
|
||||
}
|
||||
m.filters[f.ID()] = f
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memFilterStore) Get(_ context.Context, id types.FilterID) (Filter, error) {
|
||||
m.mu.Lock()
|
||||
f, found := m.filters[id]
|
||||
m.mu.Unlock()
|
||||
if !found {
|
||||
return nil, ErrFilterNotFound
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (m *memFilterStore) Remove(_ context.Context, id types.FilterID) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
if _, exists := m.filters[id]; !exists {
|
||||
return ErrFilterNotFound
|
||||
}
|
||||
delete(m.filters, id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memFilterStore) NotTakenSince(when time.Time) []Filter {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
|
||||
var res []Filter
|
||||
for _, f := range m.filters {
|
||||
if f.LastTaken().Before(when) {
|
||||
res = append(res, f)
|
||||
}
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
130
chain/events/filter/tipset.go
Normal file
130
chain/events/filter/tipset.go
Normal file
@ -0,0 +1,130 @@
|
||||
package filter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
type TipSetFilter struct {
|
||||
id types.FilterID
|
||||
maxResults int // maximum number of results to collect, 0 is unlimited
|
||||
ch chan<- interface{}
|
||||
|
||||
mu sync.Mutex
|
||||
collected []types.TipSetKey
|
||||
lastTaken time.Time
|
||||
}
|
||||
|
||||
var _ Filter = (*TipSetFilter)(nil)
|
||||
|
||||
func (f *TipSetFilter) ID() types.FilterID {
|
||||
return f.id
|
||||
}
|
||||
|
||||
func (f *TipSetFilter) SetSubChannel(ch chan<- interface{}) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.ch = ch
|
||||
f.collected = nil
|
||||
}
|
||||
|
||||
func (f *TipSetFilter) ClearSubChannel() {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
f.ch = nil
|
||||
}
|
||||
|
||||
func (f *TipSetFilter) CollectTipSet(ctx context.Context, ts *types.TipSet) {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
|
||||
// if we have a subscription channel then push tipset to it
|
||||
if f.ch != nil {
|
||||
f.ch <- ts
|
||||
return
|
||||
}
|
||||
|
||||
if f.maxResults > 0 && len(f.collected) == f.maxResults {
|
||||
copy(f.collected, f.collected[1:])
|
||||
f.collected = f.collected[:len(f.collected)-1]
|
||||
}
|
||||
f.collected = append(f.collected, ts.Key())
|
||||
}
|
||||
|
||||
func (f *TipSetFilter) TakeCollectedTipSets(context.Context) []types.TipSetKey {
|
||||
f.mu.Lock()
|
||||
collected := f.collected
|
||||
f.collected = nil
|
||||
f.lastTaken = time.Now().UTC()
|
||||
f.mu.Unlock()
|
||||
|
||||
return collected
|
||||
}
|
||||
|
||||
func (f *TipSetFilter) LastTaken() time.Time {
|
||||
f.mu.Lock()
|
||||
defer f.mu.Unlock()
|
||||
return f.lastTaken
|
||||
}
|
||||
|
||||
type TipSetFilterManager struct {
|
||||
MaxFilterResults int
|
||||
|
||||
mu sync.Mutex // guards mutations to filters
|
||||
filters map[types.FilterID]*TipSetFilter
|
||||
}
|
||||
|
||||
func (m *TipSetFilterManager) Apply(ctx context.Context, from, to *types.TipSet) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if len(m.filters) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: could run this loop in parallel with errgroup
|
||||
for _, f := range m.filters {
|
||||
f.CollectTipSet(ctx, to)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *TipSetFilterManager) Revert(ctx context.Context, from, to *types.TipSet) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *TipSetFilterManager) Install(ctx context.Context) (*TipSetFilter, error) {
|
||||
id, err := newFilterID()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("new filter id: %w", err)
|
||||
}
|
||||
|
||||
f := &TipSetFilter{
|
||||
id: id,
|
||||
maxResults: m.MaxFilterResults,
|
||||
}
|
||||
|
||||
m.mu.Lock()
|
||||
if m.filters == nil {
|
||||
m.filters = make(map[types.FilterID]*TipSetFilter)
|
||||
}
|
||||
m.filters[id] = f
|
||||
m.mu.Unlock()
|
||||
|
||||
return f, nil
|
||||
}
|
||||
|
||||
func (m *TipSetFilterManager) Remove(ctx context.Context, id types.FilterID) error {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
if _, found := m.filters[id]; !found {
|
||||
return ErrFilterNotFound
|
||||
}
|
||||
delete(m.filters, id)
|
||||
return nil
|
||||
}
|
@ -468,10 +468,6 @@ func (cg *ChainGen) NextTipSetFromMinersWithMessagesAndNulls(base *types.TipSet,
|
||||
return nil, xerrors.Errorf("making a block for next tipset failed: %w", err)
|
||||
}
|
||||
|
||||
if err := cg.cs.PersistBlockHeaders(context.TODO(), fblk.Header); err != nil {
|
||||
return nil, xerrors.Errorf("chainstore AddBlock: %w", err)
|
||||
}
|
||||
|
||||
blks = append(blks, fblk)
|
||||
}
|
||||
}
|
||||
|
@ -123,12 +123,7 @@ Genesis: {
|
||||
|
||||
func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template genesis.Template) (*state.StateTree, map[address.Address]address.Address, error) {
|
||||
// Create empty state tree
|
||||
|
||||
cst := cbor.NewCborStore(bs)
|
||||
_, err := cst.Put(context.TODO(), []struct{}{})
|
||||
if err != nil {
|
||||
return nil, nil, xerrors.Errorf("putting empty object: %w", err)
|
||||
}
|
||||
|
||||
sv, err := state.VersionForNetwork(template.NetworkVersion)
|
||||
if err != nil {
|
||||
@ -238,15 +233,12 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
|
||||
|
||||
// Create accounts
|
||||
for _, info := range template.Accounts {
|
||||
|
||||
switch info.Type {
|
||||
case genesis.TAccount:
|
||||
if err := CreateAccountActor(ctx, cst, state, info, keyIDs, av); err != nil {
|
||||
return nil, nil, xerrors.Errorf("failed to create account actor: %w", err)
|
||||
}
|
||||
|
||||
case genesis.TMultisig:
|
||||
|
||||
ida, err := address.NewIDAddress(uint64(idStart))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@ -566,6 +558,11 @@ func MakeGenesisBlock(ctx context.Context, j journal.Journal, bs bstore.Blocksto
|
||||
return nil, xerrors.Errorf("make initial state tree failed: %w", err)
|
||||
}
|
||||
|
||||
// Set up the Ethereum Address Manager
|
||||
if err = SetupEAM(ctx, st, template.NetworkVersion); err != nil {
|
||||
return nil, xerrors.Errorf("failed to setup EAM: %w", err)
|
||||
}
|
||||
|
||||
stateroot, err := st.Flush(ctx)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("flush state tree failed: %w", err)
|
||||
@ -580,11 +577,27 @@ func MakeGenesisBlock(ctx context.Context, j journal.Journal, bs bstore.Blocksto
|
||||
return nil, xerrors.Errorf("failed to verify presealed data: %w", err)
|
||||
}
|
||||
|
||||
// setup Storage Miners
|
||||
stateroot, err = SetupStorageMiners(ctx, cs, sys, stateroot, template.Miners, template.NetworkVersion)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("setup miners failed: %w", err)
|
||||
}
|
||||
|
||||
st, err = state.LoadStateTree(st.Store, stateroot)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load updated state tree: %w", err)
|
||||
}
|
||||
|
||||
// Set up Eth null addresses.
|
||||
if _, err := SetupEthNullAddresses(ctx, st, template.NetworkVersion); err != nil {
|
||||
return nil, xerrors.Errorf("failed to set up Eth null addresses: %w", err)
|
||||
}
|
||||
|
||||
stateroot, err = st.Flush(ctx)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to flush state tree: %w", err)
|
||||
}
|
||||
|
||||
store := adt.WrapStore(ctx, cbor.NewCborStore(bs))
|
||||
emptyroot, err := adt0.MakeEmptyArray(store).Root()
|
||||
if err != nil {
|
||||
|
139
chain/gen/genesis/genesis_eth.go
Normal file
139
chain/gen/genesis/genesis_eth.go
Normal file
@ -0,0 +1,139 @@
|
||||
package genesis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
actorstypes "github.com/filecoin-project/go-state-types/actors"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
"github.com/filecoin-project/go-state-types/builtin"
|
||||
"github.com/filecoin-project/go-state-types/manifest"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/actors/adt"
|
||||
init_ "github.com/filecoin-project/lotus/chain/actors/builtin/init"
|
||||
"github.com/filecoin-project/lotus/chain/state"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
)
|
||||
|
||||
// EthNullAddresses are the Ethereum addresses we want to create zero-balanced EthAccounts in.
|
||||
// We may want to add null addresses for precompiles going forward.
|
||||
var EthNullAddresses = []string{
|
||||
"0x0000000000000000000000000000000000000000",
|
||||
}
|
||||
|
||||
func SetupEAM(_ context.Context, nst *state.StateTree, nv network.Version) error {
|
||||
av, err := actorstypes.VersionForNetwork(nv)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get actors version for network version %d: %w", nv, err)
|
||||
}
|
||||
|
||||
if av < actorstypes.Version10 {
|
||||
// Not defined before version 10; migration has to create.
|
||||
return nil
|
||||
}
|
||||
|
||||
codecid, ok := actors.GetActorCodeID(av, manifest.EamKey)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to get CodeCID for EAM during genesis")
|
||||
}
|
||||
|
||||
header := &types.Actor{
|
||||
Code: codecid,
|
||||
Head: vm.EmptyObjectCid,
|
||||
Balance: big.Zero(),
|
||||
Address: &builtin.EthereumAddressManagerActorAddr, // so that it can create ETH0
|
||||
}
|
||||
return nst.SetActor(builtin.EthereumAddressManagerActorAddr, header)
|
||||
}
|
||||
|
||||
// MakeEthNullAddressActor creates a null address actor at the specified Ethereum address.
|
||||
func MakeEthNullAddressActor(av actorstypes.Version, addr address.Address) (*types.Actor, error) {
|
||||
actcid, ok := actors.GetActorCodeID(av, manifest.EthAccountKey)
|
||||
if !ok {
|
||||
return nil, xerrors.Errorf("failed to get EthAccount actor code ID for actors version %d", av)
|
||||
}
|
||||
|
||||
act := &types.Actor{
|
||||
Code: actcid,
|
||||
Head: vm.EmptyObjectCid,
|
||||
Nonce: 0,
|
||||
Balance: big.Zero(),
|
||||
Address: &addr,
|
||||
}
|
||||
|
||||
return act, nil
|
||||
}
|
||||
|
||||
func SetupEthNullAddresses(ctx context.Context, st *state.StateTree, nv network.Version) ([]address.Address, error) {
|
||||
av, err := actorstypes.VersionForNetwork(nv)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to resolve actors version for network version %d: %w", av, err)
|
||||
}
|
||||
|
||||
if av < actorstypes.Version10 {
|
||||
// Not defined before version 10.
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var ethAddresses []ethtypes.EthAddress
|
||||
for _, addr := range EthNullAddresses {
|
||||
a, err := ethtypes.ParseEthAddress(addr)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to represent the 0x0 as an EthAddress: %w", err)
|
||||
}
|
||||
ethAddresses = append(ethAddresses, a)
|
||||
}
|
||||
|
||||
initAct, err := st.GetActor(builtin.InitActorAddr)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load init actor: %w", err)
|
||||
}
|
||||
|
||||
initState, err := init_.Load(adt.WrapStore(ctx, st.Store), initAct)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to load init actor state: %w", err)
|
||||
}
|
||||
|
||||
var ret []address.Address
|
||||
for _, ethAddr := range ethAddresses {
|
||||
// Place an EthAccount at the 0x0 Eth Null Address.
|
||||
f4Addr, err := ethAddr.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to compute Filecoin address for Eth addr 0x0: %w", err)
|
||||
}
|
||||
|
||||
idAddr, err := initState.MapAddressToNewID(f4Addr)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to map addr in init actor: %w", err)
|
||||
}
|
||||
|
||||
actState, err := MakeEthNullAddressActor(av, f4Addr)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to create EthAccount actor for null address: %w", err)
|
||||
}
|
||||
|
||||
if err := st.SetActor(idAddr, actState); err != nil {
|
||||
return nil, xerrors.Errorf("failed to set Eth Null Address EthAccount actor state: %w", err)
|
||||
}
|
||||
|
||||
ret = append(ret, idAddr)
|
||||
}
|
||||
|
||||
initAct.Head, err = st.Store.Put(ctx, initState)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to add init actor state to store: %w", err)
|
||||
}
|
||||
|
||||
if err := st.SetActor(builtin.InitActorAddr, initAct); err != nil {
|
||||
return nil, xerrors.Errorf("failed to set updated state for init actor: %w", err)
|
||||
}
|
||||
|
||||
return ret, nil
|
||||
}
|
@ -33,12 +33,13 @@ import (
|
||||
|
||||
"github.com/filecoin-project/lotus/api"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain"
|
||||
"github.com/filecoin-project/lotus/chain/consensus/filcns"
|
||||
"github.com/filecoin-project/lotus/chain/stmgr"
|
||||
"github.com/filecoin-project/lotus/chain/store"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/journal"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
@ -282,7 +283,7 @@ func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict, untrusted
|
||||
}
|
||||
|
||||
ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.RequiredFunds().Int)
|
||||
//ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.Value.Int)
|
||||
// ms.requiredFunds.Sub(ms.requiredFunds, exms.Message.Value.Int)
|
||||
}
|
||||
|
||||
if !has && strict && len(ms.msgs) >= maxActorPendingMessages {
|
||||
@ -298,7 +299,7 @@ func (ms *msgSet) add(m *types.SignedMessage, mp *MessagePool, strict, untrusted
|
||||
ms.nextNonce = nextNonce
|
||||
ms.msgs[m.Message.Nonce] = m
|
||||
ms.requiredFunds.Add(ms.requiredFunds, m.Message.RequiredFunds().Int)
|
||||
//ms.requiredFunds.Add(ms.requiredFunds, m.Message.Value.Int)
|
||||
// ms.requiredFunds.Add(ms.requiredFunds, m.Message.Value.Int)
|
||||
|
||||
return !has, nil
|
||||
}
|
||||
@ -318,7 +319,7 @@ func (ms *msgSet) rm(nonce uint64, applied bool) {
|
||||
}
|
||||
|
||||
ms.requiredFunds.Sub(ms.requiredFunds, m.Message.RequiredFunds().Int)
|
||||
//ms.requiredFunds.Sub(ms.requiredFunds, m.Message.Value.Int)
|
||||
// ms.requiredFunds.Sub(ms.requiredFunds, m.Message.Value.Int)
|
||||
delete(ms.msgs, nonce)
|
||||
|
||||
// adjust next nonce
|
||||
@ -344,7 +345,7 @@ func (ms *msgSet) getRequiredFunds(nonce uint64) types.BigInt {
|
||||
m, has := ms.msgs[nonce]
|
||||
if has {
|
||||
requiredFunds.Sub(requiredFunds, m.Message.RequiredFunds().Int)
|
||||
//requiredFunds.Sub(requiredFunds, m.Message.Value.Int)
|
||||
// requiredFunds.Sub(requiredFunds, m.Message.Value.Int)
|
||||
}
|
||||
|
||||
return types.BigInt{Int: requiredFunds}
|
||||
@ -476,7 +477,7 @@ func (mp *MessagePool) resolveToKey(ctx context.Context, addr address.Address) (
|
||||
}
|
||||
|
||||
// resolve the address
|
||||
ka, err := mp.api.StateAccountKeyAtFinality(ctx, addr, mp.curTs)
|
||||
ka, err := mp.api.StateDeterministicAddressAtFinality(ctx, addr, mp.curTs)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
@ -772,11 +773,9 @@ func sigCacheKey(m *types.SignedMessage) (string, error) {
|
||||
if len(m.Signature.Data) != ffi.SignatureBytes {
|
||||
return "", fmt.Errorf("bls signature incorrectly sized")
|
||||
}
|
||||
|
||||
hashCache := blake2b.Sum256(append(m.Cid().Bytes(), m.Signature.Data...))
|
||||
|
||||
return string(hashCache[:]), nil
|
||||
case crypto.SigTypeSecp256k1:
|
||||
case crypto.SigTypeSecp256k1, crypto.SigTypeDelegated:
|
||||
return string(m.Cid().Bytes()), nil
|
||||
default:
|
||||
return "", xerrors.Errorf("unrecognized signature type: %d", m.Signature.Type)
|
||||
@ -795,8 +794,8 @@ func (mp *MessagePool) VerifyMsgSig(m *types.SignedMessage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := sigs.Verify(&m.Signature, m.Message.From, m.Message.Cid().Bytes()); err != nil {
|
||||
return err
|
||||
if err := chain.AuthenticateMessage(m, m.Message.From); err != nil {
|
||||
return xerrors.Errorf("failed to validate signature: %w", err)
|
||||
}
|
||||
|
||||
mp.sigValCache.Add(sck, struct{}{})
|
||||
@ -816,7 +815,7 @@ func (mp *MessagePool) checkBalance(ctx context.Context, m *types.SignedMessage,
|
||||
}
|
||||
|
||||
// add Value for soft failure check
|
||||
//requiredFunds = types.BigAdd(requiredFunds, m.Message.Value)
|
||||
// requiredFunds = types.BigAdd(requiredFunds, m.Message.Value)
|
||||
|
||||
mset, ok, err := mp.getPendingMset(ctx, m.Message.From)
|
||||
if err != nil {
|
||||
@ -853,18 +852,32 @@ func (mp *MessagePool) addTs(ctx context.Context, m *types.SignedMessage, curTs
|
||||
mp.lk.Lock()
|
||||
defer mp.lk.Unlock()
|
||||
|
||||
senderAct, err := mp.api.GetActorAfter(m.Message.From, curTs)
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("failed to get sender actor: %w", err)
|
||||
}
|
||||
|
||||
// This message can only be included in the _next_ epoch and beyond, hence the +1.
|
||||
epoch := curTs.Height() + 1
|
||||
nv := mp.api.StateNetworkVersion(ctx, epoch)
|
||||
|
||||
// TODO: I'm not thrilled about depending on filcns here, but I prefer this to duplicating logic
|
||||
if !filcns.IsValidForSending(nv, senderAct) {
|
||||
return false, xerrors.Errorf("sender actor %s is not a valid top-level sender", m.Message.From)
|
||||
}
|
||||
|
||||
publish, err := mp.verifyMsgBeforeAdd(ctx, m, curTs, local)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, xerrors.Errorf("verify msg failed: %w", err)
|
||||
}
|
||||
|
||||
if err := mp.checkBalance(ctx, m, curTs); err != nil {
|
||||
return false, err
|
||||
return false, xerrors.Errorf("failed to check balance: %w", err)
|
||||
}
|
||||
|
||||
err = mp.addLocked(ctx, m, !local, untrusted)
|
||||
if err != nil {
|
||||
return false, err
|
||||
return false, xerrors.Errorf("failed to add locked: %w", err)
|
||||
}
|
||||
|
||||
if local {
|
||||
|
@ -155,14 +155,14 @@ func (tma *testMpoolAPI) GetActorAfter(addr address.Address, ts *types.TipSet) (
|
||||
}
|
||||
|
||||
return &types.Actor{
|
||||
Code: builtin2.StorageMarketActorCodeID,
|
||||
Code: builtin2.AccountActorCodeID,
|
||||
Nonce: nonce,
|
||||
Balance: balance,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (tma *testMpoolAPI) StateAccountKeyAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
if addr.Protocol() != address.BLS && addr.Protocol() != address.SECP256K1 {
|
||||
func (tma *testMpoolAPI) StateDeterministicAddressAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
if addr.Protocol() != address.BLS && addr.Protocol() != address.SECP256K1 && addr.Protocol() != address.Delegated {
|
||||
return address.Undef, fmt.Errorf("given address was not a key addr")
|
||||
}
|
||||
return addr, nil
|
||||
@ -214,7 +214,7 @@ func (tma *testMpoolAPI) ChainComputeBaseFee(ctx context.Context, ts *types.TipS
|
||||
|
||||
func assertNonce(t *testing.T, mp *MessagePool, addr address.Address, val uint64) {
|
||||
t.Helper()
|
||||
//stm: @CHAIN_MEMPOOL_GET_NONCE_001
|
||||
// stm: @CHAIN_MEMPOOL_GET_NONCE_001
|
||||
n, err := mp.GetNonce(context.TODO(), addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -233,7 +233,7 @@ func mustAdd(t *testing.T, mp *MessagePool, msg *types.SignedMessage) {
|
||||
}
|
||||
|
||||
func TestMessagePool(t *testing.T) {
|
||||
//stm: @CHAIN_MEMPOOL_GET_NONCE_001
|
||||
// stm: @CHAIN_MEMPOOL_GET_NONCE_001
|
||||
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
@ -336,7 +336,7 @@ func TestCheckMessageBig(t *testing.T) {
|
||||
Message: *msg,
|
||||
Signature: *sig,
|
||||
}
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
err = mp.Add(context.TODO(), sm)
|
||||
assert.ErrorIs(t, err, ErrMessageTooBig)
|
||||
}
|
||||
@ -378,10 +378,10 @@ func TestMessagePoolMessagesInEachBlock(t *testing.T) {
|
||||
tma.applyBlock(t, a)
|
||||
tsa := mock.TipSet(a)
|
||||
|
||||
//stm: @CHAIN_MEMPOOL_PENDING_001
|
||||
// stm: @CHAIN_MEMPOOL_PENDING_001
|
||||
_, _ = mp.Pending(context.TODO())
|
||||
|
||||
//stm: @CHAIN_MEMPOOL_SELECT_001
|
||||
// stm: @CHAIN_MEMPOOL_SELECT_001
|
||||
selm, _ := mp.SelectMessages(context.Background(), tsa, 1)
|
||||
if len(selm) == 0 {
|
||||
t.Fatal("should have returned the rest of the messages")
|
||||
@ -442,7 +442,7 @@ func TestRevertMessages(t *testing.T) {
|
||||
|
||||
assertNonce(t, mp, sender, 4)
|
||||
|
||||
//stm: @CHAIN_MEMPOOL_PENDING_001
|
||||
// stm: @CHAIN_MEMPOOL_PENDING_001
|
||||
p, _ := mp.Pending(context.TODO())
|
||||
fmt.Printf("%+v\n", p)
|
||||
if len(p) != 3 {
|
||||
@ -501,7 +501,7 @@ func TestPruningSimple(t *testing.T) {
|
||||
|
||||
mp.Prune()
|
||||
|
||||
//stm: @CHAIN_MEMPOOL_PENDING_001
|
||||
// stm: @CHAIN_MEMPOOL_PENDING_001
|
||||
msgs, _ := mp.Pending(context.TODO())
|
||||
if len(msgs) != 5 {
|
||||
t.Fatal("expected only 5 messages in pool, got: ", len(msgs))
|
||||
@ -544,7 +544,7 @@ func TestLoadLocal(t *testing.T) {
|
||||
msgs := make(map[cid.Cid]struct{})
|
||||
for i := 0; i < 10; i++ {
|
||||
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
cid, err := mp.Push(context.TODO(), m, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -561,7 +561,7 @@ func TestLoadLocal(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
//stm: @CHAIN_MEMPOOL_PENDING_001
|
||||
// stm: @CHAIN_MEMPOOL_PENDING_001
|
||||
pmsgs, _ := mp.Pending(context.TODO())
|
||||
if len(msgs) != len(pmsgs) {
|
||||
t.Fatalf("expected %d messages, but got %d", len(msgs), len(pmsgs))
|
||||
@ -617,7 +617,7 @@ func TestClearAll(t *testing.T) {
|
||||
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin2.StorageMarketActorCodeID, M: 2}]
|
||||
for i := 0; i < 10; i++ {
|
||||
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
_, err := mp.Push(context.TODO(), m, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -629,10 +629,10 @@ func TestClearAll(t *testing.T) {
|
||||
mustAdd(t, mp, m)
|
||||
}
|
||||
|
||||
//stm: @CHAIN_MEMPOOL_CLEAR_001
|
||||
// stm: @CHAIN_MEMPOOL_CLEAR_001
|
||||
mp.Clear(context.Background(), true)
|
||||
|
||||
//stm: @CHAIN_MEMPOOL_PENDING_001
|
||||
// stm: @CHAIN_MEMPOOL_PENDING_001
|
||||
pending, _ := mp.Pending(context.TODO())
|
||||
if len(pending) > 0 {
|
||||
t.Fatalf("cleared the mpool, but got %d pending messages", len(pending))
|
||||
@ -675,7 +675,7 @@ func TestClearNonLocal(t *testing.T) {
|
||||
gasLimit := gasguess.Costs[gasguess.CostKey{Code: builtin2.StorageMarketActorCodeID, M: 2}]
|
||||
for i := 0; i < 10; i++ {
|
||||
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
_, err := mp.Push(context.TODO(), m, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -687,10 +687,10 @@ func TestClearNonLocal(t *testing.T) {
|
||||
mustAdd(t, mp, m)
|
||||
}
|
||||
|
||||
//stm: @CHAIN_MEMPOOL_CLEAR_001
|
||||
// stm: @CHAIN_MEMPOOL_CLEAR_001
|
||||
mp.Clear(context.Background(), false)
|
||||
|
||||
//stm: @CHAIN_MEMPOOL_PENDING_001
|
||||
// stm: @CHAIN_MEMPOOL_PENDING_001
|
||||
pending, _ := mp.Pending(context.TODO())
|
||||
if len(pending) != 10 {
|
||||
t.Fatalf("expected 10 pending messages, but got %d instead", len(pending))
|
||||
@ -748,7 +748,7 @@ func TestUpdates(t *testing.T) {
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
m := makeTestMessage(w1, a1, a2, uint64(i), gasLimit, uint64(i+1))
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
_, err := mp.Push(context.TODO(), m, true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@ -772,7 +772,7 @@ func TestUpdates(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMessageBelowMinGasFee(t *testing.T) {
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@ -818,7 +818,7 @@ func TestMessageBelowMinGasFee(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMessageValueTooHigh(t *testing.T) {
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@ -866,7 +866,7 @@ func TestMessageValueTooHigh(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestMessageSignatureInvalid(t *testing.T) {
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@ -911,7 +911,7 @@ func TestMessageSignatureInvalid(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAddMessageTwice(t *testing.T) {
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@ -957,7 +957,7 @@ func TestAddMessageTwice(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAddMessageTwiceNonceGap(t *testing.T) {
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@ -1011,7 +1011,7 @@ func TestAddMessageTwiceCidDiff(t *testing.T) {
|
||||
// Create message with different data, so CID is different
|
||||
sm2 := makeTestMessage(w, from, to, 0, 50_000_001, minimumBaseFee.Uint64())
|
||||
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// then try to add message again
|
||||
err = mp.Add(context.TODO(), sm2)
|
||||
// assert.Contains(t, err.Error(), "replace by fee has too low GasPremium")
|
||||
@ -1020,7 +1020,7 @@ func TestAddMessageTwiceCidDiff(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestAddMessageTwiceCidDiffReplaced(t *testing.T) {
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@ -1049,7 +1049,7 @@ func TestAddMessageTwiceCidDiffReplaced(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRemoveMessage(t *testing.T) {
|
||||
//stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
// stm: @CHAIN_MEMPOOL_PUSH_001
|
||||
tma := newTestMpoolAPI()
|
||||
|
||||
w, err := wallet.NewWallet(wallet.NewMemKeyStore())
|
||||
@ -1071,11 +1071,11 @@ func TestRemoveMessage(t *testing.T) {
|
||||
sm := makeTestMessage(w, from, to, 0, 50_000_000, minimumBaseFee.Uint64())
|
||||
mustAdd(t, mp, sm)
|
||||
|
||||
//stm: @CHAIN_MEMPOOL_REMOVE_001
|
||||
// stm: @CHAIN_MEMPOOL_REMOVE_001
|
||||
// remove message for sender
|
||||
mp.Remove(context.TODO(), from, sm.Message.Nonce, true)
|
||||
|
||||
//stm: @CHAIN_MEMPOOL_PENDING_FOR_001
|
||||
// stm: @CHAIN_MEMPOOL_PENDING_FOR_001
|
||||
// check messages in pool: should be none present
|
||||
msgs := mp.pendingFor(context.TODO(), from)
|
||||
assert.Len(t, msgs, 0)
|
||||
|
@ -28,7 +28,7 @@ type Provider interface {
|
||||
PutMessage(ctx context.Context, m types.ChainMsg) (cid.Cid, error)
|
||||
PubSubPublish(string, []byte) error
|
||||
GetActorAfter(address.Address, *types.TipSet) (*types.Actor, error)
|
||||
StateAccountKeyAtFinality(context.Context, address.Address, *types.TipSet) (address.Address, error)
|
||||
StateDeterministicAddressAtFinality(context.Context, address.Address, *types.TipSet) (address.Address, error)
|
||||
StateNetworkVersion(context.Context, abi.ChainEpoch) network.Version
|
||||
MessagesForBlock(context.Context, *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error)
|
||||
MessagesForTipset(context.Context, *types.TipSet) ([]types.ChainMsg, error)
|
||||
@ -74,7 +74,7 @@ func (mpp *mpoolProvider) PutMessage(ctx context.Context, m types.ChainMsg) (cid
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) PubSubPublish(k string, v []byte) error {
|
||||
return mpp.ps.Publish(k, v) //nolint
|
||||
return mpp.ps.Publish(k, v) // nolint
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) GetActorAfter(addr address.Address, ts *types.TipSet) (*types.Actor, error) {
|
||||
@ -102,8 +102,8 @@ func (mpp *mpoolProvider) GetActorAfter(addr address.Address, ts *types.TipSet)
|
||||
return st.GetActor(addr)
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) StateAccountKeyAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
return mpp.sm.ResolveToKeyAddressAtFinality(ctx, addr, ts)
|
||||
func (mpp *mpoolProvider) StateDeterministicAddressAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
return mpp.sm.ResolveToDeterministicAddressAtFinality(ctx, addr, ts)
|
||||
}
|
||||
|
||||
func (mpp *mpoolProvider) StateNetworkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {
|
||||
|
@ -97,7 +97,7 @@ func (sm *selectedMessages) tryToAdd(mc *msgChain) bool {
|
||||
sm.msgs = append(sm.msgs, mc.msgs...)
|
||||
sm.blsLimit -= l
|
||||
sm.gasLimit -= mc.gasLimit
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 {
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated {
|
||||
if sm.secpLimit < l {
|
||||
return false
|
||||
}
|
||||
@ -123,7 +123,7 @@ func (sm *selectedMessages) tryToAddWithDeps(mc *msgChain, mp *MessagePool, base
|
||||
|
||||
if mc.sigType == crypto.SigTypeBLS {
|
||||
smMsgLimit = sm.blsLimit
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 {
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated {
|
||||
smMsgLimit = sm.secpLimit
|
||||
} else {
|
||||
return false
|
||||
@ -174,7 +174,7 @@ func (sm *selectedMessages) tryToAddWithDeps(mc *msgChain, mp *MessagePool, base
|
||||
|
||||
if mc.sigType == crypto.SigTypeBLS {
|
||||
sm.blsLimit -= chainMsgLimit
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 {
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated {
|
||||
sm.secpLimit -= chainMsgLimit
|
||||
}
|
||||
|
||||
@ -187,7 +187,7 @@ func (sm *selectedMessages) trimChain(mc *msgChain, mp *MessagePool, baseFee typ
|
||||
if msgLimit > sm.blsLimit {
|
||||
msgLimit = sm.blsLimit
|
||||
}
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 {
|
||||
} else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated {
|
||||
if msgLimit > sm.secpLimit {
|
||||
msgLimit = sm.secpLimit
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types/mock"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
)
|
||||
|
||||
|
53
chain/signatures.go
Normal file
53
chain/signatures.go
Normal file
@ -0,0 +1,53 @@
|
||||
package chain
|
||||
|
||||
import (
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
)
|
||||
|
||||
// AuthenticateMessage authenticates the message by verifying that the supplied
|
||||
// SignedMessage was signed by the indicated Address, computing the correct
|
||||
// signature payload depending on the signature type. The supplied Address type
|
||||
// must be recognized by the registered verifier for the signature type.
|
||||
func AuthenticateMessage(msg *types.SignedMessage, signer address.Address) error {
|
||||
var digest []byte
|
||||
|
||||
typ := msg.Signature.Type
|
||||
switch typ {
|
||||
case crypto.SigTypeDelegated:
|
||||
txArgs, err := ethtypes.NewEthTxArgsFromMessage(&msg.Message)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to reconstruct eth transaction: %w", err)
|
||||
}
|
||||
msg, err := txArgs.ToRlpUnsignedMsg()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to repack eth rlp message: %w", err)
|
||||
}
|
||||
digest = msg
|
||||
default:
|
||||
digest = msg.Message.Cid().Bytes()
|
||||
}
|
||||
|
||||
if err := sigs.Verify(&msg.Signature, signer, digest); err != nil {
|
||||
return xerrors.Errorf("message %s has invalid signature (type %d): %w", msg.Cid(), typ, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValidSecpkSigType checks that a signature type is valid for the network
|
||||
// version, for a "secpk" message.
|
||||
func IsValidSecpkSigType(nv network.Version, typ crypto.SigType) bool {
|
||||
switch {
|
||||
case nv < network.Version18:
|
||||
return typ == crypto.SigTypeSecp256k1
|
||||
default:
|
||||
return typ == crypto.SigTypeSecp256k1 || typ == crypto.SigTypeDelegated
|
||||
}
|
||||
}
|
@ -48,7 +48,7 @@ func GetMinerWorkerRaw(ctx context.Context, sm *StateManager, st cid.Cid, maddr
|
||||
return address.Undef, xerrors.Errorf("failed to load actor info: %w", err)
|
||||
}
|
||||
|
||||
return vm.ResolveToKeyAddr(state, sm.cs.ActorStore(ctx), info.Worker)
|
||||
return vm.ResolveToDeterministicAddr(state, sm.cs.ActorStore(ctx), info.Worker)
|
||||
}
|
||||
|
||||
func GetPower(ctx context.Context, sm *StateManager, ts *types.TipSet, maddr address.Address) (power.Claim, power.Claim, bool, error) {
|
||||
@ -381,7 +381,7 @@ func MinerGetBaseInfo(ctx context.Context, sm *StateManager, bcs beacon.Schedule
|
||||
return nil, err
|
||||
}
|
||||
|
||||
worker, err := sm.ResolveToKeyAddress(ctx, info.Worker, ts)
|
||||
worker, err := sm.ResolveToDeterministicAddress(ctx, info.Worker, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("resolving worker address: %w", err)
|
||||
}
|
||||
|
@ -143,6 +143,7 @@ func (sm *StateManager) callInternal(ctx context.Context, msg *types.Message, pr
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: stateCid,
|
||||
Epoch: vmHeight,
|
||||
Timestamp: ts.MinTimestamp(),
|
||||
Rand: rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon, nvGetter),
|
||||
Bstore: buffStore,
|
||||
Actors: sm.tsExec.NewActorRegistry(),
|
||||
@ -199,7 +200,7 @@ func (sm *StateManager) callInternal(ctx context.Context, msg *types.Message, pr
|
||||
var ret *vm.ApplyRet
|
||||
var gasInfo api.MsgGasCost
|
||||
if checkGas {
|
||||
fromKey, err := sm.ResolveToKeyAddress(ctx, msg.From, ts)
|
||||
fromKey, err := sm.ResolveToDeterministicAddress(ctx, msg.From, ts)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not resolve key: %w", err)
|
||||
}
|
||||
@ -217,6 +218,24 @@ func (sm *StateManager) callInternal(ctx context.Context, msg *types.Message, pr
|
||||
Data: make([]byte, 65),
|
||||
},
|
||||
}
|
||||
case address.Delegated:
|
||||
msgApply = &types.SignedMessage{
|
||||
Message: *msg,
|
||||
Signature: crypto.Signature{
|
||||
Type: crypto.SigTypeDelegated,
|
||||
Data: make([]byte, 65),
|
||||
},
|
||||
}
|
||||
default:
|
||||
// XXX: Hack to make sending from f099 (and others) "just work".
|
||||
// REMOVE ME.
|
||||
msgApply = &types.SignedMessage{
|
||||
Message: *msg,
|
||||
Signature: crypto.Signature{
|
||||
Type: crypto.SigTypeSecp256k1,
|
||||
Data: make([]byte, 65),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
ret, err = vmi.ApplyMessage(ctx, msgApply)
|
||||
|
@ -48,7 +48,7 @@ func (s *RPCStateManager) LookupID(ctx context.Context, addr address.Address, ts
|
||||
return s.gapi.StateLookupID(ctx, addr, ts.Key())
|
||||
}
|
||||
|
||||
func (s *RPCStateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
func (s *RPCStateManager) ResolveToDeterministicAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
return s.gapi.StateAccountKey(ctx, addr, ts.Key())
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ type StateManagerAPI interface {
|
||||
GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error)
|
||||
LoadActorTsk(ctx context.Context, addr address.Address, tsk types.TipSetKey) (*types.Actor, error)
|
||||
LookupID(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error)
|
||||
ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error)
|
||||
ResolveToDeterministicAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error)
|
||||
}
|
||||
|
||||
type versionSpec struct {
|
||||
@ -207,11 +207,11 @@ func (sm *StateManager) Beacon() beacon.Schedule {
|
||||
return sm.beacon
|
||||
}
|
||||
|
||||
// ResolveToKeyAddress is similar to `vm.ResolveToKeyAddr` but does not allow `Actor` type of addresses.
|
||||
// ResolveToDeterministicAddress is similar to `vm.ResolveToDeterministicAddr` but does not allow `Actor` type of addresses.
|
||||
// Uses the `TipSet` `ts` to generate the VM state.
|
||||
func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
func (sm *StateManager) ResolveToDeterministicAddress(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
switch addr.Protocol() {
|
||||
case address.BLS, address.SECP256K1:
|
||||
case address.BLS, address.SECP256K1, address.Delegated:
|
||||
return addr, nil
|
||||
case address.Actor:
|
||||
return address.Undef, xerrors.New("cannot resolve actor address to key address")
|
||||
@ -230,7 +230,7 @@ func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Ad
|
||||
return address.Undef, xerrors.Errorf("failed to load parent state tree at tipset %s: %w", ts.Parents(), err)
|
||||
}
|
||||
|
||||
resolved, err := vm.ResolveToKeyAddr(tree, cst, addr)
|
||||
resolved, err := vm.ResolveToDeterministicAddr(tree, cst, addr)
|
||||
if err == nil {
|
||||
return resolved, nil
|
||||
}
|
||||
@ -246,14 +246,14 @@ func (sm *StateManager) ResolveToKeyAddress(ctx context.Context, addr address.Ad
|
||||
return address.Undef, xerrors.Errorf("failed to load state tree at tipset %s: %w", ts, err)
|
||||
}
|
||||
|
||||
return vm.ResolveToKeyAddr(tree, cst, addr)
|
||||
return vm.ResolveToDeterministicAddr(tree, cst, addr)
|
||||
}
|
||||
|
||||
// ResolveToKeyAddressAtFinality is similar to stmgr.ResolveToKeyAddress but fails if the ID address being resolved isn't reorg-stable yet.
|
||||
// ResolveToDeterministicAddressAtFinality is similar to stmgr.ResolveToDeterministicAddress but fails if the ID address being resolved isn't reorg-stable yet.
|
||||
// It should not be used for consensus-critical subsystems.
|
||||
func (sm *StateManager) ResolveToKeyAddressAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
func (sm *StateManager) ResolveToDeterministicAddressAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
|
||||
switch addr.Protocol() {
|
||||
case address.BLS, address.SECP256K1:
|
||||
case address.BLS, address.SECP256K1, address.Delegated:
|
||||
return addr, nil
|
||||
case address.Actor:
|
||||
return address.Undef, xerrors.New("cannot resolve actor address to key address")
|
||||
@ -287,7 +287,7 @@ func (sm *StateManager) ResolveToKeyAddressAtFinality(ctx context.Context, addr
|
||||
}
|
||||
}
|
||||
|
||||
resolved, err := vm.ResolveToKeyAddr(tree, cst, addr)
|
||||
resolved, err := vm.ResolveToDeterministicAddr(tree, cst, addr)
|
||||
if err == nil {
|
||||
return resolved, nil
|
||||
}
|
||||
@ -296,7 +296,7 @@ func (sm *StateManager) ResolveToKeyAddressAtFinality(ctx context.Context, addr
|
||||
}
|
||||
|
||||
func (sm *StateManager) GetBlsPublicKey(ctx context.Context, addr address.Address, ts *types.TipSet) (pubk []byte, err error) {
|
||||
kaddr, err := sm.ResolveToKeyAddress(ctx, addr, ts)
|
||||
kaddr, err := sm.ResolveToDeterministicAddress(ctx, addr, ts)
|
||||
if err != nil {
|
||||
return pubk, xerrors.Errorf("failed to resolve address to key address: %w", err)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package stmgr
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
@ -27,6 +28,8 @@ import (
|
||||
"github.com/filecoin-project/lotus/node/modules/dtypes"
|
||||
)
|
||||
|
||||
var ErrMetadataNotFound = errors.New("actor metadata not found")
|
||||
|
||||
func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, method abi.MethodNum, ts *types.TipSet) (cbg.CBORUnmarshaler, error) {
|
||||
act, err := sm.LoadActor(ctx, to, ts)
|
||||
if err != nil {
|
||||
@ -35,7 +38,7 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me
|
||||
|
||||
m, found := sm.tsExec.NewActorRegistry().Methods[act.Code][method]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("unknown method %d for actor %s", method, act.Code)
|
||||
return nil, fmt.Errorf("unknown method %d for actor %s: %w", method, act.Code, ErrMetadataNotFound)
|
||||
}
|
||||
|
||||
return reflect.New(m.Ret.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
||||
@ -44,7 +47,7 @@ func GetReturnType(ctx context.Context, sm *StateManager, to address.Address, me
|
||||
func GetParamType(ar *vm.ActorRegistry, actCode cid.Cid, method abi.MethodNum) (cbg.CBORUnmarshaler, error) {
|
||||
m, found := ar.Methods[actCode][method]
|
||||
if !found {
|
||||
return nil, fmt.Errorf("unknown method %d for actor %s", method, actCode)
|
||||
return nil, fmt.Errorf("unknown method %d for actor %s: %w", method, actCode, ErrMetadataNotFound)
|
||||
}
|
||||
return reflect.New(m.Params.Elem()).Interface().(cbg.CBORUnmarshaler), nil
|
||||
}
|
||||
@ -87,6 +90,7 @@ func ComputeState(ctx context.Context, sm *StateManager, height abi.ChainEpoch,
|
||||
vmopt := &vm.VMOpts{
|
||||
StateBase: base,
|
||||
Epoch: height,
|
||||
Timestamp: ts.MinTimestamp(),
|
||||
Rand: r,
|
||||
Bstore: sm.cs.StateBlockstore(),
|
||||
Actors: sm.tsExec.NewActorRegistry(),
|
||||
|
@ -1,6 +1,7 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@ -375,10 +376,8 @@ func (cs *ChainStore) SetGenesis(ctx context.Context, b *types.BlockHeader) erro
|
||||
}
|
||||
|
||||
func (cs *ChainStore) PutTipSet(ctx context.Context, ts *types.TipSet) error {
|
||||
for _, b := range ts.Blocks() {
|
||||
if err := cs.PersistBlockHeaders(ctx, b); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cs.PersistTipset(ctx, ts); err != nil {
|
||||
return xerrors.Errorf("failed to persist tipset: %w", err)
|
||||
}
|
||||
|
||||
expanded, err := cs.expandTipset(ctx, ts.Blocks()[0])
|
||||
@ -646,7 +645,7 @@ func (cs *ChainStore) takeHeaviestTipSet(ctx context.Context, ts *types.TipSet)
|
||||
|
||||
if err := cs.writeHead(ctx, ts); err != nil {
|
||||
log.Errorf("failed to write chain head: %s", err)
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
@ -958,7 +957,24 @@ func (cs *ChainStore) AddToTipSetTracker(ctx context.Context, b *types.BlockHead
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) PersistBlockHeaders(ctx context.Context, b ...*types.BlockHeader) error {
|
||||
func (cs *ChainStore) PersistTipset(ctx context.Context, ts *types.TipSet) error {
|
||||
if err := cs.persistBlockHeaders(ctx, ts.Blocks()...); err != nil {
|
||||
return xerrors.Errorf("failed to persist block headers: %w", err)
|
||||
}
|
||||
|
||||
tsBlk, err := ts.Key().ToStorageBlock()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to get tipset key block: %w", err)
|
||||
}
|
||||
|
||||
if err = cs.chainLocalBlockstore.Put(ctx, tsBlk); err != nil {
|
||||
return xerrors.Errorf("failed to put tipset key block: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) persistBlockHeaders(ctx context.Context, b ...*types.BlockHeader) error {
|
||||
sbs := make([]block.Block, len(b))
|
||||
|
||||
for i, header := range b {
|
||||
@ -1026,23 +1042,6 @@ func (cs *ChainStore) expandTipset(ctx context.Context, b *types.BlockHeader) (*
|
||||
return types.NewTipSet(all)
|
||||
}
|
||||
|
||||
func (cs *ChainStore) AddBlock(ctx context.Context, b *types.BlockHeader) error {
|
||||
if err := cs.PersistBlockHeaders(ctx, b); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ts, err := cs.expandTipset(ctx, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cs.MaybeTakeHeavierTipSet(ctx, ts); err != nil {
|
||||
return xerrors.Errorf("MaybeTakeHeavierTipSet failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetGenesis(ctx context.Context) (*types.BlockHeader, error) {
|
||||
data, err := cs.metadataDs.Get(ctx, dstore.NewKey("0"))
|
||||
if err != nil {
|
||||
@ -1165,6 +1164,24 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
|
||||
return cs.LoadTipSet(ctx, lbts.Parents())
|
||||
}
|
||||
|
||||
func (cs *ChainStore) GetTipSetByCid(ctx context.Context, c cid.Cid) (*types.TipSet, error) {
|
||||
blk, err := cs.chainBlockstore.Get(ctx, c)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("cannot find tipset with cid %s: %w", c, err)
|
||||
}
|
||||
|
||||
tsk := new(types.TipSetKey)
|
||||
if err := tsk.UnmarshalCBOR(bytes.NewReader(blk.RawData())); err != nil {
|
||||
return nil, xerrors.Errorf("cannot unmarshal block into tipset key: %w", err)
|
||||
}
|
||||
|
||||
ts, err := cs.GetTipSetFromKey(ctx, *tsk)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("cannot get tipset from key: %w", err)
|
||||
}
|
||||
return ts, nil
|
||||
}
|
||||
|
||||
func (cs *ChainStore) Weight(ctx context.Context, hts *types.TipSet) (types.BigInt, error) { // todo remove
|
||||
return cs.weight(ctx, cs.StateBlockstore(), hts)
|
||||
}
|
||||
|
@ -228,7 +228,7 @@ func (syncer *Syncer) InformNewHead(from peer.ID, fts *store.FullTipSet) bool {
|
||||
|
||||
// TODO: IMPORTANT(GARBAGE) this needs to be put in the 'temporary' side of
|
||||
// the blockstore
|
||||
if err := syncer.store.PersistBlockHeaders(ctx, fts.TipSet().Blocks()...); err != nil {
|
||||
if err := syncer.store.PersistTipset(ctx, fts.TipSet()); err != nil {
|
||||
log.Warn("failed to persist incoming block header: ", err)
|
||||
return false
|
||||
}
|
||||
@ -1145,7 +1145,7 @@ func persistMessages(ctx context.Context, bs bstore.Blockstore, bst *exchange.Co
|
||||
}
|
||||
}
|
||||
for _, m := range bst.Secpk {
|
||||
if m.Signature.Type != crypto.SigTypeSecp256k1 {
|
||||
if m.Signature.Type != crypto.SigTypeSecp256k1 && m.Signature.Type != crypto.SigTypeDelegated {
|
||||
return xerrors.Errorf("unknown signature type on message %s: %q", m.Cid(), m.Signature.Type)
|
||||
}
|
||||
//log.Infof("putting secp256k1 message: %s", m.Cid())
|
||||
@ -1198,16 +1198,13 @@ func (syncer *Syncer) collectChain(ctx context.Context, ts *types.TipSet, hts *t
|
||||
|
||||
ss.SetStage(api.StagePersistHeaders)
|
||||
|
||||
toPersist := make([]*types.BlockHeader, 0, len(headers)*int(build.BlocksPerEpoch))
|
||||
for _, ts := range headers {
|
||||
toPersist = append(toPersist, ts.Blocks()...)
|
||||
}
|
||||
if err := syncer.store.PersistBlockHeaders(ctx, toPersist...); err != nil {
|
||||
err = xerrors.Errorf("failed to persist synced blocks to the chainstore: %w", err)
|
||||
if err := syncer.store.PersistTipset(ctx, ts); err != nil {
|
||||
err = xerrors.Errorf("failed to persist synced tipset to the chainstore: %w", err)
|
||||
ss.Error(err)
|
||||
return err
|
||||
}
|
||||
toPersist = nil
|
||||
}
|
||||
|
||||
ss.SetStage(api.StageMessages)
|
||||
|
||||
|
@ -306,13 +306,13 @@ func (tu *syncTestUtil) addSourceNode(gen int) {
|
||||
require.NoError(tu.t, err)
|
||||
tu.t.Cleanup(func() { _ = stop(context.Background()) })
|
||||
|
||||
lastTs := blocks[len(blocks)-1].Blocks
|
||||
for _, lastB := range lastTs {
|
||||
lastTs := blocks[len(blocks)-1]
|
||||
cs := out.(*impl.FullNodeAPI).ChainAPI.Chain
|
||||
for _, lastB := range lastTs.Blocks {
|
||||
require.NoError(tu.t, cs.AddToTipSetTracker(context.Background(), lastB.Header))
|
||||
err = cs.AddBlock(tu.ctx, lastB.Header)
|
||||
require.NoError(tu.t, err)
|
||||
}
|
||||
err = cs.PutTipSet(tu.ctx, lastTs.TipSet())
|
||||
require.NoError(tu.t, err)
|
||||
|
||||
tu.genesis = genesis
|
||||
tu.blocks = blocks
|
||||
|
@ -26,7 +26,7 @@ type ActorV5 struct {
|
||||
Head cid.Cid
|
||||
Nonce uint64
|
||||
Balance BigInt
|
||||
// Predictable Address
|
||||
// Deterministic Address.
|
||||
Address *address.Address
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,6 @@ import (
|
||||
address "github.com/filecoin-project/go-address"
|
||||
abi "github.com/filecoin-project/go-state-types/abi"
|
||||
crypto "github.com/filecoin-project/go-state-types/crypto"
|
||||
exitcode "github.com/filecoin-project/go-state-types/exitcode"
|
||||
proof "github.com/filecoin-project/go-state-types/proof"
|
||||
)
|
||||
|
||||
@ -1289,154 +1288,6 @@ func (t *ActorV5) UnmarshalCBOR(r io.Reader) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufMessageReceipt = []byte{131}
|
||||
|
||||
func (t *MessageReceipt) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
|
||||
cw := cbg.NewCborWriter(w)
|
||||
|
||||
if _, err := cw.Write(lengthBufMessageReceipt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.ExitCode (exitcode.ExitCode) (int64)
|
||||
if t.ExitCode >= 0 {
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.ExitCode)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.ExitCode-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.Return ([]uint8) (slice)
|
||||
if len(t.Return) > cbg.ByteArrayMaxLen {
|
||||
return xerrors.Errorf("Byte array in field t.Return was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Return))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := cw.Write(t.Return[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.GasUsed (int64) (int64)
|
||||
if t.GasUsed >= 0 {
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.GasUsed)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.GasUsed-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *MessageReceipt) UnmarshalCBOR(r io.Reader) (err error) {
|
||||
*t = MessageReceipt{}
|
||||
|
||||
cr := cbg.NewCborReader(r)
|
||||
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
}()
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("cbor input should be of type array")
|
||||
}
|
||||
|
||||
if extra != 3 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.ExitCode (exitcode.ExitCode) (int64)
|
||||
{
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.ExitCode = exitcode.ExitCode(extraI)
|
||||
}
|
||||
// t.Return ([]uint8) (slice)
|
||||
|
||||
maj, extra, err = cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.ByteArrayMaxLen {
|
||||
return fmt.Errorf("t.Return: byte array too large (%d)", extra)
|
||||
}
|
||||
if maj != cbg.MajByteString {
|
||||
return fmt.Errorf("expected byte array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.Return = make([]uint8, extra)
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(cr, t.Return[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
// t.GasUsed (int64) (int64)
|
||||
{
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.GasUsed = int64(extraI)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufBlockMsg = []byte{131}
|
||||
|
||||
func (t *BlockMsg) MarshalCBOR(w io.Writer) error {
|
||||
@ -1986,3 +1837,224 @@ func (t *StateInfo0) UnmarshalCBOR(r io.Reader) (err error) {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufEvent = []byte{130}
|
||||
|
||||
func (t *Event) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
|
||||
cw := cbg.NewCborWriter(w)
|
||||
|
||||
if _, err := cw.Write(lengthBufEvent); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Emitter (abi.ActorID) (uint64)
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Emitter)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Entries ([]types.EventEntry) (slice)
|
||||
if len(t.Entries) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Slice value in field t.Entries was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajArray, uint64(len(t.Entries))); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, v := range t.Entries {
|
||||
if err := v.MarshalCBOR(cw); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Event) UnmarshalCBOR(r io.Reader) (err error) {
|
||||
*t = Event{}
|
||||
|
||||
cr := cbg.NewCborReader(r)
|
||||
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
}()
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("cbor input should be of type array")
|
||||
}
|
||||
|
||||
if extra != 2 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.Emitter (abi.ActorID) (uint64)
|
||||
|
||||
{
|
||||
|
||||
maj, extra, err = cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint64 field")
|
||||
}
|
||||
t.Emitter = abi.ActorID(extra)
|
||||
|
||||
}
|
||||
// t.Entries ([]types.EventEntry) (slice)
|
||||
|
||||
maj, extra, err = cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.MaxLength {
|
||||
return fmt.Errorf("t.Entries: array too large (%d)", extra)
|
||||
}
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("expected cbor array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.Entries = make([]EventEntry, extra)
|
||||
}
|
||||
|
||||
for i := 0; i < int(extra); i++ {
|
||||
|
||||
var v EventEntry
|
||||
if err := v.UnmarshalCBOR(cr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Entries[i] = v
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufEventEntry = []byte{131}
|
||||
|
||||
func (t *EventEntry) MarshalCBOR(w io.Writer) error {
|
||||
if t == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
|
||||
cw := cbg.NewCborWriter(w)
|
||||
|
||||
if _, err := cw.Write(lengthBufEventEntry); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Flags (uint8) (uint8)
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.Flags)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Key (string) (string)
|
||||
if len(t.Key) > cbg.MaxLength {
|
||||
return xerrors.Errorf("Value in field t.Key was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajTextString, uint64(len(t.Key))); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := io.WriteString(w, string(t.Key)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.Value ([]uint8) (slice)
|
||||
if len(t.Value) > cbg.ByteArrayMaxLen {
|
||||
return xerrors.Errorf("Byte array in field t.Value was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Value))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := cw.Write(t.Value[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *EventEntry) UnmarshalCBOR(r io.Reader) (err error) {
|
||||
*t = EventEntry{}
|
||||
|
||||
cr := cbg.NewCborReader(r)
|
||||
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
}()
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("cbor input should be of type array")
|
||||
}
|
||||
|
||||
if extra != 3 {
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// t.Flags (uint8) (uint8)
|
||||
|
||||
maj, extra, err = cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maj != cbg.MajUnsignedInt {
|
||||
return fmt.Errorf("wrong type for uint8 field")
|
||||
}
|
||||
if extra > math.MaxUint8 {
|
||||
return fmt.Errorf("integer in input was too large for uint8 field")
|
||||
}
|
||||
t.Flags = uint8(extra)
|
||||
// t.Key (string) (string)
|
||||
|
||||
{
|
||||
sval, err := cbg.ReadString(cr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
t.Key = string(sval)
|
||||
}
|
||||
// t.Value ([]uint8) (slice)
|
||||
|
||||
maj, extra, err = cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.ByteArrayMaxLen {
|
||||
return fmt.Errorf("t.Value: byte array too large (%d)", extra)
|
||||
}
|
||||
if maj != cbg.MajByteString {
|
||||
return fmt.Errorf("expected byte array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.Value = make([]uint8, extra)
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(cr, t.Value[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
595
chain/types/ethtypes/eth_transactions.go
Normal file
595
chain/types/ethtypes/eth_transactions.go
Normal file
@ -0,0 +1,595 @@
|
||||
package ethtypes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
mathbig "math/big"
|
||||
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/crypto/sha3"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
gocrypto "github.com/filecoin-project/go-crypto"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||
"github.com/filecoin-project/go-state-types/builtin/v10/eam"
|
||||
typescrypto "github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
)
|
||||
|
||||
const Eip1559TxType = 2
|
||||
|
||||
type EthTx struct {
|
||||
ChainID EthUint64 `json:"chainId"`
|
||||
Nonce EthUint64 `json:"nonce"`
|
||||
Hash EthHash `json:"hash"`
|
||||
BlockHash *EthHash `json:"blockHash"`
|
||||
BlockNumber *EthUint64 `json:"blockNumber"`
|
||||
TransactionIndex *EthUint64 `json:"transactionIndex"`
|
||||
From EthAddress `json:"from"`
|
||||
To *EthAddress `json:"to"`
|
||||
Value EthBigInt `json:"value"`
|
||||
Type EthUint64 `json:"type"`
|
||||
Input EthBytes `json:"input"`
|
||||
Gas EthUint64 `json:"gas"`
|
||||
MaxFeePerGas EthBigInt `json:"maxFeePerGas"`
|
||||
MaxPriorityFeePerGas EthBigInt `json:"maxPriorityFeePerGas"`
|
||||
V EthBigInt `json:"v"`
|
||||
R EthBigInt `json:"r"`
|
||||
S EthBigInt `json:"s"`
|
||||
}
|
||||
|
||||
type EthTxArgs struct {
|
||||
ChainID int `json:"chainId"`
|
||||
Nonce int `json:"nonce"`
|
||||
To *EthAddress `json:"to"`
|
||||
Value big.Int `json:"value"`
|
||||
MaxFeePerGas big.Int `json:"maxFeePerGas"`
|
||||
MaxPriorityFeePerGas big.Int `json:"maxPriorityFeePerGas"`
|
||||
GasLimit int `json:"gasLimit"`
|
||||
Input []byte `json:"input"`
|
||||
V big.Int `json:"v"`
|
||||
R big.Int `json:"r"`
|
||||
S big.Int `json:"s"`
|
||||
}
|
||||
|
||||
func NewEthTxArgsFromMessage(msg *types.Message) (EthTxArgs, error) {
|
||||
var (
|
||||
to *EthAddress
|
||||
decodedParams []byte
|
||||
paramsReader = bytes.NewReader(msg.Params)
|
||||
)
|
||||
|
||||
if msg.To == builtintypes.EthereumAddressManagerActorAddr {
|
||||
switch msg.Method {
|
||||
case builtintypes.MethodsEAM.Create:
|
||||
var create eam.CreateParams
|
||||
if err := create.UnmarshalCBOR(paramsReader); err != nil {
|
||||
return EthTxArgs{}, err
|
||||
}
|
||||
decodedParams = create.Initcode
|
||||
case builtintypes.MethodsEAM.Create2:
|
||||
var create2 eam.Create2Params
|
||||
if err := create2.UnmarshalCBOR(paramsReader); err != nil {
|
||||
return EthTxArgs{}, err
|
||||
}
|
||||
decodedParams = create2.Initcode
|
||||
default:
|
||||
return EthTxArgs{}, fmt.Errorf("unsupported EAM method")
|
||||
}
|
||||
} else {
|
||||
addr, err := EthAddressFromFilecoinAddress(msg.To)
|
||||
if err != nil {
|
||||
return EthTxArgs{}, err
|
||||
}
|
||||
to = &addr
|
||||
|
||||
if len(msg.Params) > 0 {
|
||||
params, err := cbg.ReadByteArray(paramsReader, uint64(len(msg.Params)))
|
||||
if err != nil {
|
||||
return EthTxArgs{}, err
|
||||
}
|
||||
decodedParams = params
|
||||
}
|
||||
}
|
||||
|
||||
return EthTxArgs{
|
||||
ChainID: build.Eip155ChainId,
|
||||
Nonce: int(msg.Nonce),
|
||||
To: to,
|
||||
Value: msg.Value,
|
||||
Input: decodedParams,
|
||||
MaxFeePerGas: msg.GasFeeCap,
|
||||
MaxPriorityFeePerGas: msg.GasPremium,
|
||||
GasLimit: int(msg.GasLimit),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) ToSignedMessage() (*types.SignedMessage, error) {
|
||||
from, err := tx.Sender()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var to address.Address
|
||||
var params []byte
|
||||
|
||||
if len(tx.To) == 0 && len(tx.Input) == 0 {
|
||||
return nil, fmt.Errorf("to and input cannot both be empty")
|
||||
}
|
||||
|
||||
var method abi.MethodNum
|
||||
if tx.To == nil {
|
||||
// TODO unify with applyEvmMsg
|
||||
|
||||
// this is a contract creation
|
||||
to = builtintypes.EthereumAddressManagerActorAddr
|
||||
|
||||
params2, err := actors.SerializeParams(&eam.CreateParams{
|
||||
Initcode: tx.Input,
|
||||
Nonce: uint64(tx.Nonce),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to serialize Create params: %w", err)
|
||||
}
|
||||
params = params2
|
||||
method = builtintypes.MethodsEAM.Create
|
||||
} else {
|
||||
addr, err := tx.To.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
to = addr
|
||||
|
||||
if len(tx.Input) > 0 {
|
||||
var buf bytes.Buffer
|
||||
if err := cbg.WriteByteArray(&buf, tx.Input); err != nil {
|
||||
return nil, fmt.Errorf("failed to encode tx input into a cbor byte-string")
|
||||
}
|
||||
params = buf.Bytes()
|
||||
method = builtintypes.MethodsEVM.InvokeContract
|
||||
} else {
|
||||
method = builtintypes.MethodSend
|
||||
}
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
Nonce: uint64(tx.Nonce),
|
||||
From: from,
|
||||
To: to,
|
||||
Value: tx.Value,
|
||||
Method: method,
|
||||
Params: params,
|
||||
GasLimit: int64(tx.GasLimit),
|
||||
GasFeeCap: tx.MaxFeePerGas,
|
||||
GasPremium: tx.MaxPriorityFeePerGas,
|
||||
}
|
||||
|
||||
sig, err := tx.Signature()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
signedMsg := types.SignedMessage{
|
||||
Message: *msg,
|
||||
Signature: *sig,
|
||||
}
|
||||
return &signedMsg, nil
|
||||
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) HashedOriginalRlpMsg() ([]byte, error) {
|
||||
msg, err := tx.ToRlpUnsignedMsg()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
hasher.Write(msg)
|
||||
hash := hasher.Sum(nil)
|
||||
return hash, nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) ToRlpUnsignedMsg() ([]byte, error) {
|
||||
packed, err := tx.packTxFields()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encoded, err := EncodeRLP(packed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append([]byte{0x02}, encoded...), nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) ToRlpSignedMsg() ([]byte, error) {
|
||||
packed1, err := tx.packTxFields()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
packed2, err := tx.packSigFields()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
encoded, err := EncodeRLP(append(packed1, packed2...))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return append([]byte{0x02}, encoded...), nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) packTxFields() ([]interface{}, error) {
|
||||
chainId, err := formatInt(tx.ChainID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonce, err := formatInt(tx.Nonce)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
maxPriorityFeePerGas, err := formatBigInt(tx.MaxPriorityFeePerGas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
maxFeePerGas, err := formatBigInt(tx.MaxFeePerGas)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gasLimit, err := formatInt(tx.GasLimit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value, err := formatBigInt(tx.Value)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := []interface{}{
|
||||
chainId,
|
||||
nonce,
|
||||
maxPriorityFeePerGas,
|
||||
maxFeePerGas,
|
||||
gasLimit,
|
||||
formatEthAddr(tx.To),
|
||||
value,
|
||||
tx.Input,
|
||||
[]interface{}{}, // access list
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) packSigFields() ([]interface{}, error) {
|
||||
r, err := formatBigInt(tx.R)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s, err := formatBigInt(tx.S)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v, err := formatBigInt(tx.V)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res := []interface{}{v, r, s}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) Signature() (*typescrypto.Signature, error) {
|
||||
r := tx.R.Int.Bytes()
|
||||
s := tx.S.Int.Bytes()
|
||||
v := tx.V.Int.Bytes()
|
||||
|
||||
sig := append([]byte{}, padLeadingZeros(r, 32)...)
|
||||
sig = append(sig, padLeadingZeros(s, 32)...)
|
||||
if len(v) == 0 {
|
||||
sig = append(sig, 0)
|
||||
} else {
|
||||
sig = append(sig, v[0])
|
||||
}
|
||||
|
||||
if len(sig) != 65 {
|
||||
return nil, fmt.Errorf("signature is not 65 bytes")
|
||||
}
|
||||
return &typescrypto.Signature{
|
||||
Type: typescrypto.SigTypeDelegated, Data: sig,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (tx *EthTxArgs) Sender() (address.Address, error) {
|
||||
msg, err := tx.ToRlpUnsignedMsg()
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
hasher.Write(msg)
|
||||
hash := hasher.Sum(nil)
|
||||
|
||||
sig, err := tx.Signature()
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
pubk, err := gocrypto.EcRecover(hash, sig.Data)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
ethAddr, err := EthAddressFromPubKey(pubk)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
ea, err := CastEthAddress(ethAddr)
|
||||
if err != nil {
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
return ea.ToFilecoinAddress()
|
||||
}
|
||||
|
||||
func RecoverSignature(sig typescrypto.Signature) (r, s, v EthBigInt, err error) {
|
||||
if sig.Type != typescrypto.SigTypeDelegated {
|
||||
return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("RecoverSignature only supports Delegated signature")
|
||||
}
|
||||
|
||||
if len(sig.Data) != 65 {
|
||||
return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("signature should be 65 bytes long, but got %d bytes", len(sig.Data))
|
||||
}
|
||||
|
||||
r_, err := parseBigInt(sig.Data[0:32])
|
||||
if err != nil {
|
||||
return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("cannot parse r into EthBigInt")
|
||||
}
|
||||
|
||||
s_, err := parseBigInt(sig.Data[32:64])
|
||||
if err != nil {
|
||||
return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("cannot parse s into EthBigInt")
|
||||
}
|
||||
|
||||
v_, err := parseBigInt([]byte{sig.Data[64]})
|
||||
if err != nil {
|
||||
return EthBigIntZero, EthBigIntZero, EthBigIntZero, fmt.Errorf("cannot parse v into EthBigInt")
|
||||
}
|
||||
|
||||
return EthBigInt(r_), EthBigInt(s_), EthBigInt(v_), nil
|
||||
}
|
||||
|
||||
func parseEip1559Tx(data []byte) (*EthTxArgs, error) {
|
||||
if data[0] != 2 {
|
||||
return nil, fmt.Errorf("not an EIP-1559 transaction: first byte is not 2")
|
||||
}
|
||||
|
||||
d, err := DecodeRLP(data[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
decoded, ok := d.([]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("not an EIP-1559 transaction: decoded data is not a list")
|
||||
}
|
||||
|
||||
if len(decoded) != 12 {
|
||||
return nil, fmt.Errorf("not an EIP-1559 transaction: should have 12 elements in the rlp list")
|
||||
}
|
||||
|
||||
chainId, err := parseInt(decoded[0])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nonce, err := parseInt(decoded[1])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
maxPriorityFeePerGas, err := parseBigInt(decoded[2])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
maxFeePerGas, err := parseBigInt(decoded[3])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
gasLimit, err := parseInt(decoded[4])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
to, err := parseEthAddr(decoded[5])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
value, err := parseBigInt(decoded[6])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
input, err := parseBytes(decoded[7])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accessList, ok := decoded[8].([]interface{})
|
||||
if !ok || (ok && len(accessList) != 0) {
|
||||
return nil, fmt.Errorf("access list should be an empty list")
|
||||
}
|
||||
|
||||
r, err := parseBigInt(decoded[10])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s, err := parseBigInt(decoded[11])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v, err := parseBigInt(decoded[9])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// EIP-1559 and EIP-2930 transactions only support 0 or 1 for v
|
||||
// Legacy and EIP-155 transactions support other values
|
||||
// https://github.com/ethers-io/ethers.js/blob/56fabe987bb8c1e4891fdf1e5d3fe8a4c0471751/packages/transactions/src.ts/index.ts#L333
|
||||
if !v.Equals(big.NewInt(0)) && !v.Equals(big.NewInt(1)) {
|
||||
return nil, fmt.Errorf("EIP-1559 transactions only support 0 or 1 for v")
|
||||
}
|
||||
|
||||
args := EthTxArgs{
|
||||
ChainID: chainId,
|
||||
Nonce: nonce,
|
||||
To: to,
|
||||
MaxPriorityFeePerGas: maxPriorityFeePerGas,
|
||||
MaxFeePerGas: maxFeePerGas,
|
||||
GasLimit: gasLimit,
|
||||
Value: value,
|
||||
Input: input,
|
||||
V: v,
|
||||
R: r,
|
||||
S: s,
|
||||
}
|
||||
return &args, nil
|
||||
}
|
||||
|
||||
func ParseEthTxArgs(data []byte) (*EthTxArgs, error) {
|
||||
if len(data) == 0 {
|
||||
return nil, fmt.Errorf("empty data")
|
||||
}
|
||||
|
||||
if data[0] > 0x7f {
|
||||
// legacy transaction
|
||||
return nil, fmt.Errorf("legacy transaction is not supported")
|
||||
}
|
||||
|
||||
if data[0] == 1 {
|
||||
// EIP-2930
|
||||
return nil, fmt.Errorf("EIP-2930 transaction is not supported")
|
||||
}
|
||||
|
||||
if data[0] == Eip1559TxType {
|
||||
// EIP-1559
|
||||
return parseEip1559Tx(data)
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unsupported transaction type")
|
||||
}
|
||||
|
||||
func padLeadingZeros(data []byte, length int) []byte {
|
||||
if len(data) >= length {
|
||||
return data
|
||||
}
|
||||
zeros := make([]byte, length-len(data))
|
||||
return append(zeros, data...)
|
||||
}
|
||||
|
||||
func removeLeadingZeros(data []byte) []byte {
|
||||
firstNonZeroIndex := len(data)
|
||||
for i, b := range data {
|
||||
if b > 0 {
|
||||
firstNonZeroIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
return data[firstNonZeroIndex:]
|
||||
}
|
||||
|
||||
func formatInt(val int) ([]byte, error) {
|
||||
buf := new(bytes.Buffer)
|
||||
err := binary.Write(buf, binary.BigEndian, int64(val))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return removeLeadingZeros(buf.Bytes()), nil
|
||||
}
|
||||
|
||||
func formatEthAddr(addr *EthAddress) []byte {
|
||||
if addr == nil {
|
||||
return nil
|
||||
}
|
||||
return addr[:]
|
||||
}
|
||||
|
||||
func formatBigInt(val big.Int) ([]byte, error) {
|
||||
b, err := val.Bytes()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return removeLeadingZeros(b), nil
|
||||
}
|
||||
|
||||
func parseInt(v interface{}) (int, error) {
|
||||
data, ok := v.([]byte)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("cannot parse interface to int: input is not a byte array")
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
if len(data) > 8 {
|
||||
return 0, fmt.Errorf("cannot parse interface to int: length is more than 8 bytes")
|
||||
}
|
||||
var value int64
|
||||
r := bytes.NewReader(append(make([]byte, 8-len(data)), data...))
|
||||
if err := binary.Read(r, binary.BigEndian, &value); err != nil {
|
||||
return 0, fmt.Errorf("cannot parse interface to EthUint64: %w", err)
|
||||
}
|
||||
return int(value), nil
|
||||
}
|
||||
|
||||
func parseBigInt(v interface{}) (big.Int, error) {
|
||||
data, ok := v.([]byte)
|
||||
if !ok {
|
||||
return big.Zero(), fmt.Errorf("cannot parse interface to big.Int: input is not a byte array")
|
||||
}
|
||||
if len(data) == 0 {
|
||||
return big.Zero(), nil
|
||||
}
|
||||
var b mathbig.Int
|
||||
b.SetBytes(data)
|
||||
return big.NewFromGo(&b), nil
|
||||
}
|
||||
|
||||
func parseBytes(v interface{}) ([]byte, error) {
|
||||
val, ok := v.([]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("cannot parse interface into bytes: input is not a byte array")
|
||||
}
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func parseEthAddr(v interface{}) (*EthAddress, error) {
|
||||
b, err := parseBytes(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(b) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
addr, err := CastEthAddress(b)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &addr, nil
|
||||
}
|
251
chain/types/ethtypes/eth_transactions_test.go
Normal file
251
chain/types/ethtypes/eth_transactions_test.go
Normal file
File diff suppressed because one or more lines are too long
600
chain/types/ethtypes/eth_types.go
Normal file
600
chain/types/ethtypes/eth_types.go
Normal file
@ -0,0 +1,600 @@
|
||||
package ethtypes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
mathbig "math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/multiformats/go-multihash"
|
||||
"github.com/multiformats/go-varint"
|
||||
"golang.org/x/crypto/sha3"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
)
|
||||
|
||||
var (
|
||||
EthTopic1 = "topic1"
|
||||
EthTopic2 = "topic2"
|
||||
EthTopic3 = "topic3"
|
||||
EthTopic4 = "topic4"
|
||||
)
|
||||
|
||||
var ErrInvalidAddress = errors.New("invalid Filecoin Eth address")
|
||||
|
||||
type EthUint64 uint64
|
||||
|
||||
func (e EthUint64) MarshalJSON() ([]byte, error) {
|
||||
if e == 0 {
|
||||
return json.Marshal("0x0")
|
||||
}
|
||||
return json.Marshal(fmt.Sprintf("0x%x", e))
|
||||
}
|
||||
|
||||
func (e *EthUint64) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
parsedInt, err := strconv.ParseUint(strings.Replace(s, "0x", "", -1), 16, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
eint := EthUint64(parsedInt)
|
||||
*e = eint
|
||||
return nil
|
||||
}
|
||||
|
||||
func EthUint64FromHex(s string) (EthUint64, error) {
|
||||
parsedInt, err := strconv.ParseUint(strings.Replace(s, "0x", "", -1), 16, 64)
|
||||
if err != nil {
|
||||
return EthUint64(0), err
|
||||
}
|
||||
return EthUint64(parsedInt), nil
|
||||
}
|
||||
|
||||
// EthBigInt represents a large integer whose zero value serializes to "0x0".
|
||||
type EthBigInt big.Int
|
||||
|
||||
var EthBigIntZero = EthBigInt{Int: big.Zero().Int}
|
||||
|
||||
func (e EthBigInt) MarshalJSON() ([]byte, error) {
|
||||
if e.Int == nil || e.Int.BitLen() == 0 {
|
||||
return json.Marshal("0x0")
|
||||
}
|
||||
return json.Marshal(fmt.Sprintf("0x%x", e.Int))
|
||||
}
|
||||
|
||||
func (e *EthBigInt) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
replaced := strings.Replace(s, "0x", "", -1)
|
||||
if len(replaced)%2 == 1 {
|
||||
replaced = "0" + replaced
|
||||
}
|
||||
|
||||
i := new(mathbig.Int)
|
||||
i.SetString(replaced, 16)
|
||||
|
||||
*e = EthBigInt(big.NewFromGo(i))
|
||||
return nil
|
||||
}
|
||||
|
||||
// EthBytes represent arbitrary bytes. A nil or empty slice serializes to "0x".
|
||||
type EthBytes []byte
|
||||
|
||||
func (e EthBytes) MarshalJSON() ([]byte, error) {
|
||||
if len(e) == 0 {
|
||||
return json.Marshal("0x")
|
||||
}
|
||||
s := hex.EncodeToString(e)
|
||||
return json.Marshal("0x" + s)
|
||||
}
|
||||
|
||||
func (e *EthBytes) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s = strings.Replace(s, "0x", "", -1)
|
||||
if len(s)%2 == 1 {
|
||||
s = "0" + s
|
||||
}
|
||||
|
||||
decoded, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*e = decoded
|
||||
return nil
|
||||
}
|
||||
|
||||
type EthBlock struct {
|
||||
Hash EthHash `json:"hash"`
|
||||
ParentHash EthHash `json:"parentHash"`
|
||||
Sha3Uncles EthHash `json:"sha3Uncles"`
|
||||
Miner EthAddress `json:"miner"`
|
||||
StateRoot EthHash `json:"stateRoot"`
|
||||
TransactionsRoot EthHash `json:"transactionsRoot"`
|
||||
ReceiptsRoot EthHash `json:"receiptsRoot"`
|
||||
LogsBloom EthBytes `json:"logsBloom"`
|
||||
Difficulty EthUint64 `json:"difficulty"`
|
||||
TotalDifficulty EthUint64 `json:"totalDifficulty"`
|
||||
Number EthUint64 `json:"number"`
|
||||
GasLimit EthUint64 `json:"gasLimit"`
|
||||
GasUsed EthUint64 `json:"gasUsed"`
|
||||
Timestamp EthUint64 `json:"timestamp"`
|
||||
Extradata []byte `json:"extraData"`
|
||||
MixHash EthHash `json:"mixHash"`
|
||||
Nonce EthNonce `json:"nonce"`
|
||||
BaseFeePerGas EthBigInt `json:"baseFeePerGas"`
|
||||
Size EthUint64 `json:"size"`
|
||||
// can be []EthTx or []string depending on query params
|
||||
Transactions []interface{} `json:"transactions"`
|
||||
Uncles []EthHash `json:"uncles"`
|
||||
}
|
||||
|
||||
var (
|
||||
EmptyEthBloom = [256]byte{}
|
||||
EmptyEthHash = EthHash{}
|
||||
EmptyEthInt = EthUint64(0)
|
||||
EmptyEthNonce = [8]byte{0, 0, 0, 0, 0, 0, 0, 0}
|
||||
)
|
||||
|
||||
func NewEthBlock() EthBlock {
|
||||
return EthBlock{
|
||||
Sha3Uncles: EmptyEthHash,
|
||||
StateRoot: EmptyEthHash,
|
||||
TransactionsRoot: EmptyEthHash,
|
||||
ReceiptsRoot: EmptyEthHash,
|
||||
Difficulty: EmptyEthInt,
|
||||
LogsBloom: EmptyEthBloom[:],
|
||||
Extradata: []byte{},
|
||||
MixHash: EmptyEthHash,
|
||||
Nonce: EmptyEthNonce,
|
||||
GasLimit: EthUint64(build.BlockGasLimit), // TODO we map Ethereum blocks to Filecoin tipsets; this is inconsistent.
|
||||
Uncles: []EthHash{},
|
||||
Transactions: []interface{}{},
|
||||
}
|
||||
}
|
||||
|
||||
type EthCall struct {
|
||||
From *EthAddress `json:"from"`
|
||||
To *EthAddress `json:"to"`
|
||||
Gas EthUint64 `json:"gas"`
|
||||
GasPrice EthBigInt `json:"gasPrice"`
|
||||
Value EthBigInt `json:"value"`
|
||||
Data EthBytes `json:"data"`
|
||||
}
|
||||
|
||||
func (c *EthCall) UnmarshalJSON(b []byte) error {
|
||||
type TempEthCall EthCall
|
||||
var params TempEthCall
|
||||
|
||||
if err := json.Unmarshal(b, ¶ms); err != nil {
|
||||
return err
|
||||
}
|
||||
*c = EthCall(params)
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
EthAddressLength = 20
|
||||
EthHashLength = 32
|
||||
)
|
||||
|
||||
type EthNonce [8]byte
|
||||
|
||||
func (n EthNonce) String() string {
|
||||
return "0x" + hex.EncodeToString(n[:])
|
||||
}
|
||||
|
||||
func (n EthNonce) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(n.String())
|
||||
}
|
||||
|
||||
func (n *EthNonce) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s = strings.Replace(s, "0x", "", -1)
|
||||
if len(s)%2 == 1 {
|
||||
s = "0" + s
|
||||
}
|
||||
|
||||
decoded, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
copy(n[:], decoded[:8])
|
||||
return nil
|
||||
}
|
||||
|
||||
type EthAddress [EthAddressLength]byte
|
||||
|
||||
// EthAddressFromPubKey returns the Ethereum address corresponding to an
|
||||
// uncompressed secp256k1 public key.
|
||||
func EthAddressFromPubKey(pubk []byte) ([]byte, error) {
|
||||
// if we get an uncompressed public key (that's what we get from the library,
|
||||
// but putting this check here for defensiveness), strip the prefix
|
||||
const pubKeyLen = 65
|
||||
if len(pubk) != pubKeyLen {
|
||||
return nil, fmt.Errorf("public key should have %d in length, but got %d", pubKeyLen, len(pubk))
|
||||
}
|
||||
if pubk[0] != 0x04 {
|
||||
return nil, fmt.Errorf("expected first byte of secp256k1 to be 0x04 (uncompressed)")
|
||||
}
|
||||
pubk = pubk[1:]
|
||||
|
||||
// Calculate the Ethereum address based on the keccak hash of the pubkey.
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
hasher.Write(pubk)
|
||||
ethAddr := hasher.Sum(nil)[12:]
|
||||
return ethAddr, nil
|
||||
}
|
||||
|
||||
func EthAddressFromFilecoinAddress(addr address.Address) (EthAddress, error) {
|
||||
switch addr.Protocol() {
|
||||
case address.ID:
|
||||
id, err := address.IDFromAddress(addr)
|
||||
if err != nil {
|
||||
return EthAddress{}, err
|
||||
}
|
||||
var ethaddr EthAddress
|
||||
ethaddr[0] = 0xff
|
||||
binary.BigEndian.PutUint64(ethaddr[12:], id)
|
||||
return ethaddr, nil
|
||||
case address.Delegated:
|
||||
payload := addr.Payload()
|
||||
namespace, n, err := varint.FromUvarint(payload)
|
||||
if err != nil {
|
||||
return EthAddress{}, xerrors.Errorf("invalid delegated address namespace in: %s", addr)
|
||||
}
|
||||
payload = payload[n:]
|
||||
if namespace == builtintypes.EthereumAddressManagerActorID {
|
||||
return CastEthAddress(payload)
|
||||
}
|
||||
}
|
||||
return EthAddress{}, ErrInvalidAddress
|
||||
}
|
||||
|
||||
// ParseEthAddress parses an Ethereum address from a hex string.
|
||||
func ParseEthAddress(s string) (EthAddress, error) {
|
||||
b, err := decodeHexString(s, EthAddressLength)
|
||||
if err != nil {
|
||||
return EthAddress{}, err
|
||||
}
|
||||
var h EthAddress
|
||||
copy(h[EthAddressLength-len(b):], b)
|
||||
return h, nil
|
||||
}
|
||||
|
||||
// CastEthAddress interprets bytes as an EthAddress, performing some basic checks.
|
||||
func CastEthAddress(b []byte) (EthAddress, error) {
|
||||
var a EthAddress
|
||||
if len(b) != EthAddressLength {
|
||||
return EthAddress{}, xerrors.Errorf("cannot parse bytes into an EthAddress: incorrect input length")
|
||||
}
|
||||
copy(a[:], b[:])
|
||||
return a, nil
|
||||
}
|
||||
|
||||
func (ea EthAddress) String() string {
|
||||
return "0x" + hex.EncodeToString(ea[:])
|
||||
}
|
||||
|
||||
func (ea EthAddress) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(ea.String())
|
||||
}
|
||||
|
||||
func (ea *EthAddress) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
addr, err := ParseEthAddress(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
copy(ea[:], addr[:])
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ea EthAddress) IsMaskedID() bool {
|
||||
idmask := [12]byte{0xff}
|
||||
return bytes.Equal(ea[:12], idmask[:])
|
||||
}
|
||||
|
||||
func (ea EthAddress) ToFilecoinAddress() (address.Address, error) {
|
||||
if ea.IsMaskedID() {
|
||||
// This is a masked ID address.
|
||||
id := binary.BigEndian.Uint64(ea[12:])
|
||||
return address.NewIDAddress(id)
|
||||
}
|
||||
|
||||
// Otherwise, translate the address into an address controlled by the
|
||||
// Ethereum Address Manager.
|
||||
addr, err := address.NewDelegatedAddress(builtintypes.EthereumAddressManagerActorID, ea[:])
|
||||
if err != nil {
|
||||
return address.Undef, fmt.Errorf("failed to translate supplied address (%s) into a "+
|
||||
"Filecoin f4 address: %w", hex.EncodeToString(ea[:]), err)
|
||||
}
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
type EthHash [EthHashLength]byte
|
||||
|
||||
func (h EthHash) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(h.String())
|
||||
}
|
||||
|
||||
func (h *EthHash) UnmarshalJSON(b []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(b, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
hash, err := ParseEthHash(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
copy(h[:], hash[:])
|
||||
return nil
|
||||
}
|
||||
|
||||
func decodeHexString(s string, expectedLen int) ([]byte, error) {
|
||||
// Strip the leading 0x or 0X prefix since hex.DecodeString does not support it.
|
||||
if strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X") {
|
||||
s = s[2:]
|
||||
}
|
||||
// Sometimes clients will omit a leading zero in a byte; pad so we can decode correctly.
|
||||
if len(s)%2 == 1 {
|
||||
s = "0" + s
|
||||
}
|
||||
if len(s) != expectedLen*2 {
|
||||
return nil, xerrors.Errorf("expected hex string length sans prefix %d, got %d", expectedLen*2, len(s))
|
||||
}
|
||||
b, err := hex.DecodeString(s)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("cannot parse hex value: %w", err)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func EthHashFromCid(c cid.Cid) (EthHash, error) {
|
||||
return ParseEthHash(c.Hash().HexString()[8:])
|
||||
}
|
||||
|
||||
func ParseEthHash(s string) (EthHash, error) {
|
||||
b, err := decodeHexString(s, EthHashLength)
|
||||
if err != nil {
|
||||
return EthHash{}, err
|
||||
}
|
||||
var h EthHash
|
||||
copy(h[EthHashLength-len(b):], b)
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (h EthHash) String() string {
|
||||
return "0x" + hex.EncodeToString(h[:])
|
||||
}
|
||||
|
||||
func (h EthHash) ToCid() cid.Cid {
|
||||
// err is always nil
|
||||
mh, _ := multihash.EncodeName(h[:], "blake2b-256")
|
||||
|
||||
return cid.NewCidV1(cid.DagCBOR, mh)
|
||||
}
|
||||
|
||||
type EthFeeHistory struct {
|
||||
OldestBlock uint64 `json:"oldestBlock"`
|
||||
BaseFeePerGas []EthBigInt `json:"baseFeePerGas"`
|
||||
GasUsedRatio []float64 `json:"gasUsedRatio"`
|
||||
Reward *[][]EthBigInt `json:"reward,omitempty"`
|
||||
}
|
||||
|
||||
type EthFilterID EthHash
|
||||
|
||||
// An opaque identifier generated by the Lotus node to refer to an active subscription.
|
||||
type EthSubscriptionID EthHash
|
||||
|
||||
type EthFilterSpec struct {
|
||||
// Interpreted as an epoch or one of "latest" for last mined block, "earliest" for first,
|
||||
// "pending" for not yet committed messages.
|
||||
// Optional, default: "latest".
|
||||
FromBlock *string `json:"fromBlock,omitempty"`
|
||||
|
||||
// Interpreted as an epoch or one of "latest" for last mined block, "earliest" for first,
|
||||
// "pending" for not yet committed messages.
|
||||
// Optional, default: "latest".
|
||||
ToBlock *string `json:"toBlock,omitempty"`
|
||||
|
||||
// Actor address or a list of addresses from which event logs should originate.
|
||||
// Optional, default nil.
|
||||
// The JSON decoding must treat a string as equivalent to an array with one value, for example
|
||||
// "0x8888f1f195afa192cfee86069858" must be decoded as [ "0x8888f1f195afa192cfee86069858" ]
|
||||
Address EthAddressList `json:"address"`
|
||||
|
||||
// List of topics to be matched.
|
||||
// Optional, default: empty list
|
||||
Topics EthTopicSpec `json:"topics"`
|
||||
|
||||
// Restricts event logs returned to those emitted from messages contained in this tipset.
|
||||
// If BlockHash is present in in the filter criteria, then neither FromBlock nor ToBlock are allowed.
|
||||
// Added in EIP-234
|
||||
BlockHash *EthHash `json:"blockHash,omitempty"`
|
||||
}
|
||||
|
||||
// EthAddressSpec represents a list of addresses.
|
||||
// The JSON decoding must treat a string as equivalent to an array with one value, for example
|
||||
// "0x8888f1f195afa192cfee86069858" must be decoded as [ "0x8888f1f195afa192cfee86069858" ]
|
||||
type EthAddressList []EthAddress
|
||||
|
||||
func (e *EthAddressList) UnmarshalJSON(b []byte) error {
|
||||
if bytes.Equal(b, []byte{'n', 'u', 'l', 'l'}) {
|
||||
return nil
|
||||
}
|
||||
if len(b) > 0 && b[0] == '[' {
|
||||
var addrs []EthAddress
|
||||
err := json.Unmarshal(b, &addrs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*e = addrs
|
||||
return nil
|
||||
}
|
||||
var addr EthAddress
|
||||
err := json.Unmarshal(b, &addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*e = []EthAddress{addr}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TopicSpec represents a specification for matching by topic. An empty spec means all topics
|
||||
// will be matched. Otherwise topics are matched conjunctively in the first dimension of the
|
||||
// slice and disjunctively in the second dimension. Topics are matched in order.
|
||||
// An event log with topics [A, B] will be matched by the following topic specs:
|
||||
// [] "all"
|
||||
// [[A]] "A in first position (and anything after)"
|
||||
// [nil, [B] ] "anything in first position AND B in second position (and anything after)"
|
||||
// [[A], [B]] "A in first position AND B in second position (and anything after)"
|
||||
// [[A, B], [A, B]] "(A OR B) in first position AND (A OR B) in second position (and anything after)"
|
||||
//
|
||||
// The JSON decoding must treat string values as equivalent to arrays with one value, for example
|
||||
// { "A", [ "B", "C" ] } must be decoded as [ [ A ], [ B, C ] ]
|
||||
type EthTopicSpec []EthHashList
|
||||
|
||||
// EthHashList represents a list of EthHashes.
|
||||
// The JSON decoding treats string values as equivalent to arrays with one value.
|
||||
type EthHashList []EthHash
|
||||
|
||||
func (e *EthHashList) UnmarshalJSON(b []byte) error {
|
||||
if bytes.Equal(b, []byte{'n', 'u', 'l', 'l'}) {
|
||||
return nil
|
||||
}
|
||||
if len(b) > 0 && b[0] == '[' {
|
||||
var hashes []EthHash
|
||||
err := json.Unmarshal(b, &hashes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*e = hashes
|
||||
return nil
|
||||
}
|
||||
var hash EthHash
|
||||
err := json.Unmarshal(b, &hash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*e = []EthHash{hash}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FilterResult represents the response from executing a filter: a list of block hashes, a list of transaction hashes
|
||||
// or a list of logs
|
||||
// This is a union type. Only one field will be populated.
|
||||
// The JSON encoding must produce an array of the populated field.
|
||||
type EthFilterResult struct {
|
||||
Results []interface{}
|
||||
}
|
||||
|
||||
func (h EthFilterResult) MarshalJSON() ([]byte, error) {
|
||||
if h.Results != nil {
|
||||
return json.Marshal(h.Results)
|
||||
}
|
||||
return []byte{'[', ']'}, nil
|
||||
}
|
||||
|
||||
func (h *EthFilterResult) UnmarshalJSON(b []byte) error {
|
||||
if bytes.Equal(b, []byte{'n', 'u', 'l', 'l'}) {
|
||||
return nil
|
||||
}
|
||||
err := json.Unmarshal(b, &h.Results)
|
||||
return err
|
||||
}
|
||||
|
||||
// EthLog represents the results of an event filter execution.
|
||||
type EthLog struct {
|
||||
// Address is the address of the actor that produced the event log.
|
||||
Address EthAddress `json:"address"`
|
||||
|
||||
// Data is the value of the event log, excluding topics
|
||||
Data EthBytes `json:"data"`
|
||||
|
||||
// List of topics associated with the event log.
|
||||
Topics []EthBytes `json:"topics"`
|
||||
|
||||
// Following fields are derived from the transaction containing the log
|
||||
|
||||
// Indicates whether the log was removed due to a chain reorganization.
|
||||
Removed bool `json:"removed"`
|
||||
|
||||
// LogIndex is the index of the event log in the sequence of events produced by the message execution.
|
||||
// (this is the index in the events AMT on the message receipt)
|
||||
LogIndex EthUint64 `json:"logIndex"`
|
||||
|
||||
// TransactionIndex is the index in the tipset of the transaction that produced the event log.
|
||||
// The index corresponds to the sequence of messages produced by ChainGetParentMessages
|
||||
TransactionIndex EthUint64 `json:"transactionIndex"`
|
||||
|
||||
// TransactionHash is the cid of the message that produced the event log.
|
||||
TransactionHash EthHash `json:"transactionHash"`
|
||||
|
||||
// BlockHash is the hash of the tipset containing the message that produced the log.
|
||||
BlockHash EthHash `json:"blockHash"`
|
||||
|
||||
// BlockNumber is the epoch of the tipset containing the message.
|
||||
BlockNumber EthUint64 `json:"blockNumber"`
|
||||
}
|
||||
|
||||
type EthSubscriptionParams struct {
|
||||
// List of topics to be matched.
|
||||
// Optional, default: empty list
|
||||
Topics EthTopicSpec `json:"topics,omitempty"`
|
||||
}
|
||||
|
||||
type EthSubscriptionResponse struct {
|
||||
// The persistent identifier for the subscription which can be used to unsubscribe.
|
||||
SubscriptionID EthSubscriptionID `json:"subscription"`
|
||||
|
||||
// The object matching the subscription. This may be a Block (tipset), a Transaction (message) or an EthLog
|
||||
Result interface{} `json:"result"`
|
||||
}
|
||||
|
||||
func GetContractEthAddressFromCode(sender EthAddress, salt [32]byte, initcode []byte) (EthAddress, error) {
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
hasher.Write(initcode)
|
||||
inithash := hasher.Sum(nil)
|
||||
|
||||
hasher.Reset()
|
||||
hasher.Write([]byte{0xff})
|
||||
hasher.Write(sender[:])
|
||||
hasher.Write(salt[:])
|
||||
hasher.Write(inithash)
|
||||
|
||||
ethAddr, err := CastEthAddress(hasher.Sum(nil)[12:])
|
||||
if err != nil {
|
||||
return [20]byte{}, err
|
||||
}
|
||||
|
||||
return ethAddr, nil
|
||||
}
|
384
chain/types/ethtypes/eth_types_test.go
Normal file
384
chain/types/ethtypes/eth_types_test.go
Normal file
@ -0,0 +1,384 @@
|
||||
package ethtypes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
)
|
||||
|
||||
type TestCase struct {
|
||||
Input interface{}
|
||||
Output interface{}
|
||||
}
|
||||
|
||||
func TestEthIntMarshalJSON(t *testing.T) {
|
||||
// https://ethereum.org/en/developers/docs/apis/json-rpc/#quantities-encoding
|
||||
testcases := []TestCase{
|
||||
{EthUint64(0), []byte("\"0x0\"")},
|
||||
{EthUint64(65), []byte("\"0x41\"")},
|
||||
{EthUint64(1024), []byte("\"0x400\"")},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
j, err := tc.Input.(EthUint64).MarshalJSON()
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, j, tc.Output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthIntUnmarshalJSON(t *testing.T) {
|
||||
testcases := []TestCase{
|
||||
{[]byte("\"0x0\""), EthUint64(0)},
|
||||
{[]byte("\"0x41\""), EthUint64(65)},
|
||||
{[]byte("\"0x400\""), EthUint64(1024)},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
var i EthUint64
|
||||
err := i.UnmarshalJSON(tc.Input.([]byte))
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, i, tc.Output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthBigIntMarshalJSON(t *testing.T) {
|
||||
testcases := []TestCase{
|
||||
{EthBigInt(big.NewInt(0)), []byte("\"0x0\"")},
|
||||
{EthBigInt(big.NewInt(65)), []byte("\"0x41\"")},
|
||||
{EthBigInt(big.NewInt(1024)), []byte("\"0x400\"")},
|
||||
{EthBigInt(big.Int{}), []byte("\"0x0\"")},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
j, err := tc.Input.(EthBigInt).MarshalJSON()
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, j, tc.Output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthBigIntUnmarshalJSON(t *testing.T) {
|
||||
testcases := []TestCase{
|
||||
{[]byte("\"0x0\""), EthBigInt(big.MustFromString("0"))},
|
||||
{[]byte("\"0x41\""), EthBigInt(big.MustFromString("65"))},
|
||||
{[]byte("\"0x400\""), EthBigInt(big.MustFromString("1024"))},
|
||||
{[]byte("\"0xff1000000000000000000000000\""), EthBigInt(big.MustFromString("323330131220712761719252861321216"))},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
var i EthBigInt
|
||||
err := i.UnmarshalJSON(tc.Input.([]byte))
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, i, tc.Output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthHash(t *testing.T) {
|
||||
testcases := []string{
|
||||
`"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"`,
|
||||
`"0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"`,
|
||||
}
|
||||
|
||||
for _, hash := range testcases {
|
||||
var h EthHash
|
||||
err := h.UnmarshalJSON([]byte(hash))
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, h.String(), strings.Replace(hash, `"`, "", -1))
|
||||
|
||||
c := h.ToCid()
|
||||
h1, err := EthHashFromCid(c)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, h, h1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthAddr(t *testing.T) {
|
||||
testcases := []string{
|
||||
strings.ToLower(`"0xd4c5fb16488Aa48081296299d54b0c648C9333dA"`),
|
||||
strings.ToLower(`"0x2C2EC67e3e1FeA8e4A39601cB3A3Cd44f5fa830d"`),
|
||||
strings.ToLower(`"0x01184F793982104363F9a8a5845743f452dE0586"`),
|
||||
}
|
||||
|
||||
for _, addr := range testcases {
|
||||
var a EthAddress
|
||||
err := a.UnmarshalJSON([]byte(addr))
|
||||
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, a.String(), strings.Replace(addr, `"`, "", -1))
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseEthAddr(t *testing.T) {
|
||||
testcases := []uint64{
|
||||
1, 2, 3, 100, 101,
|
||||
}
|
||||
for _, id := range testcases {
|
||||
addr, err := address.NewIDAddress(id)
|
||||
require.Nil(t, err)
|
||||
|
||||
eaddr, err := EthAddressFromFilecoinAddress(addr)
|
||||
require.Nil(t, err)
|
||||
|
||||
faddr, err := eaddr.ToFilecoinAddress()
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, addr, faddr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnmarshalEthCall(t *testing.T) {
|
||||
data := `{"from":"0x4D6D86b31a112a05A473c4aE84afaF873f632325","to":"0xFe01CC39f5Ae8553D6914DBb9dC27D219fa22D7f","gas":"0x5","gasPrice":"0x6","value":"0x123","data":""}`
|
||||
|
||||
var c EthCall
|
||||
err := c.UnmarshalJSON([]byte(data))
|
||||
require.Nil(t, err)
|
||||
}
|
||||
|
||||
func TestUnmarshalEthBytes(t *testing.T) {
|
||||
testcases := []string{
|
||||
`"0x00"`,
|
||||
strings.ToLower(`"0xd4c5fb16488Aa48081296299d54b0c648C9333dA"`),
|
||||
strings.ToLower(`"0x2C2EC67e3e1FeA8e4A39601cB3A3Cd44f5fa830d"`),
|
||||
strings.ToLower(`"0x01184F793982104363F9a8a5845743f452dE0586"`),
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
var s EthBytes
|
||||
err := s.UnmarshalJSON([]byte(tc))
|
||||
require.Nil(t, err)
|
||||
|
||||
data, err := s.MarshalJSON()
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, string(data), tc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthFilterResultMarshalJSON(t *testing.T) {
|
||||
hash1, err := ParseEthHash("013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184")
|
||||
require.NoError(t, err, "eth hash")
|
||||
|
||||
hash2, err := ParseEthHash("ab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738")
|
||||
require.NoError(t, err, "eth hash")
|
||||
|
||||
addr, err := ParseEthAddress("d4c5fb16488Aa48081296299d54b0c648C9333dA")
|
||||
require.NoError(t, err, "eth address")
|
||||
|
||||
log := EthLog{
|
||||
Removed: true,
|
||||
LogIndex: 5,
|
||||
TransactionIndex: 45,
|
||||
TransactionHash: hash1,
|
||||
BlockHash: hash2,
|
||||
BlockNumber: 53,
|
||||
Topics: []EthBytes{hash1[:]},
|
||||
Data: EthBytes(hash1[:]),
|
||||
Address: addr,
|
||||
}
|
||||
logjson, err := json.Marshal(log)
|
||||
require.NoError(t, err, "log json")
|
||||
|
||||
testcases := []struct {
|
||||
res EthFilterResult
|
||||
want string
|
||||
}{
|
||||
{
|
||||
res: EthFilterResult{},
|
||||
want: "[]",
|
||||
},
|
||||
|
||||
{
|
||||
res: EthFilterResult{
|
||||
Results: []any{hash1, hash2},
|
||||
},
|
||||
want: `["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184","0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"]`,
|
||||
},
|
||||
|
||||
{
|
||||
res: EthFilterResult{
|
||||
Results: []any{hash1, hash2},
|
||||
},
|
||||
want: `["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184","0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"]`,
|
||||
},
|
||||
|
||||
{
|
||||
res: EthFilterResult{
|
||||
Results: []any{log},
|
||||
},
|
||||
want: `[` + string(logjson) + `]`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
tc := tc
|
||||
t.Run("", func(t *testing.T) {
|
||||
data, err := json.Marshal(tc.res)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.want, string(data))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthFilterSpecUnmarshalJSON(t *testing.T) {
|
||||
hash1, err := ParseEthHash("013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184")
|
||||
require.NoError(t, err, "eth hash")
|
||||
|
||||
hash2, err := ParseEthHash("ab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738")
|
||||
require.NoError(t, err, "eth hash")
|
||||
|
||||
addr, err := ParseEthAddress("d4c5fb16488Aa48081296299d54b0c648C9333dA")
|
||||
require.NoError(t, err, "eth address")
|
||||
|
||||
pstring := func(s string) *string { return &s }
|
||||
phash := func(h EthHash) *EthHash { return &h }
|
||||
|
||||
testcases := []struct {
|
||||
input string
|
||||
want EthFilterSpec
|
||||
}{
|
||||
{
|
||||
input: `{"fromBlock":"latest"}`,
|
||||
want: EthFilterSpec{FromBlock: pstring("latest")},
|
||||
},
|
||||
{
|
||||
input: `{"toBlock":"pending"}`,
|
||||
want: EthFilterSpec{ToBlock: pstring("pending")},
|
||||
},
|
||||
{
|
||||
input: `{"address":["0xd4c5fb16488Aa48081296299d54b0c648C9333dA"]}`,
|
||||
want: EthFilterSpec{Address: EthAddressList{addr}},
|
||||
},
|
||||
{
|
||||
input: `{"address":"0xd4c5fb16488Aa48081296299d54b0c648C9333dA"}`,
|
||||
want: EthFilterSpec{Address: EthAddressList{addr}},
|
||||
},
|
||||
{
|
||||
input: `{"blockHash":"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"}`,
|
||||
want: EthFilterSpec{BlockHash: phash(hash1)},
|
||||
},
|
||||
{
|
||||
input: `{"topics":["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"]}`,
|
||||
want: EthFilterSpec{
|
||||
Topics: EthTopicSpec{
|
||||
{hash1},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: `{"topics":["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184","0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"]}`,
|
||||
want: EthFilterSpec{
|
||||
Topics: EthTopicSpec{
|
||||
{hash1},
|
||||
{hash2},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: `{"topics":[null, ["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184","0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"]]}`,
|
||||
want: EthFilterSpec{
|
||||
Topics: EthTopicSpec{
|
||||
nil,
|
||||
{hash1, hash2},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
input: `{"topics":[null, "0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"]}`,
|
||||
want: EthFilterSpec{
|
||||
Topics: EthTopicSpec{
|
||||
nil,
|
||||
{hash1},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
var got EthFilterSpec
|
||||
err := json.Unmarshal([]byte(tc.input), &got)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthAddressListUnmarshalJSON(t *testing.T) {
|
||||
addr1, err := ParseEthAddress("d4c5fb16488Aa48081296299d54b0c648C9333dA")
|
||||
require.NoError(t, err, "eth address")
|
||||
|
||||
addr2, err := ParseEthAddress("abbbfb16488Aa48081296299d54b0c648C9333dA")
|
||||
require.NoError(t, err, "eth address")
|
||||
|
||||
testcases := []struct {
|
||||
input string
|
||||
want EthAddressList
|
||||
}{
|
||||
{
|
||||
input: `["0xd4c5fb16488Aa48081296299d54b0c648C9333dA"]`,
|
||||
want: EthAddressList{addr1},
|
||||
},
|
||||
{
|
||||
input: `["0xd4c5fb16488Aa48081296299d54b0c648C9333dA","abbbfb16488Aa48081296299d54b0c648C9333dA"]`,
|
||||
want: EthAddressList{addr1, addr2},
|
||||
},
|
||||
{
|
||||
input: `"0xd4c5fb16488Aa48081296299d54b0c648C9333dA"`,
|
||||
want: EthAddressList{addr1},
|
||||
},
|
||||
{
|
||||
input: `[]`,
|
||||
want: EthAddressList{},
|
||||
},
|
||||
{
|
||||
input: `null`,
|
||||
want: EthAddressList(nil),
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
tc := tc
|
||||
t.Run("", func(t *testing.T) {
|
||||
var got EthAddressList
|
||||
err := json.Unmarshal([]byte(tc.input), &got)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEthHashListUnmarshalJSON(t *testing.T) {
|
||||
hash1, err := ParseEthHash("013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184")
|
||||
require.NoError(t, err, "eth hash")
|
||||
|
||||
hash2, err := ParseEthHash("ab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738")
|
||||
require.NoError(t, err, "eth hash")
|
||||
|
||||
testcases := []struct {
|
||||
input string
|
||||
want *EthHashList
|
||||
}{
|
||||
{
|
||||
input: `["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"]`,
|
||||
want: &EthHashList{hash1},
|
||||
},
|
||||
{
|
||||
input: `["0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184","0xab8653edf9f51785664a643b47605a7ba3d917b5339a0724e7642c114d0e4738"]`,
|
||||
want: &EthHashList{hash1, hash2},
|
||||
},
|
||||
{
|
||||
input: `"0x013dbb9442ca9667baccc6230fcd5c1c4b2d4d2870f4bd20681d4d47cfd15184"`,
|
||||
want: &EthHashList{hash1},
|
||||
},
|
||||
{
|
||||
input: `null`,
|
||||
want: nil,
|
||||
},
|
||||
}
|
||||
for _, tc := range testcases {
|
||||
var got *EthHashList
|
||||
err := json.Unmarshal([]byte(tc.input), &got)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tc.want, got)
|
||||
}
|
||||
}
|
182
chain/types/ethtypes/rlp.go
Normal file
182
chain/types/ethtypes/rlp.go
Normal file
@ -0,0 +1,182 @@
|
||||
package ethtypes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
// maxListElements restricts the amount of RLP list elements we'll read.
|
||||
// The ETH API only ever reads EIP-1559 transactions, which are bounded by
|
||||
// 12 elements exactly, so we play it safe and set exactly that limit here.
|
||||
const maxListElements = 12
|
||||
|
||||
func EncodeRLP(val interface{}) ([]byte, error) {
|
||||
return encodeRLP(val)
|
||||
}
|
||||
|
||||
func encodeRLPListItems(list []interface{}) (result []byte, err error) {
|
||||
res := []byte{}
|
||||
for _, elem := range list {
|
||||
encoded, err := encodeRLP(elem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res = append(res, encoded...)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func encodeLength(length int) (lenInBytes []byte, err error) {
|
||||
if length == 0 {
|
||||
return nil, fmt.Errorf("cannot encode length: length should be larger than 0")
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
err = binary.Write(buf, binary.BigEndian, int64(length))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
firstNonZeroIndex := len(buf.Bytes()) - 1
|
||||
for i, b := range buf.Bytes() {
|
||||
if b != 0 {
|
||||
firstNonZeroIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
res := buf.Bytes()[firstNonZeroIndex:]
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func encodeRLP(val interface{}) ([]byte, error) {
|
||||
switch data := val.(type) {
|
||||
case []byte:
|
||||
if len(data) == 1 && data[0] <= 0x7f {
|
||||
return data, nil
|
||||
} else if len(data) <= 55 {
|
||||
prefix := byte(0x80 + len(data))
|
||||
return append([]byte{prefix}, data...), nil
|
||||
} else {
|
||||
lenInBytes, err := encodeLength(len(data))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prefix := byte(0xb7 + len(lenInBytes))
|
||||
return append(
|
||||
[]byte{prefix},
|
||||
append(lenInBytes, data...)...,
|
||||
), nil
|
||||
}
|
||||
case []interface{}:
|
||||
encodedList, err := encodeRLPListItems(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(encodedList) <= 55 {
|
||||
prefix := byte(0xc0 + len(encodedList))
|
||||
return append(
|
||||
[]byte{prefix},
|
||||
encodedList...,
|
||||
), nil
|
||||
}
|
||||
lenInBytes, err := encodeLength(len(encodedList))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
prefix := byte(0xf7 + len(lenInBytes))
|
||||
return append(
|
||||
[]byte{prefix},
|
||||
append(lenInBytes, encodedList...)...,
|
||||
), nil
|
||||
default:
|
||||
return nil, fmt.Errorf("input data should either be a list or a byte array")
|
||||
}
|
||||
}
|
||||
|
||||
func DecodeRLP(data []byte) (interface{}, error) {
|
||||
res, consumed, err := decodeRLP(data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if consumed != len(data) {
|
||||
return nil, xerrors.Errorf("invalid rlp data: length %d, consumed %d", len(data), consumed)
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func decodeRLP(data []byte) (res interface{}, consumed int, err error) {
|
||||
if len(data) == 0 {
|
||||
return data, 0, xerrors.Errorf("invalid rlp data: data cannot be empty")
|
||||
}
|
||||
if data[0] >= 0xf8 {
|
||||
listLenInBytes := int(data[0]) - 0xf7
|
||||
listLen, err := decodeLength(data[1:], listLenInBytes)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if 1+listLenInBytes+listLen > len(data) {
|
||||
return nil, 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list")
|
||||
}
|
||||
result, err := decodeListElems(data[1+listLenInBytes:], listLen)
|
||||
return result, 1 + listLenInBytes + listLen, err
|
||||
} else if data[0] >= 0xc0 {
|
||||
length := int(data[0]) - 0xc0
|
||||
result, err := decodeListElems(data[1:], length)
|
||||
return result, 1 + length, err
|
||||
} else if data[0] >= 0xb8 {
|
||||
strLenInBytes := int(data[0]) - 0xb7
|
||||
strLen, err := decodeLength(data[1:], strLenInBytes)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
totalLen := 1 + strLenInBytes + strLen
|
||||
if totalLen > len(data) {
|
||||
return nil, 0, xerrors.Errorf("invalid rlp data: out of bound while parsing string")
|
||||
}
|
||||
return data[1+strLenInBytes : totalLen], totalLen, nil
|
||||
} else if data[0] >= 0x80 {
|
||||
length := int(data[0]) - 0x80
|
||||
if 1+length > len(data) {
|
||||
return nil, 0, xerrors.Errorf("invalid rlp data: out of bound while parsing string")
|
||||
}
|
||||
return data[1 : 1+length], 1 + length, nil
|
||||
}
|
||||
return []byte{data[0]}, 1, nil
|
||||
}
|
||||
|
||||
func decodeLength(data []byte, lenInBytes int) (length int, err error) {
|
||||
if lenInBytes > len(data) || lenInBytes > 8 {
|
||||
return 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list length")
|
||||
}
|
||||
var decodedLength int64
|
||||
r := bytes.NewReader(append(make([]byte, 8-lenInBytes), data[:lenInBytes]...))
|
||||
if err := binary.Read(r, binary.BigEndian, &decodedLength); err != nil {
|
||||
return 0, xerrors.Errorf("invalid rlp data: cannot parse string length: %w", err)
|
||||
}
|
||||
if lenInBytes+int(decodedLength) > len(data) {
|
||||
return 0, xerrors.Errorf("invalid rlp data: out of bound while parsing list")
|
||||
}
|
||||
return int(decodedLength), nil
|
||||
}
|
||||
|
||||
func decodeListElems(data []byte, length int) (res []interface{}, err error) {
|
||||
totalConsumed := 0
|
||||
result := []interface{}{}
|
||||
|
||||
for i := 0; totalConsumed < length && i < maxListElements; i++ {
|
||||
elem, consumed, err := decodeRLP(data[totalConsumed:])
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("invalid rlp data: cannot decode list element: %w", err)
|
||||
}
|
||||
totalConsumed += consumed
|
||||
result = append(result, elem)
|
||||
}
|
||||
if totalConsumed != length {
|
||||
return nil, xerrors.Errorf("invalid rlp data: incorrect list length")
|
||||
}
|
||||
return result, nil
|
||||
}
|
190
chain/types/ethtypes/rlp_test.go
Normal file
190
chain/types/ethtypes/rlp_test.go
Normal file
@ -0,0 +1,190 @@
|
||||
package ethtypes
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
)
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
testcases := []TestCase{
|
||||
{[]byte(""), mustDecodeHex("0x80")},
|
||||
{mustDecodeHex("0x01"), mustDecodeHex("0x01")},
|
||||
{mustDecodeHex("0xaa"), mustDecodeHex("0x81aa")},
|
||||
{mustDecodeHex("0x0402"), mustDecodeHex("0x820402")},
|
||||
{
|
||||
[]interface{}{},
|
||||
mustDecodeHex("0xc0"),
|
||||
},
|
||||
{
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xb83cabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"),
|
||||
},
|
||||
{
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xb8aaabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"),
|
||||
},
|
||||
{
|
||||
[]interface{}{
|
||||
mustDecodeHex("0xaaaa"),
|
||||
mustDecodeHex("0xbbbb"),
|
||||
mustDecodeHex("0xcccc"),
|
||||
mustDecodeHex("0xdddd"),
|
||||
},
|
||||
mustDecodeHex("0xcc82aaaa82bbbb82cccc82dddd"),
|
||||
},
|
||||
{
|
||||
[]interface{}{
|
||||
mustDecodeHex("0xaaaaaaaaaaaaaaaaaaaa"),
|
||||
mustDecodeHex("0xbbbbbbbbbbbbbbbbbbbb"),
|
||||
[]interface{}{
|
||||
mustDecodeHex("0xc1c1c1c1c1c1c1c1c1c1"),
|
||||
mustDecodeHex("0xc2c2c2c2c2c2c2c2c2c2"),
|
||||
mustDecodeHex("0xc3c3c3c3c3c3c3c3c3c3"),
|
||||
},
|
||||
mustDecodeHex("0xdddddddddddddddddddd"),
|
||||
mustDecodeHex("0xeeeeeeeeeeeeeeeeeeee"),
|
||||
mustDecodeHex("0xffffffffffffffffffff"),
|
||||
},
|
||||
mustDecodeHex("0xf8598aaaaaaaaaaaaaaaaaaaaa8abbbbbbbbbbbbbbbbbbbbe18ac1c1c1c1c1c1c1c1c1c18ac2c2c2c2c2c2c2c2c2c28ac3c3c3c3c3c3c3c3c3c38adddddddddddddddddddd8aeeeeeeeeeeeeeeeeeeee8affffffffffffffffffff"),
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
result, err := EncodeRLP(tc.Input)
|
||||
require.Nil(t, err)
|
||||
|
||||
require.Equal(t, tc.Output.([]byte), result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeString(t *testing.T) {
|
||||
testcases := []TestCase{
|
||||
{"0x00", "0x00"},
|
||||
{"0x80", "0x"},
|
||||
{"0x0f", "0x0f"},
|
||||
{"0x81aa", "0xaa"},
|
||||
{"0x820400", "0x0400"},
|
||||
{"0xb83cabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
|
||||
"0xabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
input, err := hex.DecodeString(strings.Replace(tc.Input.(string), "0x", "", -1))
|
||||
require.Nil(t, err)
|
||||
|
||||
output, err := hex.DecodeString(strings.Replace(tc.Output.(string), "0x", "", -1))
|
||||
require.Nil(t, err)
|
||||
|
||||
result, err := DecodeRLP(input)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, output, result.([]byte))
|
||||
}
|
||||
}
|
||||
|
||||
func mustDecodeHex(s string) []byte {
|
||||
d, err := hex.DecodeString(strings.Replace(s, "0x", "", -1))
|
||||
if err != nil {
|
||||
panic(fmt.Errorf("err must be nil: %w", err))
|
||||
}
|
||||
return d
|
||||
}
|
||||
|
||||
func TestDecodeList(t *testing.T) {
|
||||
testcases := []TestCase{
|
||||
{"0xc0", []interface{}{}},
|
||||
{"0xc100", []interface{}{[]byte{0}}},
|
||||
{"0xc3000102", []interface{}{[]byte{0}, []byte{1}, []byte{2}}},
|
||||
{"0xc4000181aa", []interface{}{[]byte{0}, []byte{1}, []byte{0xaa}}},
|
||||
{"0xc6000181aa81ff", []interface{}{[]byte{0}, []byte{1}, []byte{0xaa}, []byte{0xff}}},
|
||||
{"0xf8428aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd8aabcdabcdabcdabcdabcd",
|
||||
[]interface{}{
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcd"),
|
||||
mustDecodeHex("0xabcdabcdabcdabcdabcd"),
|
||||
},
|
||||
},
|
||||
{"0xf1030185012a05f2008504a817c800825208942b87d1cb599bc2a606db9a0169fcec96af04ad3a880de0b6b3a764000080c0",
|
||||
[]interface{}{
|
||||
[]byte{3},
|
||||
[]byte{1},
|
||||
mustDecodeHex("0x012a05f200"),
|
||||
mustDecodeHex("0x04a817c800"),
|
||||
mustDecodeHex("0x5208"),
|
||||
mustDecodeHex("0x2b87d1CB599Bc2a606Db9A0169fcEc96Af04ad3a"),
|
||||
mustDecodeHex("0x0de0b6b3a7640000"),
|
||||
[]byte{},
|
||||
[]interface{}{},
|
||||
}},
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
input, err := hex.DecodeString(strings.Replace(tc.Input.(string), "0x", "", -1))
|
||||
require.Nil(t, err)
|
||||
|
||||
result, err := DecodeRLP(input)
|
||||
require.Nil(t, err)
|
||||
|
||||
fmt.Println(result)
|
||||
r := result.([]interface{})
|
||||
require.Equal(t, len(tc.Output.([]interface{})), len(r))
|
||||
|
||||
for i, v := range r {
|
||||
require.Equal(t, tc.Output.([]interface{})[i], v)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeEncodeTx(t *testing.T) {
|
||||
testcases := [][]byte{
|
||||
mustDecodeHex("0xdc82013a0185012a05f2008504a817c8008080872386f26fc1000000c0"),
|
||||
mustDecodeHex("0xf85f82013a0185012a05f2008504a817c8008080872386f26fc1000000c001a027fa36fb9623e4d71fcdd7f7dce71eb814c9560dcf3908c1719386e2efd122fba05fb4e4227174eeb0ba84747a4fb883c8d4e0fdb129c4b1f42e90282c41480234"),
|
||||
mustDecodeHex("0xf9061c82013a0185012a05f2008504a817c8008080872386f26fc10000b905bb608060405234801561001057600080fd5b506127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610556806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637bd703e81461004657806390b98a1114610076578063f8b2cb4f146100a6575b600080fd5b610060600480360381019061005b919061030a565b6100d6565b60405161006d9190610350565b60405180910390f35b610090600480360381019061008b9190610397565b6100f4565b60405161009d91906103f2565b60405180910390f35b6100c060048036038101906100bb919061030a565b61025f565b6040516100cd9190610350565b60405180910390f35b600060026100e38361025f565b6100ed919061043c565b9050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101455760009050610259565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101939190610496565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101e891906104ca565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161024c9190610350565b60405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d7826102ac565b9050919050565b6102e7816102cc565b81146102f257600080fd5b50565b600081359050610304816102de565b92915050565b6000602082840312156103205761031f6102a7565b5b600061032e848285016102f5565b91505092915050565b6000819050919050565b61034a81610337565b82525050565b60006020820190506103656000830184610341565b92915050565b61037481610337565b811461037f57600080fd5b50565b6000813590506103918161036b565b92915050565b600080604083850312156103ae576103ad6102a7565b5b60006103bc858286016102f5565b92505060206103cd85828601610382565b9150509250929050565b60008115159050919050565b6103ec816103d7565b82525050565b600060208201905061040760008301846103e3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061044782610337565b915061045283610337565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561048b5761048a61040d565b5b828202905092915050565b60006104a182610337565b91506104ac83610337565b9250828210156104bf576104be61040d565b5b828203905092915050565b60006104d582610337565b91506104e083610337565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156105155761051461040d565b5b82820190509291505056fea26469706673582212208e5b4b874c839967f88008ed2fa42d6c2d9c9b0ae05d1d2c61faa7d229c134e664736f6c634300080d0033c080a0c4e9477f57c6848b2f1ea73a14809c1f44529d20763c947f3ac8ffd3d1629d93a011485a215457579bb13ac7b53bb9d6804763ae6fe5ce8ddd41642cea55c9a09a"),
|
||||
mustDecodeHex("0xf9063082013a0185012a05f2008504a817c8008094025b594a4f1c4888cafcfaf2bb24ed95507749e0872386f26fc10000b905bb608060405234801561001057600080fd5b506127106000803273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550610556806100656000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c80637bd703e81461004657806390b98a1114610076578063f8b2cb4f146100a6575b600080fd5b610060600480360381019061005b919061030a565b6100d6565b60405161006d9190610350565b60405180910390f35b610090600480360381019061008b9190610397565b6100f4565b60405161009d91906103f2565b60405180910390f35b6100c060048036038101906100bb919061030a565b61025f565b6040516100cd9190610350565b60405180910390f35b600060026100e38361025f565b6100ed919061043c565b9050919050565b6000816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205410156101455760009050610259565b816000803373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101939190610496565b92505081905550816000808573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546101e891906104ca565b925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8460405161024c9190610350565b60405180910390a3600190505b92915050565b60008060008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020549050919050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102d7826102ac565b9050919050565b6102e7816102cc565b81146102f257600080fd5b50565b600081359050610304816102de565b92915050565b6000602082840312156103205761031f6102a7565b5b600061032e848285016102f5565b91505092915050565b6000819050919050565b61034a81610337565b82525050565b60006020820190506103656000830184610341565b92915050565b61037481610337565b811461037f57600080fd5b50565b6000813590506103918161036b565b92915050565b600080604083850312156103ae576103ad6102a7565b5b60006103bc858286016102f5565b92505060206103cd85828601610382565b9150509250929050565b60008115159050919050565b6103ec816103d7565b82525050565b600060208201905061040760008301846103e3565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061044782610337565b915061045283610337565b9250817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561048b5761048a61040d565b5b828202905092915050565b60006104a182610337565b91506104ac83610337565b9250828210156104bf576104be61040d565b5b828203905092915050565b60006104d582610337565b91506104e083610337565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156105155761051461040d565b5b82820190509291505056fea26469706673582212208e5b4b874c839967f88008ed2fa42d6c2d9c9b0ae05d1d2c61faa7d229c134e664736f6c634300080d0033c080a0fe38720928596f9e9dfbf891d00311638efce3713f03cdd67b212ecbbcf18f29a05993e656c0b35b8a580da6aff7c89b3d3e8b1c6f83a7ce09473c0699a8500b9c"),
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
decoded, err := DecodeRLP(tc)
|
||||
require.Nil(t, err)
|
||||
|
||||
encoded, err := EncodeRLP(decoded)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, tc, encoded)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecodeError(t *testing.T) {
|
||||
testcases := [][]byte{
|
||||
mustDecodeHex("0xdc82013a0185012a05f2008504a817c8008080872386f26fc1000000"),
|
||||
mustDecodeHex("0xdc013a01012a05f2008504a817c8008080872386f26fc1000000"),
|
||||
mustDecodeHex("0xdc82013a0185012a05f28504a817c08080872386f26fc1000000"),
|
||||
mustDecodeHex("0xdc82013a0185012a05f504a817c080872386ffc1000000"),
|
||||
mustDecodeHex("0x013a018505f2008504a817c8008080872386f26fc1000000"),
|
||||
}
|
||||
|
||||
for _, tc := range testcases {
|
||||
_, err := DecodeRLP(tc)
|
||||
require.NotNil(t, err, hex.EncodeToString(tc))
|
||||
}
|
||||
}
|
||||
|
||||
func TestDecode1(t *testing.T) {
|
||||
b := mustDecodeHex("0x02f8758401df5e7680832c8411832c8411830767f89452963ef50e27e06d72d59fcb4f3c2a687be3cfef880de0b6b3a764000080c080a094b11866f453ad85a980e0e8a2fc98cbaeb4409618c7734a7e12ae2f66fd405da042dbfb1b37af102023830ceeee0e703ffba0b8b3afeb8fe59f405eca9ed61072")
|
||||
decoded, err := ParseEthTxArgs(b)
|
||||
require.NoError(t, err)
|
||||
|
||||
sender, err := decoded.Sender()
|
||||
require.NoError(t, err)
|
||||
|
||||
addr, err := address.NewFromString("f410fkkld55ioe7qg24wvt7fu6pbknb56ht7pt4zamxa")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, sender, addr)
|
||||
}
|
32
chain/types/event.go
Normal file
32
chain/types/event.go
Normal file
@ -0,0 +1,32 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
)
|
||||
|
||||
type Event struct {
|
||||
// The ID of the actor that emitted this event.
|
||||
Emitter abi.ActorID
|
||||
|
||||
// Key values making up this event.
|
||||
Entries []EventEntry
|
||||
}
|
||||
|
||||
type EventEntry struct {
|
||||
// A bitmap conveying metadata or hints about this entry.
|
||||
Flags uint8
|
||||
|
||||
// The key of this event entry
|
||||
Key string
|
||||
|
||||
// Any DAG-CBOR encodeable type.
|
||||
Value []byte
|
||||
}
|
||||
|
||||
type FilterID [32]byte // compatible with EthHash
|
||||
|
||||
// EventEntry flags defined in fvm_shared
|
||||
const (
|
||||
EventFlagIndexedKey = 0b00000001
|
||||
EventFlagIndexedValue = 0b00000010
|
||||
)
|
@ -39,6 +39,8 @@ func (kt *KeyType) UnmarshalJSON(bb []byte) error {
|
||||
*kt = KTBLS
|
||||
case crypto.SigTypeSecp256k1:
|
||||
*kt = KTSecp256k1
|
||||
case crypto.SigTypeDelegated:
|
||||
*kt = KTDelegated
|
||||
default:
|
||||
return fmt.Errorf("unknown sigtype: %d", bst)
|
||||
}
|
||||
@ -51,6 +53,7 @@ const (
|
||||
KTBLS KeyType = "bls"
|
||||
KTSecp256k1 KeyType = "secp256k1"
|
||||
KTSecp256k1Ledger KeyType = "secp256k1-ledger"
|
||||
KTDelegated KeyType = "delegated"
|
||||
)
|
||||
|
||||
// KeyInfo is used for storing keys in KeyStore
|
||||
|
@ -3,15 +3,59 @@ package types
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
)
|
||||
|
||||
type MessageReceiptVersion byte
|
||||
|
||||
const (
|
||||
// MessageReceiptV0 refers to pre FIP-0049 receipts.
|
||||
MessageReceiptV0 MessageReceiptVersion = 0
|
||||
// MessageReceiptV1 refers to post FIP-0049 receipts.
|
||||
MessageReceiptV1 MessageReceiptVersion = 1
|
||||
)
|
||||
|
||||
const EventAMTBitwidth = 5
|
||||
|
||||
type MessageReceipt struct {
|
||||
version MessageReceiptVersion
|
||||
|
||||
ExitCode exitcode.ExitCode
|
||||
Return []byte
|
||||
GasUsed int64
|
||||
EventsRoot *cid.Cid // Root of Event AMT with bitwidth = EventAMTBitwidth
|
||||
}
|
||||
|
||||
// NewMessageReceiptV0 creates a new pre FIP-0049 receipt with no capability to
|
||||
// convey events.
|
||||
func NewMessageReceiptV0(exitcode exitcode.ExitCode, ret []byte, gasUsed int64) MessageReceipt {
|
||||
return MessageReceipt{
|
||||
version: MessageReceiptV0,
|
||||
ExitCode: exitcode,
|
||||
Return: ret,
|
||||
GasUsed: gasUsed,
|
||||
}
|
||||
}
|
||||
|
||||
// NewMessageReceiptV1 creates a new pre FIP-0049 receipt with the ability to
|
||||
// convey events.
|
||||
func NewMessageReceiptV1(exitcode exitcode.ExitCode, ret []byte, gasUsed int64, eventsRoot *cid.Cid) MessageReceipt {
|
||||
return MessageReceipt{
|
||||
version: MessageReceiptV1,
|
||||
ExitCode: exitcode,
|
||||
Return: ret,
|
||||
GasUsed: gasUsed,
|
||||
EventsRoot: eventsRoot,
|
||||
}
|
||||
}
|
||||
|
||||
func (mr *MessageReceipt) Version() MessageReceiptVersion {
|
||||
return mr.version
|
||||
}
|
||||
|
||||
func (mr *MessageReceipt) Equals(o *MessageReceipt) bool {
|
||||
return mr.ExitCode == o.ExitCode && bytes.Equal(mr.Return, o.Return) && mr.GasUsed == o.GasUsed
|
||||
return mr.version == o.version && mr.ExitCode == o.ExitCode && bytes.Equal(mr.Return, o.Return) && mr.GasUsed == o.GasUsed &&
|
||||
(mr.EventsRoot == o.EventsRoot || (mr.EventsRoot != nil && o.EventsRoot != nil && *mr.EventsRoot == *o.EventsRoot))
|
||||
}
|
||||
|
359
chain/types/message_receipt_cbor.go
Normal file
359
chain/types/message_receipt_cbor.go
Normal file
@ -0,0 +1,359 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-state-types/cbor"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
)
|
||||
|
||||
// This file contains custom CBOR serde logic to deal with the new versioned
|
||||
// MessageReceipt resulting from the introduction of actor events (FIP-0049).
|
||||
|
||||
type messageReceiptV0 struct{ *MessageReceipt }
|
||||
|
||||
type messageReceiptV1 struct{ *MessageReceipt }
|
||||
|
||||
func (mr *MessageReceipt) MarshalCBOR(w io.Writer) error {
|
||||
if mr == nil {
|
||||
_, err := w.Write(cbg.CborNull)
|
||||
return err
|
||||
}
|
||||
|
||||
var m cbor.Marshaler
|
||||
switch mr.version {
|
||||
case MessageReceiptV0:
|
||||
m = &messageReceiptV0{mr}
|
||||
case MessageReceiptV1:
|
||||
m = &messageReceiptV1{mr}
|
||||
default:
|
||||
return xerrors.Errorf("invalid message receipt version: %d", mr.version)
|
||||
}
|
||||
|
||||
return m.MarshalCBOR(w)
|
||||
}
|
||||
|
||||
func (mr *MessageReceipt) UnmarshalCBOR(r io.Reader) (err error) {
|
||||
*mr = MessageReceipt{}
|
||||
|
||||
cr := cbg.NewCborReader(r)
|
||||
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
}()
|
||||
|
||||
if maj != cbg.MajArray {
|
||||
return fmt.Errorf("cbor input should be of type array")
|
||||
}
|
||||
|
||||
var u cbor.Unmarshaler
|
||||
switch extra {
|
||||
case 3:
|
||||
mr.version = MessageReceiptV0
|
||||
u = &messageReceiptV0{mr}
|
||||
case 4:
|
||||
mr.version = MessageReceiptV1
|
||||
u = &messageReceiptV1{mr}
|
||||
default:
|
||||
return fmt.Errorf("cbor input had wrong number of fields")
|
||||
}
|
||||
|
||||
// Ok to pass a CBOR reader since cbg.NewCborReader will return itself when
|
||||
// already a CBOR reader.
|
||||
return u.UnmarshalCBOR(cr)
|
||||
}
|
||||
|
||||
var lengthBufAMessageReceiptV0 = []byte{131}
|
||||
|
||||
func (t *messageReceiptV0) MarshalCBOR(w io.Writer) error {
|
||||
// eliding null check since nulls were already handled in the dispatcher
|
||||
|
||||
cw := cbg.NewCborWriter(w)
|
||||
|
||||
if _, err := cw.Write(lengthBufAMessageReceiptV0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.ExitCode (exitcode.ExitCode) (int64)
|
||||
if t.ExitCode >= 0 {
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.ExitCode)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.ExitCode-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.Return ([]uint8) (slice)
|
||||
if len(t.Return) > cbg.ByteArrayMaxLen {
|
||||
return xerrors.Errorf("Byte array in field t.Return was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Return))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := cw.Write(t.Return[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.GasUsed (int64) (int64)
|
||||
if t.GasUsed >= 0 {
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.GasUsed)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.GasUsed-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *messageReceiptV0) UnmarshalCBOR(r io.Reader) (err error) {
|
||||
cr := cbg.NewCborReader(r)
|
||||
|
||||
// t.ExitCode (exitcode.ExitCode) (int64)
|
||||
{
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.ExitCode = exitcode.ExitCode(extraI)
|
||||
}
|
||||
// t.Return ([]uint8) (slice)
|
||||
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.ByteArrayMaxLen {
|
||||
return fmt.Errorf("t.Return: byte array too large (%d)", extra)
|
||||
}
|
||||
if maj != cbg.MajByteString {
|
||||
return fmt.Errorf("expected byte array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.Return = make([]uint8, extra)
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(cr, t.Return[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
// t.GasUsed (int64) (int64)
|
||||
{
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.GasUsed = extraI
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var lengthBufBMessageReceiptV1 = []byte{132}
|
||||
|
||||
func (t *messageReceiptV1) MarshalCBOR(w io.Writer) error {
|
||||
// eliding null check since nulls were already handled in the dispatcher
|
||||
|
||||
cw := cbg.NewCborWriter(w)
|
||||
|
||||
if _, err := cw.Write(lengthBufBMessageReceiptV1); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.ExitCode (exitcode.ExitCode) (int64)
|
||||
if t.ExitCode >= 0 {
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.ExitCode)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.ExitCode-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.Return ([]uint8) (slice)
|
||||
if len(t.Return) > cbg.ByteArrayMaxLen {
|
||||
return xerrors.Errorf("Byte array in field t.Return was too long")
|
||||
}
|
||||
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajByteString, uint64(len(t.Return))); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := cw.Write(t.Return[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// t.GasUsed (int64) (int64)
|
||||
if t.GasUsed >= 0 {
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajUnsignedInt, uint64(t.GasUsed)); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cw.WriteMajorTypeHeader(cbg.MajNegativeInt, uint64(-t.GasUsed-1)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// t.EventsRoot (cid.Cid) (struct)
|
||||
|
||||
if t.EventsRoot == nil {
|
||||
if _, err := cw.Write(cbg.CborNull); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := cbg.WriteCid(cw, *t.EventsRoot); err != nil {
|
||||
return xerrors.Errorf("failed to write cid field t.EventsRoot: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *messageReceiptV1) UnmarshalCBOR(r io.Reader) (err error) {
|
||||
cr := cbg.NewCborReader(r)
|
||||
|
||||
// t.ExitCode (exitcode.ExitCode) (int64)
|
||||
{
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.ExitCode = exitcode.ExitCode(extraI)
|
||||
}
|
||||
// t.Return ([]uint8) (slice)
|
||||
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if extra > cbg.ByteArrayMaxLen {
|
||||
return fmt.Errorf("t.Return: byte array too large (%d)", extra)
|
||||
}
|
||||
if maj != cbg.MajByteString {
|
||||
return fmt.Errorf("expected byte array")
|
||||
}
|
||||
|
||||
if extra > 0 {
|
||||
t.Return = make([]uint8, extra)
|
||||
}
|
||||
|
||||
if _, err := io.ReadFull(cr, t.Return[:]); err != nil {
|
||||
return err
|
||||
}
|
||||
// t.GasUsed (int64) (int64)
|
||||
{
|
||||
maj, extra, err := cr.ReadHeader()
|
||||
var extraI int64
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch maj {
|
||||
case cbg.MajUnsignedInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 positive overflow")
|
||||
}
|
||||
case cbg.MajNegativeInt:
|
||||
extraI = int64(extra)
|
||||
if extraI < 0 {
|
||||
return fmt.Errorf("int64 negative oveflow")
|
||||
}
|
||||
extraI = -1 - extraI
|
||||
default:
|
||||
return fmt.Errorf("wrong type for int64 field: %d", maj)
|
||||
}
|
||||
|
||||
t.GasUsed = extraI
|
||||
}
|
||||
// t.EventsRoot (cid.Cid) (struct)
|
||||
|
||||
{
|
||||
|
||||
b, err := cr.ReadByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if b != cbg.CborNull[0] {
|
||||
if err := cr.UnreadByte(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c, err := cbg.ReadCid(cr)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read cid field t.EventsRoot: %w", err)
|
||||
}
|
||||
|
||||
t.EventsRoot = &c
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
}
|
75
chain/types/message_receipt_test.go
Normal file
75
chain/types/message_receipt_test.go
Normal file
@ -0,0 +1,75 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMessageReceiptSerdeRoundrip(t *testing.T) {
|
||||
var (
|
||||
assert = assert.New(t)
|
||||
buf = new(bytes.Buffer)
|
||||
err error
|
||||
)
|
||||
|
||||
randomCid, err := cid.Decode("bafy2bzacecu7n7wbtogznrtuuvf73dsz7wasgyneqasksdblxupnyovmtwxxu")
|
||||
assert.NoError(err)
|
||||
|
||||
//
|
||||
// Version 0
|
||||
//
|
||||
mr := NewMessageReceiptV0(0, []byte{0x00, 0x01, 0x02, 0x04}, 42)
|
||||
|
||||
// marshal
|
||||
err = mr.MarshalCBOR(buf)
|
||||
assert.NoError(err)
|
||||
|
||||
t.Logf("version 0: %s\n", hex.EncodeToString(buf.Bytes()))
|
||||
|
||||
// unmarshal
|
||||
var mr2 MessageReceipt
|
||||
err = mr2.UnmarshalCBOR(buf)
|
||||
assert.NoError(err)
|
||||
assert.Equal(mr, mr2)
|
||||
|
||||
// version 0 with an events root -- should not serialize the events root!
|
||||
mr.EventsRoot = &randomCid
|
||||
|
||||
buf.Reset()
|
||||
|
||||
// marshal
|
||||
err = mr.MarshalCBOR(buf)
|
||||
assert.NoError(err)
|
||||
|
||||
t.Logf("version 0 (with root): %s\n", hex.EncodeToString(buf.Bytes()))
|
||||
|
||||
// unmarshal
|
||||
mr2 = MessageReceipt{}
|
||||
err = mr2.UnmarshalCBOR(buf)
|
||||
assert.NoError(err)
|
||||
assert.NotEqual(mr, mr2)
|
||||
assert.Nil(mr2.EventsRoot)
|
||||
|
||||
//
|
||||
// Version 1
|
||||
//
|
||||
buf.Reset()
|
||||
mr = NewMessageReceiptV1(0, []byte{0x00, 0x01, 0x02, 0x04}, 42, &randomCid)
|
||||
|
||||
// marshal
|
||||
err = mr.MarshalCBOR(buf)
|
||||
assert.NoError(err)
|
||||
|
||||
t.Logf("version 1: %s\n", hex.EncodeToString(buf.Bytes()))
|
||||
|
||||
// unmarshal
|
||||
mr2 = MessageReceipt{}
|
||||
err = mr2.UnmarshalCBOR(buf)
|
||||
assert.NoError(err)
|
||||
assert.Equal(mr, mr2)
|
||||
assert.NotNil(mr2.EventsRoot)
|
||||
}
|
@ -196,8 +196,23 @@ func (ts *TipSet) MinTicket() *Ticket {
|
||||
}
|
||||
|
||||
func (ts *TipSet) MinTimestamp() uint64 {
|
||||
minTs := ts.Blocks()[0].Timestamp
|
||||
for _, bh := range ts.Blocks()[1:] {
|
||||
if ts == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
blks := ts.Blocks()
|
||||
|
||||
// TODO::FVM @vyzo @magik Null rounds shouldn't ever be represented as
|
||||
// tipsets with no blocks; Null-round generally means that the tipset at
|
||||
// that epoch doesn't exist - and the next tipset that does exist links
|
||||
// straight to first epoch with blocks (@raulk agrees -- this is odd)
|
||||
if len(blks) == 0 {
|
||||
// null rounds make things crash -- it is threaded in every fvm instantiation
|
||||
return 0
|
||||
}
|
||||
|
||||
minTs := blks[0].Timestamp
|
||||
for _, bh := range blks[1:] {
|
||||
if bh.Timestamp < minTs {
|
||||
minTs = bh.Timestamp
|
||||
}
|
||||
|
@ -24,6 +24,8 @@ type StateTree interface {
|
||||
SetActor(addr address.Address, act *Actor) error
|
||||
// GetActor returns the actor from any type of `addr` provided.
|
||||
GetActor(addr address.Address) (*Actor, error)
|
||||
|
||||
Version() StateTreeVersion
|
||||
}
|
||||
|
||||
type storageWrapper struct {
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/vectors"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
)
|
||||
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
actorstypes "github.com/filecoin-project/go-state-types/actors"
|
||||
"github.com/filecoin-project/go-state-types/exitcode"
|
||||
"github.com/filecoin-project/go-state-types/manifest"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
|
||||
"github.com/filecoin-project/lotus/blockstore"
|
||||
"github.com/filecoin-project/lotus/build"
|
||||
@ -275,7 +276,7 @@ func (x *FvmExtern) workerKeyAtLookback(ctx context.Context, minerId address.Add
|
||||
return address.Undef, gasUsed, err
|
||||
}
|
||||
|
||||
raddr, err := ResolveToKeyAddr(stateTree, cstWithGas, info.Worker)
|
||||
raddr, err := ResolveToDeterministicAddr(stateTree, cstWithGas, info.Worker)
|
||||
if err != nil {
|
||||
return address.Undef, gasUsed, err
|
||||
}
|
||||
@ -285,6 +286,7 @@ func (x *FvmExtern) workerKeyAtLookback(ctx context.Context, minerId address.Add
|
||||
|
||||
type FVM struct {
|
||||
fvm *ffi.FVM
|
||||
nv network.Version
|
||||
}
|
||||
|
||||
func defaultFVMOpts(ctx context.Context, opts *VMOpts) (*ffi.FVMOpts, error) {
|
||||
@ -309,11 +311,14 @@ func defaultFVMOpts(ctx context.Context, opts *VMOpts) (*ffi.FVMOpts, error) {
|
||||
epoch: opts.Epoch,
|
||||
},
|
||||
Epoch: opts.Epoch,
|
||||
Timestamp: opts.Timestamp,
|
||||
ChainID: build.Eip155ChainId,
|
||||
BaseFee: opts.BaseFee,
|
||||
BaseCircSupply: circToReport,
|
||||
NetworkVersion: opts.NetworkVersion,
|
||||
StateBase: opts.StateBase,
|
||||
Tracing: opts.Tracing || EnableDetailedTracing,
|
||||
Debug: build.ActorDebugging,
|
||||
}, nil
|
||||
|
||||
}
|
||||
@ -324,20 +329,6 @@ func NewFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
|
||||
return nil, xerrors.Errorf("creating fvm opts: %w", err)
|
||||
}
|
||||
|
||||
if os.Getenv("LOTUS_USE_FVM_CUSTOM_BUNDLE") == "1" {
|
||||
av, err := actorstypes.VersionForNetwork(opts.NetworkVersion)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("mapping network version to actors version: %w", err)
|
||||
}
|
||||
|
||||
c, ok := actors.GetManifest(av)
|
||||
if !ok {
|
||||
return nil, xerrors.Errorf("no manifest for custom bundle (actors version %d)", av)
|
||||
}
|
||||
|
||||
fvmOpts.Manifest = c
|
||||
}
|
||||
|
||||
fvm, err := ffi.CreateFVM(fvmOpts)
|
||||
|
||||
if err != nil {
|
||||
@ -346,6 +337,7 @@ func NewFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
|
||||
|
||||
return &FVM{
|
||||
fvm: fvm,
|
||||
nv: opts.NetworkVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -448,6 +440,7 @@ func NewDebugFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
|
||||
|
||||
return &FVM{
|
||||
fvm: fvm,
|
||||
nv: opts.NetworkVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -466,10 +459,12 @@ func (vm *FVM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet
|
||||
}
|
||||
|
||||
duration := time.Since(start)
|
||||
receipt := types.MessageReceipt{
|
||||
Return: ret.Return,
|
||||
ExitCode: exitcode.ExitCode(ret.ExitCode),
|
||||
GasUsed: ret.GasUsed,
|
||||
|
||||
var receipt types.MessageReceipt
|
||||
if vm.nv >= network.Version18 {
|
||||
receipt = types.NewMessageReceiptV1(exitcode.ExitCode(ret.ExitCode), ret.Return, ret.GasUsed, ret.EventsRoot)
|
||||
} else {
|
||||
receipt = types.NewMessageReceiptV0(exitcode.ExitCode(ret.ExitCode), ret.Return, ret.GasUsed)
|
||||
}
|
||||
|
||||
var aerr aerrors.ActorError
|
||||
@ -530,10 +525,12 @@ func (vm *FVM) ApplyImplicitMessage(ctx context.Context, cmsg *types.Message) (*
|
||||
}
|
||||
|
||||
duration := time.Since(start)
|
||||
receipt := types.MessageReceipt{
|
||||
Return: ret.Return,
|
||||
ExitCode: exitcode.ExitCode(ret.ExitCode),
|
||||
GasUsed: ret.GasUsed,
|
||||
|
||||
var receipt types.MessageReceipt
|
||||
if vm.nv >= network.Version18 {
|
||||
receipt = types.NewMessageReceiptV1(exitcode.ExitCode(ret.ExitCode), ret.Return, ret.GasUsed, ret.EventsRoot)
|
||||
} else {
|
||||
receipt = types.NewMessageReceiptV0(exitcode.ExitCode(ret.ExitCode), ret.Return, ret.GasUsed)
|
||||
}
|
||||
|
||||
var aerr aerrors.ActorError
|
||||
|
@ -111,6 +111,7 @@ var Prices = map[abi.ChainEpoch]Pricelist{
|
||||
verifySignature: map[crypto.SigType]int64{
|
||||
crypto.SigTypeBLS: 16598605,
|
||||
crypto.SigTypeSecp256k1: 1637292,
|
||||
crypto.SigTypeDelegated: 1637292,
|
||||
},
|
||||
|
||||
hashingBase: 31355,
|
||||
|
@ -284,16 +284,16 @@ func DecodeParams(b []byte, out interface{}) error {
|
||||
}
|
||||
|
||||
func DumpActorState(i *ActorRegistry, act *types.Actor, b []byte) (interface{}, error) {
|
||||
if builtin.IsAccountActor(act.Code) { // Account code special case
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
actInfo, ok := i.actors[act.Code]
|
||||
if !ok {
|
||||
return nil, xerrors.Errorf("state type for actor %s not found", act.Code)
|
||||
}
|
||||
|
||||
um := actInfo.vmActor.State()
|
||||
if um == nil {
|
||||
// TODO::FVM @arajasek I would like to assert that we have the empty object here
|
||||
return nil, nil
|
||||
}
|
||||
if err := um.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
|
||||
return nil, xerrors.Errorf("unmarshaling actor state: %w", err)
|
||||
}
|
||||
|
@ -168,8 +168,8 @@ func (rt *Runtime) shimCall(f func() interface{}) (rval []byte, aerr aerrors.Act
|
||||
aerr = ar
|
||||
return
|
||||
}
|
||||
//log.Desugar().WithOptions(zap.AddStacktrace(zapcore.ErrorLevel)).
|
||||
//Sugar().Errorf("spec actors failure: %s", r)
|
||||
// log.Desugar().WithOptions(zap.AddStacktrace(zapcore.ErrorLevel)).
|
||||
// Sugar().Errorf("spec actors failure: %s", r)
|
||||
log.Errorf("spec actors failure: %s", r)
|
||||
if rt.NetworkVersion() <= network.Version3 {
|
||||
aerr = aerrors.Newf(1, "spec actors failure: %s", r)
|
||||
@ -249,7 +249,7 @@ func (rt *Runtime) GetRandomnessFromBeacon(personalization crypto.DomainSeparati
|
||||
|
||||
func (rt *Runtime) NewActorAddress() address.Address {
|
||||
var b bytes.Buffer
|
||||
oa, _ := ResolveToKeyAddr(rt.vm.cstate, rt.vm.cst, rt.origin)
|
||||
oa, _ := ResolveToDeterministicAddr(rt.vm.cstate, rt.vm.cst, rt.origin)
|
||||
if err := oa.MarshalCBOR(&b); err != nil { // todo: spec says cbor; why not just bytes?
|
||||
panic(aerrors.Fatalf("writing caller address into a buffer: %v", err))
|
||||
}
|
||||
|
@ -255,7 +255,7 @@ func (ss *syscallShim) workerKeyAtLookback(height abi.ChainEpoch) (address.Addre
|
||||
return address.Undef, err
|
||||
}
|
||||
|
||||
return ResolveToKeyAddr(ss.cstate, ss.cst, info.Worker)
|
||||
return ResolveToDeterministicAddr(ss.cstate, ss.cst, info.Worker)
|
||||
}
|
||||
|
||||
func (ss *syscallShim) VerifyPoSt(info proof7.WindowPoStVerifyInfo) error {
|
||||
@ -270,8 +270,8 @@ func (ss *syscallShim) VerifyPoSt(info proof7.WindowPoStVerifyInfo) error {
|
||||
}
|
||||
|
||||
func (ss *syscallShim) VerifySeal(info proof7.SealVerifyInfo) error {
|
||||
//_, span := trace.StartSpan(ctx, "ValidatePoRep")
|
||||
//defer span.End()
|
||||
// _, span := trace.StartSpan(ctx, "ValidatePoRep")
|
||||
// defer span.End()
|
||||
|
||||
miner, err := address.NewIDAddress(uint64(info.Miner))
|
||||
if err != nil {
|
||||
@ -284,7 +284,7 @@ func (ss *syscallShim) VerifySeal(info proof7.SealVerifyInfo) error {
|
||||
|
||||
log.Debugf("Verif r:%s; d:%s; m:%s; t:%x; s:%x; N:%d; p:%x", info.SealedCID, info.UnsealedCID, miner, ticket, seed, info.SectorID.Number, proof)
|
||||
|
||||
//func(ctx context.Context, maddr address.Address, ssize abi.SectorSize, commD, commR, ticket, proof, seed []byte, sectorID abi.SectorNumber)
|
||||
// func(ctx context.Context, maddr address.Address, ssize abi.SectorSize, commD, commR, ticket, proof, seed []byte, sectorID abi.SectorNumber)
|
||||
ok, err := ss.verifier.VerifySeal(info)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to validate PoRep: %w", err)
|
||||
@ -325,7 +325,7 @@ func (ss *syscallShim) VerifyReplicaUpdate(update proof7.ReplicaUpdateInfo) erro
|
||||
func (ss *syscallShim) VerifySignature(sig crypto.Signature, addr address.Address, input []byte) error {
|
||||
// TODO: in genesis setup, we are currently faking signatures
|
||||
|
||||
kaddr, err := ResolveToKeyAddr(ss.cstate, ss.cst, addr)
|
||||
kaddr, err := ResolveToDeterministicAddr(ss.cstate, ss.cst, addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -45,9 +45,11 @@ var (
|
||||
gasOnActorExec = newGasCharge("OnActorExec", 0, 0)
|
||||
)
|
||||
|
||||
// ResolveToKeyAddr returns the public key type of address (`BLS`/`SECP256K1`) of an account actor identified by `addr`.
|
||||
func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, error) {
|
||||
if addr.Protocol() == address.BLS || addr.Protocol() == address.SECP256K1 {
|
||||
// ResolveToDeterministicAddr returns the public key type of address
|
||||
// (`BLS`/`SECP256K1`) of an actor identified by `addr`, or its
|
||||
// delegated address.
|
||||
func ResolveToDeterministicAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, error) {
|
||||
if addr.Protocol() == address.BLS || addr.Protocol() == address.SECP256K1 || addr.Protocol() == address.Delegated {
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
@ -56,12 +58,19 @@ func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Ad
|
||||
return address.Undef, xerrors.Errorf("failed to find actor: %s", addr)
|
||||
}
|
||||
|
||||
if state.Version() >= types.StateTreeVersion5 {
|
||||
if act.Address != nil {
|
||||
// If there _is_ an f4 address, return it as "key" address
|
||||
return *act.Address, nil
|
||||
}
|
||||
}
|
||||
|
||||
aast, err := account.Load(adt.WrapStore(context.TODO(), cst), act)
|
||||
if err != nil {
|
||||
return address.Undef, xerrors.Errorf("failed to get account actor state for %s: %w", addr, err)
|
||||
}
|
||||
|
||||
return aast.PubkeyAddress()
|
||||
|
||||
}
|
||||
|
||||
var (
|
||||
@ -216,6 +225,7 @@ type LegacyVM struct {
|
||||
type VMOpts struct {
|
||||
StateBase cid.Cid
|
||||
Epoch abi.ChainEpoch
|
||||
Timestamp uint64
|
||||
Rand Rand
|
||||
Bstore blockstore.Blockstore
|
||||
Actors *ActorRegistry
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"github.com/filecoin-project/go-state-types/crypto"
|
||||
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
)
|
||||
|
||||
@ -50,6 +51,22 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) {
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err)
|
||||
}
|
||||
case types.KTDelegated:
|
||||
// Transitory Delegated signature verification as per FIP-0055
|
||||
ethAddr, err := ethtypes.EthAddressFromPubKey(k.PublicKey)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to calculate Eth address from public key: %w", err)
|
||||
}
|
||||
|
||||
ea, err := ethtypes.CastEthAddress(ethAddr)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to create ethereum address from bytes: %w", err)
|
||||
}
|
||||
|
||||
k.Address, err = ea.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("converting Delegated to address: %w", err)
|
||||
}
|
||||
case types.KTBLS:
|
||||
k.Address, err = address.NewBLSAddress(k.PublicKey)
|
||||
if err != nil {
|
||||
@ -58,6 +75,7 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) {
|
||||
default:
|
||||
return nil, xerrors.Errorf("unsupported key type: %s", k.Type)
|
||||
}
|
||||
|
||||
return k, nil
|
||||
|
||||
}
|
||||
@ -68,6 +86,8 @@ func ActSigType(typ types.KeyType) crypto.SigType {
|
||||
return crypto.SigTypeBLS
|
||||
case types.KTSecp256k1:
|
||||
return crypto.SigTypeSecp256k1
|
||||
case types.KTDelegated:
|
||||
return crypto.SigTypeDelegated
|
||||
default:
|
||||
return crypto.SigTypeUnknown
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/wallet/key"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures
|
||||
)
|
||||
|
||||
|
@ -149,7 +149,7 @@ var ChainGetBlock = &cli.Command{
|
||||
recpts, err := api.ChainGetParentReceipts(ctx, bcid)
|
||||
if err != nil {
|
||||
log.Warn(err)
|
||||
//return xerrors.Errorf("failed to get receipts: %w", err)
|
||||
// return xerrors.Errorf("failed to get receipts: %w", err)
|
||||
}
|
||||
|
||||
cblock := struct {
|
||||
|
@ -81,6 +81,7 @@ var Commands = []*cli.Command{
|
||||
WithCategory("developer", LogCmd),
|
||||
WithCategory("developer", WaitApiCmd),
|
||||
WithCategory("developer", FetchParamCmd),
|
||||
WithCategory("developer", EvmCmd),
|
||||
WithCategory("network", NetCmd),
|
||||
WithCategory("network", SyncCmd),
|
||||
WithCategory("status", StatusCmd),
|
||||
|
503
cli/evm.go
Normal file
503
cli/evm.go
Normal file
@ -0,0 +1,503 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/urfave/cli/v2"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/filecoin-project/go-address"
|
||||
amt4 "github.com/filecoin-project/go-amt-ipld/v4"
|
||||
"github.com/filecoin-project/go-state-types/abi"
|
||||
"github.com/filecoin-project/go-state-types/big"
|
||||
builtintypes "github.com/filecoin-project/go-state-types/builtin"
|
||||
"github.com/filecoin-project/go-state-types/builtin/v10/eam"
|
||||
|
||||
"github.com/filecoin-project/lotus/api/v0api"
|
||||
"github.com/filecoin-project/lotus/chain/actors"
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/types/ethtypes"
|
||||
)
|
||||
|
||||
var EvmCmd = &cli.Command{
|
||||
Name: "evm",
|
||||
Usage: "Commands related to the Filecoin EVM runtime",
|
||||
Subcommands: []*cli.Command{
|
||||
EvmDeployCmd,
|
||||
EvmInvokeCmd,
|
||||
EvmGetInfoCmd,
|
||||
EvmCallSimulateCmd,
|
||||
EvmGetContractAddress,
|
||||
},
|
||||
}
|
||||
|
||||
var EvmGetInfoCmd = &cli.Command{
|
||||
Name: "stat",
|
||||
Usage: "Print eth/filecoin addrs and code cid",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "filAddr",
|
||||
Usage: "Filecoin address",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "ethAddr",
|
||||
Usage: "Ethereum address",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
|
||||
filAddr := cctx.String("filAddr")
|
||||
ethAddr := cctx.String("ethAddr")
|
||||
|
||||
var faddr address.Address
|
||||
var eaddr ethtypes.EthAddress
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if filAddr != "" {
|
||||
addr, err := address.NewFromString(filAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
eaddr, faddr, err = ethAddrFromFilecoinAddress(ctx, addr, api)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if ethAddr != "" {
|
||||
eaddr, err = ethtypes.ParseEthAddress(ethAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
faddr, err = eaddr.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
return xerrors.Errorf("Neither filAddr nor ethAddr specified")
|
||||
}
|
||||
|
||||
actor, err := api.StateGetActor(ctx, faddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Filecoin address: ", faddr)
|
||||
fmt.Println("Eth address: ", eaddr)
|
||||
fmt.Println("Code cid: ", actor.Code.String())
|
||||
|
||||
return nil
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
var EvmCallSimulateCmd = &cli.Command{
|
||||
Name: "call",
|
||||
Usage: "Simulate an eth contract call",
|
||||
ArgsUsage: "[from] [to] [params]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
|
||||
if cctx.NArg() != 3 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
fromEthAddr, err := ethtypes.ParseEthAddress(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toEthAddr, err := ethtypes.ParseEthAddress(cctx.Args().Get(1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
params, err := hex.DecodeString(cctx.Args().Get(2))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
api, closer, err := GetFullNodeAPIV1(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
res, err := api.EthCall(ctx, ethtypes.EthCall{
|
||||
From: &fromEthAddr,
|
||||
To: &toEthAddr,
|
||||
Data: params,
|
||||
}, "")
|
||||
if err != nil {
|
||||
fmt.Println("Eth call fails, return val: ", res)
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Result: ", res)
|
||||
|
||||
return nil
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
var EvmGetContractAddress = &cli.Command{
|
||||
Name: "contract-address",
|
||||
Usage: "Generate contract address from smart contract code",
|
||||
ArgsUsage: "[senderEthAddr] [salt] [contractHexPath]",
|
||||
Action: func(cctx *cli.Context) error {
|
||||
|
||||
if cctx.NArg() != 3 {
|
||||
return IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
sender, err := ethtypes.ParseEthAddress(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
salt, err := hex.DecodeString(cctx.Args().Get(1))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Could not decode salt: %w", err)
|
||||
}
|
||||
if len(salt) > 32 {
|
||||
return xerrors.Errorf("Len of salt bytes greater than 32")
|
||||
}
|
||||
var fsalt [32]byte
|
||||
copy(fsalt[:], salt[:])
|
||||
|
||||
contractBin := cctx.Args().Get(2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
contractHex, err := os.ReadFile(contractBin)
|
||||
if err != nil {
|
||||
|
||||
return err
|
||||
}
|
||||
contract, err := hex.DecodeString(string(contractHex))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("Could not decode contract file: %w", err)
|
||||
}
|
||||
|
||||
contractAddr, err := ethtypes.GetContractEthAddressFromCode(sender, fsalt, contract)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Contract Eth address: ", contractAddr)
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var EvmDeployCmd = &cli.Command{
|
||||
Name: "deploy",
|
||||
Usage: "Deploy an EVM smart contract and return its address",
|
||||
ArgsUsage: "contract",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "from",
|
||||
Usage: "optionally specify the account to use for sending the creation message",
|
||||
},
|
||||
&cli.BoolFlag{
|
||||
Name: "hex",
|
||||
Usage: "use when input contract is in hex",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if argc := cctx.Args().Len(); argc != 1 {
|
||||
return xerrors.Errorf("must pass the contract init code")
|
||||
}
|
||||
|
||||
contract, err := os.ReadFile(cctx.Args().First())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to read contract: %w", err)
|
||||
}
|
||||
if cctx.Bool("hex") {
|
||||
contract, err = hex.DecodeString(string(contract))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to decode contract: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
var fromAddr address.Address
|
||||
if from := cctx.String("from"); from == "" {
|
||||
fromAddr, err = api.WalletDefaultAddress(ctx)
|
||||
} else {
|
||||
fromAddr, err = address.NewFromString(from)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nonce, err := api.MpoolGetNonce(ctx, fromAddr)
|
||||
if err != nil {
|
||||
nonce = 0 // assume a zero nonce on error (e.g. sender doesn't exist).
|
||||
}
|
||||
|
||||
params, err := actors.SerializeParams(&eam.CreateParams{
|
||||
Initcode: contract,
|
||||
Nonce: nonce,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to serialize Create params: %w", err)
|
||||
}
|
||||
|
||||
msg := &types.Message{
|
||||
To: builtintypes.EthereumAddressManagerActorAddr,
|
||||
From: fromAddr,
|
||||
Value: big.Zero(),
|
||||
Method: builtintypes.MethodsEAM.Create,
|
||||
Params: params,
|
||||
}
|
||||
|
||||
// TODO: On Jan 11th, we decided to add an `EAM#create_external` method
|
||||
// that uses the nonce of the caller instead of taking a user-supplied nonce.
|
||||
// Track: https://github.com/filecoin-project/ref-fvm/issues/1255
|
||||
// When that's implemented, we should migrate the CLI to use that,
|
||||
// as `EAM#create` will be reserved for the EVM runtime actor.
|
||||
// TODO: this is very racy. It may assign a _different_ nonce than the expected one.
|
||||
afmt.Println("sending message...")
|
||||
smsg, err := api.MpoolPushMessage(ctx, msg, nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to push message: %w", err)
|
||||
}
|
||||
|
||||
afmt.Println("waiting for message to execute...")
|
||||
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), 0)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error waiting for message: %w", err)
|
||||
}
|
||||
|
||||
// check it executed successfully
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
return xerrors.Errorf("actor execution failed")
|
||||
}
|
||||
|
||||
var result eam.CreateReturn
|
||||
r := bytes.NewReader(wait.Receipt.Return)
|
||||
if err := result.UnmarshalCBOR(r); err != nil {
|
||||
return xerrors.Errorf("error unmarshaling return value: %w", err)
|
||||
}
|
||||
|
||||
addr, err := address.NewIDAddress(result.ActorID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
afmt.Printf("Actor ID: %d\n", result.ActorID)
|
||||
afmt.Printf("ID Address: %s\n", addr)
|
||||
afmt.Printf("Robust Address: %s\n", result.RobustAddress)
|
||||
afmt.Printf("Eth Address: %s\n", "0x"+hex.EncodeToString(result.EthAddress[:]))
|
||||
|
||||
ea, err := ethtypes.CastEthAddress(result.EthAddress[:])
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create ethereum address: %w", err)
|
||||
}
|
||||
|
||||
delegated, err := ea.ToFilecoinAddress()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to calculate f4 address: %w", err)
|
||||
}
|
||||
|
||||
afmt.Printf("f4 Address: %s\n", delegated)
|
||||
|
||||
if len(wait.Receipt.Return) > 0 {
|
||||
result := base64.StdEncoding.EncodeToString(wait.Receipt.Return)
|
||||
afmt.Printf("Return: %s\n", result)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
var EvmInvokeCmd = &cli.Command{
|
||||
Name: "invoke",
|
||||
Usage: "Invoke an EVM smart contract using the specified CALLDATA",
|
||||
ArgsUsage: "address calldata",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "from",
|
||||
Usage: "optionally specify the account to use for sending the exec message",
|
||||
}, &cli.IntFlag{
|
||||
Name: "value",
|
||||
Usage: "optionally specify the value to be sent with the invokation message",
|
||||
},
|
||||
},
|
||||
Action: func(cctx *cli.Context) error {
|
||||
afmt := NewAppFmt(cctx.App)
|
||||
|
||||
api, closer, err := GetFullNodeAPI(cctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer()
|
||||
ctx := ReqContext(cctx)
|
||||
|
||||
if argc := cctx.Args().Len(); argc < 2 || argc > 3 {
|
||||
return xerrors.Errorf("must pass the address, entry point and (optionally) input data")
|
||||
}
|
||||
|
||||
addr, err := address.NewFromString(cctx.Args().Get(0))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to decode address: %w", err)
|
||||
}
|
||||
|
||||
var calldata []byte
|
||||
calldata, err = hex.DecodeString(cctx.Args().Get(2))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("decoding hex input data: %w", err)
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
if err := cbg.WriteByteArray(&buffer, calldata); err != nil {
|
||||
return xerrors.Errorf("failed to encode evm params as cbor: %w", err)
|
||||
}
|
||||
calldata = buffer.Bytes()
|
||||
|
||||
var fromAddr address.Address
|
||||
if from := cctx.String("from"); from == "" {
|
||||
defaddr, err := api.WalletDefaultAddress(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fromAddr = defaddr
|
||||
} else {
|
||||
addr, err := address.NewFromString(from)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fromAddr = addr
|
||||
}
|
||||
|
||||
val := abi.NewTokenAmount(cctx.Int64("value"))
|
||||
msg := &types.Message{
|
||||
To: addr,
|
||||
From: fromAddr,
|
||||
Value: val,
|
||||
Method: abi.MethodNum(2),
|
||||
Params: calldata,
|
||||
}
|
||||
|
||||
afmt.Println("sending message...")
|
||||
smsg, err := api.MpoolPushMessage(ctx, msg, nil)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to push message: %w", err)
|
||||
}
|
||||
|
||||
afmt.Println("waiting for message to execute...")
|
||||
wait, err := api.StateWaitMsg(ctx, smsg.Cid(), 0)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("error waiting for message: %w", err)
|
||||
}
|
||||
|
||||
// check it executed successfully
|
||||
if wait.Receipt.ExitCode != 0 {
|
||||
return xerrors.Errorf("actor execution failed")
|
||||
}
|
||||
|
||||
afmt.Println("Gas used: ", wait.Receipt.GasUsed)
|
||||
result, err := cbg.ReadByteArray(bytes.NewBuffer(wait.Receipt.Return), uint64(len(wait.Receipt.Return)))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("evm result not correctly encoded: %w", err)
|
||||
}
|
||||
|
||||
if len(result) > 0 {
|
||||
afmt.Println(hex.EncodeToString(result))
|
||||
} else {
|
||||
afmt.Println("OK")
|
||||
}
|
||||
|
||||
if eventsRoot := wait.Receipt.EventsRoot; eventsRoot != nil {
|
||||
afmt.Println("Events emitted:")
|
||||
|
||||
s := &apiIpldStore{ctx, api}
|
||||
amt, err := amt4.LoadAMT(ctx, s, *eventsRoot, amt4.UseTreeBitWidth(types.EventAMTBitwidth))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var evt types.Event
|
||||
err = amt.ForEach(ctx, func(u uint64, deferred *cbg.Deferred) error {
|
||||
fmt.Printf("%x\n", deferred.Raw)
|
||||
if err := evt.UnmarshalCBOR(bytes.NewReader(deferred.Raw)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("\tEmitter ID: %s\n", evt.Emitter)
|
||||
for _, e := range evt.Entries {
|
||||
value, err := cbg.ReadByteArray(bytes.NewBuffer(e.Value), uint64(len(e.Value)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("\t\tKey: %s, Value: 0x%x, Flags: b%b\n", e.Key, value, e.Flags)
|
||||
}
|
||||
return nil
|
||||
|
||||
})
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func ethAddrFromFilecoinAddress(ctx context.Context, addr address.Address, fnapi v0api.FullNode) (ethtypes.EthAddress, address.Address, error) {
|
||||
var faddr address.Address
|
||||
var err error
|
||||
|
||||
switch addr.Protocol() {
|
||||
case address.BLS, address.SECP256K1:
|
||||
faddr, err = fnapi.StateLookupID(ctx, addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return ethtypes.EthAddress{}, addr, err
|
||||
}
|
||||
case address.Actor, address.ID:
|
||||
faddr, err = fnapi.StateLookupID(ctx, addr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return ethtypes.EthAddress{}, addr, err
|
||||
}
|
||||
fAct, err := fnapi.StateGetActor(ctx, faddr, types.EmptyTSK)
|
||||
if err != nil {
|
||||
return ethtypes.EthAddress{}, addr, err
|
||||
}
|
||||
if fAct.Address != nil && (*fAct.Address).Protocol() == address.Delegated {
|
||||
faddr = *fAct.Address
|
||||
}
|
||||
case address.Delegated:
|
||||
faddr = addr
|
||||
default:
|
||||
return ethtypes.EthAddress{}, addr, xerrors.Errorf("Filecoin address doesn't match known protocols")
|
||||
}
|
||||
|
||||
ethAddr, err := ethtypes.EthAddressFromFilecoinAddress(faddr)
|
||||
if err != nil {
|
||||
return ethtypes.EthAddress{}, addr, err
|
||||
}
|
||||
|
||||
return ethAddr, faddr, nil
|
||||
}
|
@ -776,6 +776,7 @@ var StateGetActorCmd = &cli.Command{
|
||||
fmt.Printf("Nonce:\t\t%d\n", a.Nonce)
|
||||
fmt.Printf("Code:\t\t%s (%s)\n", a.Code, strtype)
|
||||
fmt.Printf("Head:\t\t%s\n", a.Head)
|
||||
fmt.Printf("Delegated address:\t\t%s\n", a.Address)
|
||||
|
||||
return nil
|
||||
},
|
||||
|
@ -41,6 +41,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
lcli "github.com/filecoin-project/lotus/cli"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
"github.com/filecoin-project/lotus/node/repo"
|
||||
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
)
|
||||
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/wallet"
|
||||
"github.com/filecoin-project/lotus/chain/wallet/key"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
"github.com/filecoin-project/lotus/node/modules"
|
||||
"github.com/filecoin-project/lotus/node/modules/lp2p"
|
||||
|
@ -4,10 +4,10 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/ipfs/go-cid"
|
||||
logging "github.com/ipfs/go-log/v2"
|
||||
"github.com/urfave/cli/v2"
|
||||
cbg "github.com/whyrusleeping/cbor-gen"
|
||||
"golang.org/x/xerrors"
|
||||
@ -25,6 +25,8 @@ import (
|
||||
adt9 "github.com/filecoin-project/go-state-types/builtin/v9/util/adt"
|
||||
verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg"
|
||||
"github.com/filecoin-project/go-state-types/manifest"
|
||||
mutil "github.com/filecoin-project/go-state-types/migration"
|
||||
"github.com/filecoin-project/go-state-types/network"
|
||||
"github.com/filecoin-project/specs-actors/v7/actors/migration/nv15"
|
||||
|
||||
"github.com/filecoin-project/lotus/blockstore"
|
||||
@ -47,9 +49,9 @@ import (
|
||||
)
|
||||
|
||||
var migrationsCmd = &cli.Command{
|
||||
Name: "migrate-nv17",
|
||||
Description: "Run the nv17 migration",
|
||||
ArgsUsage: "[block to look back from]",
|
||||
Name: "migrate-state",
|
||||
Description: "Run a network upgrade migration",
|
||||
ArgsUsage: "[new network version, block to look back from]",
|
||||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "repo",
|
||||
@ -65,16 +67,21 @@ var migrationsCmd = &cli.Command{
|
||||
Action: func(cctx *cli.Context) error {
|
||||
ctx := context.TODO()
|
||||
|
||||
err := logging.SetLogLevelRegex("badger*", "ERROR")
|
||||
if cctx.NArg() != 2 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
nv, err := strconv.ParseUint(cctx.Args().Get(0), 10, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse network version: %w", err)
|
||||
}
|
||||
|
||||
upgradeActorsFunc, preUpgradeActorsFunc, checkInvariantsFunc, err := getMigrationFuncsForNetwork(network.Version(nv))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cctx.NArg() != 1 {
|
||||
return lcli.IncorrectNumArgs(cctx)
|
||||
}
|
||||
|
||||
blkCid, err := cid.Decode(cctx.Args().First())
|
||||
blkCid, err := cid.Decode(cctx.Args().Get(1))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to parse input: %w", err)
|
||||
}
|
||||
@ -129,7 +136,7 @@ var migrationsCmd = &cli.Command{
|
||||
|
||||
startTime := time.Now()
|
||||
|
||||
newCid2, err := filcns.UpgradeActorsV9(ctx, sm, nv15.NewMemMigrationCache(), nil, blk.ParentStateRoot, blk.Height-1, migrationTs)
|
||||
newCid2, err := upgradeActorsFunc(ctx, sm, nv15.NewMemMigrationCache(), nil, blk.ParentStateRoot, blk.Height-1, migrationTs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -142,7 +149,7 @@ var migrationsCmd = &cli.Command{
|
||||
fmt.Println("completed round actual (without cache), took ", uncachedMigrationTime)
|
||||
|
||||
if !cctx.IsSet("skip-pre-migration") {
|
||||
cache := nv15.NewMemMigrationCache()
|
||||
cache := mutil.NewMemMigrationCache()
|
||||
|
||||
ts1, err := cs.GetTipsetByHeight(ctx, blk.Height-240, migrationTs, false)
|
||||
if err != nil {
|
||||
@ -151,7 +158,7 @@ var migrationsCmd = &cli.Command{
|
||||
|
||||
startTime = time.Now()
|
||||
|
||||
err = filcns.PreUpgradeActorsV9(ctx, sm, cache, ts1.ParentState(), ts1.Height()-1, ts1)
|
||||
err = preUpgradeActorsFunc(ctx, sm, cache, ts1.ParentState(), ts1.Height()-1, ts1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -165,7 +172,7 @@ var migrationsCmd = &cli.Command{
|
||||
|
||||
startTime = time.Now()
|
||||
|
||||
err = filcns.PreUpgradeActorsV9(ctx, sm, cache, ts2.ParentState(), ts2.Height()-1, ts2)
|
||||
err = preUpgradeActorsFunc(ctx, sm, cache, ts2.ParentState(), ts2.Height()-1, ts2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -174,7 +181,7 @@ var migrationsCmd = &cli.Command{
|
||||
|
||||
startTime = time.Now()
|
||||
|
||||
newCid1, err := filcns.UpgradeActorsV9(ctx, sm, cache, nil, blk.ParentStateRoot, blk.Height-1, migrationTs)
|
||||
newCid1, err := upgradeActorsFunc(ctx, sm, cache, nil, blk.ParentStateRoot, blk.Height-1, migrationTs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -191,7 +198,10 @@ var migrationsCmd = &cli.Command{
|
||||
}
|
||||
|
||||
if cctx.Bool("check-invariants") {
|
||||
err = checkMigrationInvariants(ctx, blk.ParentStateRoot, newCid2, bs, blk.Height-1)
|
||||
if checkInvariantsFunc == nil {
|
||||
return xerrors.Errorf("check invariants not implemented for nv%d", nv)
|
||||
}
|
||||
err = checkInvariantsFunc(ctx, blk.ParentStateRoot, newCid2, bs, blk.Height-1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -201,7 +211,22 @@ var migrationsCmd = &cli.Command{
|
||||
},
|
||||
}
|
||||
|
||||
func checkMigrationInvariants(ctx context.Context, v8StateRootCid cid.Cid, v9StateRootCid cid.Cid, bs blockstore.Blockstore, epoch abi.ChainEpoch) error {
|
||||
func getMigrationFuncsForNetwork(nv network.Version) (UpgradeActorsFunc, PreUpgradeActorsFunc, CheckInvariantsFunc, error) {
|
||||
switch nv {
|
||||
case network.Version17:
|
||||
return filcns.UpgradeActorsV9, filcns.PreUpgradeActorsV9, checkNv17Invariants, nil
|
||||
case network.Version18:
|
||||
return filcns.UpgradeActorsV10, filcns.PreUpgradeActorsV10, nil, nil
|
||||
default:
|
||||
return nil, nil, nil, xerrors.Errorf("migration not implemented for nv%d", nv)
|
||||
}
|
||||
}
|
||||
|
||||
type UpgradeActorsFunc = func(context.Context, *stmgr.StateManager, stmgr.MigrationCache, stmgr.ExecMonitor, cid.Cid, abi.ChainEpoch, *types.TipSet) (cid.Cid, error)
|
||||
type PreUpgradeActorsFunc = func(context.Context, *stmgr.StateManager, stmgr.MigrationCache, cid.Cid, abi.ChainEpoch, *types.TipSet) error
|
||||
type CheckInvariantsFunc = func(context.Context, cid.Cid, cid.Cid, blockstore.Blockstore, abi.ChainEpoch) error
|
||||
|
||||
func checkNv17Invariants(ctx context.Context, v8StateRootCid cid.Cid, v9StateRootCid cid.Cid, bs blockstore.Blockstore, epoch abi.ChainEpoch) error {
|
||||
actorStore := store.ActorStore(ctx, bs)
|
||||
startTime := time.Now()
|
||||
|
||||
|
@ -74,14 +74,17 @@ func (sim *Simulation) makeTipSet(ctx context.Context, messages []*types.Message
|
||||
Timestamp: uts,
|
||||
ElectionProof: &types.ElectionProof{WinCount: 1},
|
||||
}}
|
||||
err = sim.Node.Chainstore.PersistBlockHeaders(ctx, blks...)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to persist block headers: %w", err)
|
||||
}
|
||||
|
||||
newTipSet, err := types.NewTipSet(blks)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to create new tipset: %w", err)
|
||||
}
|
||||
|
||||
err = sim.Node.Chainstore.PersistTipset(ctx, newTipSet)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("failed to persist block headers: %w", err)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
_, _, err = sim.StateManager.TipSetState(ctx, newTipSet)
|
||||
if err != nil {
|
||||
|
@ -28,6 +28,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/vm"
|
||||
"github.com/filecoin-project/lotus/conformance/chaos"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls" // enable bls signatures
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp" // enable secp signatures
|
||||
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
|
||||
)
|
||||
|
@ -464,7 +464,9 @@ Inputs:
|
||||
{
|
||||
"SealProof": 8,
|
||||
"SectorNumber": 9,
|
||||
"SectorKey": null,
|
||||
"SectorKey": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"SealedCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
@ -1279,8 +1281,12 @@ Response:
|
||||
"ProposalCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"AddFundsCid": null,
|
||||
"PublishCid": null,
|
||||
"AddFundsCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PublishCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Miner": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
|
||||
"Client": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
|
||||
"State": 42,
|
||||
@ -1295,7 +1301,9 @@ Response:
|
||||
"Root": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceCid": null,
|
||||
"PieceCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceSize": 1024,
|
||||
"RawBlockSize": 42
|
||||
},
|
||||
@ -1457,8 +1465,12 @@ Response:
|
||||
"ProposalCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"AddFundsCid": null,
|
||||
"PublishCid": null,
|
||||
"AddFundsCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PublishCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Miner": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
|
||||
"Client": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
|
||||
"State": 42,
|
||||
@ -1473,7 +1485,9 @@ Response:
|
||||
"Root": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceCid": null,
|
||||
"PieceCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceSize": 1024,
|
||||
"RawBlockSize": 42
|
||||
},
|
||||
@ -1509,7 +1523,9 @@ Response:
|
||||
"Selector": {
|
||||
"Raw": "Ynl0ZSBhcnJheQ=="
|
||||
},
|
||||
"PieceCID": null,
|
||||
"PieceCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PricePerByte": "0",
|
||||
"PaymentInterval": 42,
|
||||
"PaymentIntervalIncrease": 42,
|
||||
@ -2908,7 +2924,9 @@ Inputs:
|
||||
1024,
|
||||
{},
|
||||
{
|
||||
"PublishCid": null,
|
||||
"PublishCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"DealID": 5432,
|
||||
"DealProposal": {
|
||||
"PieceCID": {
|
||||
@ -2962,7 +2980,9 @@ Response:
|
||||
"FailedSectors": {
|
||||
"123": "can't acquire read lock"
|
||||
},
|
||||
"Msg": null,
|
||||
"Msg": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Error": "string value"
|
||||
}
|
||||
]
|
||||
@ -3156,7 +3176,9 @@ Response:
|
||||
123,
|
||||
124
|
||||
],
|
||||
"Msg": null,
|
||||
"Msg": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Error": "string value"
|
||||
}
|
||||
]
|
||||
@ -3204,7 +3226,9 @@ Inputs:
|
||||
}
|
||||
},
|
||||
"DealInfo": {
|
||||
"PublishCid": null,
|
||||
"PublishCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"DealID": 5432,
|
||||
"DealProposal": {
|
||||
"PieceCID": {
|
||||
@ -3232,8 +3256,12 @@ Inputs:
|
||||
"TicketValue": "Bw==",
|
||||
"TicketEpoch": 10101,
|
||||
"PreCommit1Out": "Bw==",
|
||||
"CommD": null,
|
||||
"CommR": null,
|
||||
"CommD": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"CommR": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PreCommitInfo": {
|
||||
"SealProof": 8,
|
||||
"SectorNumber": 9,
|
||||
@ -3245,10 +3273,14 @@ Inputs:
|
||||
5432
|
||||
],
|
||||
"Expiration": 10101,
|
||||
"UnsealedCid": null
|
||||
"UnsealedCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"PreCommitDeposit": "0",
|
||||
"PreCommitMessage": null,
|
||||
"PreCommitMessage": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PreCommitTipSet": [
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
@ -3260,7 +3292,9 @@ Inputs:
|
||||
"SeedValue": "Bw==",
|
||||
"SeedEpoch": 10101,
|
||||
"CommitProof": "Ynl0ZSBhcnJheQ==",
|
||||
"CommitMessage": null,
|
||||
"CommitMessage": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Log": [
|
||||
{
|
||||
"Kind": "string value",
|
||||
@ -3396,7 +3430,12 @@ Perms: admin
|
||||
|
||||
Inputs: `null`
|
||||
|
||||
Response: `null`
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
```
|
||||
|
||||
### SectorTerminatePending
|
||||
SectorTerminatePending returns a list of pending sector terminations to be sent in the next batch message
|
||||
@ -3497,8 +3536,12 @@ Response:
|
||||
{
|
||||
"SectorID": 9,
|
||||
"State": "Proving",
|
||||
"CommD": null,
|
||||
"CommR": null,
|
||||
"CommD": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"CommR": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Proof": "Ynl0ZSBhcnJheQ==",
|
||||
"Deals": [
|
||||
5432
|
||||
@ -3512,7 +3555,9 @@ Response:
|
||||
}
|
||||
},
|
||||
"DealInfo": {
|
||||
"PublishCid": null,
|
||||
"PublishCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"DealID": 5432,
|
||||
"DealProposal": {
|
||||
"PieceCID": {
|
||||
@ -3545,11 +3590,17 @@ Response:
|
||||
"Value": "Bw==",
|
||||
"Epoch": 10101
|
||||
},
|
||||
"PreCommitMsg": null,
|
||||
"CommitMsg": null,
|
||||
"PreCommitMsg": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"CommitMsg": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Retries": 42,
|
||||
"ToUpgrade": true,
|
||||
"ReplicaUpdateMessage": null,
|
||||
"ReplicaUpdateMessage": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"LastErr": "string value",
|
||||
"Log": [
|
||||
{
|
||||
@ -3603,7 +3654,9 @@ Inputs:
|
||||
1040384,
|
||||
1024,
|
||||
"Bw==",
|
||||
null
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
|
@ -754,7 +754,10 @@ Response:
|
||||
{
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
}
|
||||
]
|
||||
```
|
||||
@ -1247,7 +1250,9 @@ Inputs:
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
null
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
@ -1259,7 +1264,9 @@ Response:
|
||||
"Root": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Piece": null,
|
||||
"Piece": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Size": 42,
|
||||
"MinPrice": "0",
|
||||
"UnsealPrice": "0",
|
||||
@ -1270,7 +1277,9 @@ Response:
|
||||
"MinerPeer": {
|
||||
"Address": "f01234",
|
||||
"ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
|
||||
"PieceCID": null
|
||||
"PieceCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@ -1341,7 +1350,9 @@ Response:
|
||||
"Root": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceCid": null,
|
||||
"PieceCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceSize": 1024,
|
||||
"RawBlockSize": 42
|
||||
},
|
||||
@ -1445,7 +1456,9 @@ Response:
|
||||
"Root": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceCid": null,
|
||||
"PieceCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceSize": 1024,
|
||||
"RawBlockSize": 42
|
||||
},
|
||||
@ -1510,7 +1523,9 @@ Response:
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"ID": 5,
|
||||
"PieceCID": null,
|
||||
"PieceCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PricePerByte": "0",
|
||||
"UnsealPrice": "0",
|
||||
"Status": 0,
|
||||
@ -1683,7 +1698,9 @@ Response:
|
||||
"Root": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceCid": null,
|
||||
"PieceCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceSize": 1024,
|
||||
"RawBlockSize": 42
|
||||
},
|
||||
@ -1748,7 +1765,9 @@ Response:
|
||||
{
|
||||
"Key": 50,
|
||||
"Err": "string value",
|
||||
"Root": null,
|
||||
"Root": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Source": "string value",
|
||||
"FilePath": "string value",
|
||||
"CARPath": "string value"
|
||||
@ -1773,7 +1792,9 @@ Response:
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"ID": 5,
|
||||
"PieceCID": null,
|
||||
"PieceCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PricePerByte": "0",
|
||||
"UnsealPrice": "0",
|
||||
"Status": 0,
|
||||
@ -1834,7 +1855,9 @@ Inputs:
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
null
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
@ -1845,7 +1868,9 @@ Response:
|
||||
"Root": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Piece": null,
|
||||
"Piece": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Size": 42,
|
||||
"MinPrice": "0",
|
||||
"UnsealPrice": "0",
|
||||
@ -1856,7 +1881,9 @@ Response:
|
||||
"MinerPeer": {
|
||||
"Address": "f01234",
|
||||
"ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
|
||||
"PieceCID": null
|
||||
"PieceCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1933,7 +1960,9 @@ Inputs:
|
||||
"Root": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Piece": null,
|
||||
"Piece": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"DatamodelPathSelector": "Links/21/Hash/Links/42/Hash",
|
||||
"Size": 42,
|
||||
"FromLocalCAR": "string value",
|
||||
@ -1946,7 +1975,9 @@ Inputs:
|
||||
"MinerPeer": {
|
||||
"Address": "f01234",
|
||||
"ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
|
||||
"PieceCID": null
|
||||
"PieceCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -1988,7 +2019,9 @@ Inputs:
|
||||
"Root": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"Piece": null,
|
||||
"Piece": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"DatamodelPathSelector": "Links/21/Hash/Links/42/Hash",
|
||||
"Size": 42,
|
||||
"FromLocalCAR": "string value",
|
||||
@ -2001,7 +2034,9 @@ Inputs:
|
||||
"MinerPeer": {
|
||||
"Address": "f01234",
|
||||
"ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
|
||||
"PieceCID": null
|
||||
"PieceCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -2037,7 +2072,9 @@ Inputs:
|
||||
"Root": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceCid": null,
|
||||
"PieceCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceSize": 1024,
|
||||
"RawBlockSize": 42
|
||||
},
|
||||
@ -2053,7 +2090,12 @@ Inputs:
|
||||
]
|
||||
```
|
||||
|
||||
Response: `null`
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
```
|
||||
|
||||
### ClientStatelessDeal
|
||||
ClientStatelessDeal fire-and-forget-proposes an offline deal to a miner without subsequent tracking.
|
||||
@ -2070,7 +2112,9 @@ Inputs:
|
||||
"Root": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceCid": null,
|
||||
"PieceCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"PieceSize": 1024,
|
||||
"RawBlockSize": 42
|
||||
},
|
||||
@ -2086,7 +2130,12 @@ Inputs:
|
||||
]
|
||||
```
|
||||
|
||||
Response: `null`
|
||||
Response:
|
||||
```json
|
||||
{
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
```
|
||||
|
||||
## Create
|
||||
|
||||
@ -2613,7 +2662,9 @@ Response:
|
||||
{
|
||||
"SealProof": 8,
|
||||
"SectorNumber": 9,
|
||||
"SectorKey": null,
|
||||
"SectorKey": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"SealedCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
@ -4156,7 +4207,9 @@ Response:
|
||||
"PendingAmt": "0",
|
||||
"NonReservedAmt": "0",
|
||||
"PendingAvailableAmt": "0",
|
||||
"PendingWaitSentinel": null,
|
||||
"PendingWaitSentinel": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"QueuedAmt": "0",
|
||||
"VoucherReedeemedAmt": "0"
|
||||
}
|
||||
@ -4185,7 +4238,9 @@ Response:
|
||||
"PendingAmt": "0",
|
||||
"NonReservedAmt": "0",
|
||||
"PendingAvailableAmt": "0",
|
||||
"PendingWaitSentinel": null,
|
||||
"PendingWaitSentinel": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"QueuedAmt": "0",
|
||||
"VoucherReedeemedAmt": "0"
|
||||
}
|
||||
@ -4792,7 +4847,10 @@ Response:
|
||||
"MsgRct": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"GasCost": {
|
||||
"Message": {
|
||||
@ -4825,7 +4883,10 @@ Response:
|
||||
"MsgRct": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"Error": "string value",
|
||||
"Duration": 60000000000,
|
||||
@ -4869,7 +4930,10 @@ Response:
|
||||
"MsgRct": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"Error": "string value",
|
||||
"Duration": 60000000000,
|
||||
@ -5059,7 +5123,10 @@ Response:
|
||||
"MsgRct": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"GasCost": {
|
||||
"Message": {
|
||||
@ -5092,7 +5159,10 @@ Response:
|
||||
"MsgRct": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"Error": "string value",
|
||||
"Duration": 60000000000,
|
||||
@ -5136,7 +5206,10 @@ Response:
|
||||
"MsgRct": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"Error": "string value",
|
||||
"Duration": 60000000000,
|
||||
@ -5460,7 +5533,8 @@ Response:
|
||||
"UpgradeChocolateHeight": 10101,
|
||||
"UpgradeOhSnapHeight": 10101,
|
||||
"UpgradeSkyrHeight": 10101,
|
||||
"UpgradeSharkHeight": 10101
|
||||
"UpgradeSharkHeight": 10101,
|
||||
"UpgradeHyggeHeight": 10101
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -5551,7 +5625,10 @@ Response:
|
||||
{
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -5864,7 +5941,9 @@ Response:
|
||||
"ExpectedStoragePledge": "0",
|
||||
"ReplacedSectorAge": 10101,
|
||||
"ReplacedDayReward": "0",
|
||||
"SectorKeyCID": null,
|
||||
"SectorKeyCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"SimpleQAPower": true
|
||||
}
|
||||
]
|
||||
@ -6032,7 +6111,9 @@ Inputs:
|
||||
5432
|
||||
],
|
||||
"Expiration": 10101,
|
||||
"UnsealedCid": null
|
||||
"UnsealedCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
[
|
||||
{
|
||||
@ -6154,7 +6235,9 @@ Inputs:
|
||||
5432
|
||||
],
|
||||
"Expiration": 10101,
|
||||
"UnsealedCid": null
|
||||
"UnsealedCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
[
|
||||
{
|
||||
@ -6337,7 +6420,9 @@ Response:
|
||||
"ExpectedStoragePledge": "0",
|
||||
"ReplacedSectorAge": 10101,
|
||||
"ReplacedDayReward": "0",
|
||||
"SectorKeyCID": null,
|
||||
"SectorKeyCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"SimpleQAPower": true
|
||||
}
|
||||
]
|
||||
@ -6470,7 +6555,10 @@ Response:
|
||||
"MsgRct": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"GasCost": {
|
||||
"Message": {
|
||||
@ -6503,7 +6591,10 @@ Response:
|
||||
"MsgRct": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"Error": "string value",
|
||||
"Duration": 60000000000,
|
||||
@ -6547,7 +6638,10 @@ Response:
|
||||
"MsgRct": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"Error": "string value",
|
||||
"Duration": 60000000000,
|
||||
@ -6618,7 +6712,10 @@ Response:
|
||||
"Receipt": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"ReturnDec": {},
|
||||
"TipSet": [
|
||||
@ -6672,7 +6769,10 @@ Response:
|
||||
"Receipt": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"ReturnDec": {},
|
||||
"TipSet": [
|
||||
@ -6761,7 +6861,9 @@ Response:
|
||||
"ExpectedStoragePledge": "0",
|
||||
"ReplacedSectorAge": 10101,
|
||||
"ReplacedDayReward": "0",
|
||||
"SectorKeyCID": null,
|
||||
"SectorKeyCID": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
},
|
||||
"SimpleQAPower": true
|
||||
}
|
||||
```
|
||||
@ -6832,7 +6934,9 @@ Response:
|
||||
5432
|
||||
],
|
||||
"Expiration": 10101,
|
||||
"UnsealedCid": null
|
||||
"UnsealedCid": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"PreCommitDeposit": "0",
|
||||
"PreCommitEpoch": 10101
|
||||
@ -6984,7 +7088,10 @@ Response:
|
||||
"Receipt": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"ReturnDec": {},
|
||||
"TipSet": [
|
||||
@ -7041,7 +7148,10 @@ Response:
|
||||
"Receipt": {
|
||||
"ExitCode": 0,
|
||||
"Return": "Ynl0ZSBhcnJheQ==",
|
||||
"GasUsed": 9
|
||||
"GasUsed": 9,
|
||||
"EventsRoot": {
|
||||
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
|
||||
}
|
||||
},
|
||||
"ReturnDec": {},
|
||||
"TipSet": [
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,6 +31,7 @@ COMMANDS:
|
||||
log Manage logging
|
||||
wait-api Wait for lotus api to come online
|
||||
fetch-params Fetch proving parameters
|
||||
evm Commands related to the Filecoin EVM runtime
|
||||
NETWORK:
|
||||
net Manage P2P Network
|
||||
sync Inspect or interact with the chain syncer
|
||||
@ -2539,6 +2540,95 @@ OPTIONS:
|
||||
|
||||
```
|
||||
|
||||
## lotus evm
|
||||
```
|
||||
NAME:
|
||||
lotus evm - Commands related to the Filecoin EVM runtime
|
||||
|
||||
USAGE:
|
||||
lotus evm command [command options] [arguments...]
|
||||
|
||||
COMMANDS:
|
||||
deploy Deploy an EVM smart contract and return its address
|
||||
invoke Invoke an EVM smart contract using the specified CALLDATA
|
||||
stat Print eth/filecoin addrs and code cid
|
||||
call Simulate an eth contract call
|
||||
contract-address Generate contract address from smart contract code
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
OPTIONS:
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
### lotus evm deploy
|
||||
```
|
||||
NAME:
|
||||
lotus evm deploy - Deploy an EVM smart contract and return its address
|
||||
|
||||
USAGE:
|
||||
lotus evm deploy [command options] contract
|
||||
|
||||
OPTIONS:
|
||||
--from value optionally specify the account to use for sending the creation message
|
||||
--hex use when input contract is in hex (default: false)
|
||||
|
||||
```
|
||||
|
||||
### lotus evm invoke
|
||||
```
|
||||
NAME:
|
||||
lotus evm invoke - Invoke an EVM smart contract using the specified CALLDATA
|
||||
|
||||
USAGE:
|
||||
lotus evm invoke [command options] address calldata
|
||||
|
||||
OPTIONS:
|
||||
--from value optionally specify the account to use for sending the exec message
|
||||
--value value optionally specify the value to be sent with the invokation message (default: 0)
|
||||
|
||||
```
|
||||
|
||||
### lotus evm stat
|
||||
```
|
||||
NAME:
|
||||
lotus evm stat - Print eth/filecoin addrs and code cid
|
||||
|
||||
USAGE:
|
||||
lotus evm stat [command options] [arguments...]
|
||||
|
||||
OPTIONS:
|
||||
--ethAddr value Ethereum address
|
||||
--filAddr value Filecoin address
|
||||
|
||||
```
|
||||
|
||||
### lotus evm call
|
||||
```
|
||||
NAME:
|
||||
lotus evm call - Simulate an eth contract call
|
||||
|
||||
USAGE:
|
||||
lotus evm call [command options] [from] [to] [params]
|
||||
|
||||
OPTIONS:
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
### lotus evm contract-address
|
||||
```
|
||||
NAME:
|
||||
lotus evm contract-address - Generate contract address from smart contract code
|
||||
|
||||
USAGE:
|
||||
lotus evm contract-address [command options] [senderEthAddr] [salt] [contractHexPath]
|
||||
|
||||
OPTIONS:
|
||||
--help, -h show help (default: false)
|
||||
|
||||
```
|
||||
|
||||
## lotus net
|
||||
```
|
||||
NAME:
|
||||
|
@ -293,3 +293,53 @@
|
||||
#Tracing = false
|
||||
|
||||
|
||||
[ActorEvent]
|
||||
# EnableRealTimeFilterAPI enables APIs that can create and query filters for actor events as they are emitted.
|
||||
#
|
||||
# type: bool
|
||||
# env var: LOTUS_ACTOREVENT_ENABLEREALTIMEFILTERAPI
|
||||
#EnableRealTimeFilterAPI = false
|
||||
|
||||
# EnableHistoricFilterAPI enables APIs that can create and query filters for actor events that occurred in the past.
|
||||
# A queryable index of events will be maintained.
|
||||
#
|
||||
# type: bool
|
||||
# env var: LOTUS_ACTOREVENT_ENABLEHISTORICFILTERAPI
|
||||
#EnableHistoricFilterAPI = false
|
||||
|
||||
# FilterTTL specifies the time to live for actor event filters. Filters that haven't been accessed longer than
|
||||
# this time become eligible for automatic deletion.
|
||||
#
|
||||
# type: Duration
|
||||
# env var: LOTUS_ACTOREVENT_FILTERTTL
|
||||
#FilterTTL = "24h0m0s"
|
||||
|
||||
# MaxFilters specifies the maximum number of filters that may exist at any one time.
|
||||
#
|
||||
# type: int
|
||||
# env var: LOTUS_ACTOREVENT_MAXFILTERS
|
||||
#MaxFilters = 100
|
||||
|
||||
# MaxFilterResults specifies the maximum number of results that can be accumulated by an actor event filter.
|
||||
#
|
||||
# type: int
|
||||
# env var: LOTUS_ACTOREVENT_MAXFILTERRESULTS
|
||||
#MaxFilterResults = 10000
|
||||
|
||||
# MaxFilterHeightRange specifies the maximum range of heights that can be used in a filter (to avoid querying
|
||||
# the entire chain)
|
||||
#
|
||||
# type: uint64
|
||||
# env var: LOTUS_ACTOREVENT_MAXFILTERHEIGHTRANGE
|
||||
#MaxFilterHeightRange = 2880
|
||||
|
||||
# ActorEventDatabasePath is the full path to a sqlite database that will be used to index actor events to
|
||||
# support the historic filter APIs. If the database does not exist it will be created. The directory containing
|
||||
# the database must already exist and be writeable. If a relative path is provided here, sqlite treats it as
|
||||
# relative to the CWD (current working directory).
|
||||
#
|
||||
# type: string
|
||||
# env var: LOTUS_ACTOREVENT_ACTOREVENTDATABASEPATH
|
||||
#ActorEventDatabasePath = ""
|
||||
|
||||
|
||||
|
2
extern/filecoin-ffi
vendored
2
extern/filecoin-ffi
vendored
@ -1 +1 @@
|
||||
Subproject commit 02ebb2d6169131cfe489e1063e896f14982c463d
|
||||
Subproject commit c4adeb4532719acf7b1c182cb98a3cca7b955a14
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/filecoin-project/lotus/chain/types"
|
||||
"github.com/filecoin-project/lotus/lib/sigs"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/bls"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/delegated"
|
||||
_ "github.com/filecoin-project/lotus/lib/sigs/secp"
|
||||
"github.com/filecoin-project/lotus/metrics"
|
||||
"github.com/filecoin-project/lotus/node/impl/full"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user