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:
raulk 2023-01-13 19:11:13 +00:00 committed by GitHub
parent 048ccc71bb
commit cdf3812e40
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
141 changed files with 14043 additions and 662 deletions

View File

@ -720,6 +720,46 @@ workflows:
suite: itest-dup_mpool_messages suite: itest-dup_mpool_messages
target: "./itests/dup_mpool_messages_test.go" 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: - test:
name: test-itest-gas_estimation name: test-itest-gas_estimation
suite: itest-gas_estimation suite: itest-gas_estimation
@ -755,6 +795,11 @@ workflows:
suite: itest-migration_nv17 suite: itest-migration_nv17
target: "./itests/migration_nv17_test.go" target: "./itests/migration_nv17_test.go"
- test:
name: test-itest-migration_nv18
suite: itest-migration_nv18
target: "./itests/migration_nv18_test.go"
- test: - test:
name: test-itest-mpool_msg_uuid name: test-itest-mpool_msg_uuid
suite: itest-mpool_msg_uuid suite: itest-mpool_msg_uuid

View File

@ -84,6 +84,12 @@ butterflynet: build-devnets
interopnet: GOFLAGS+=-tags=interopnet interopnet: GOFLAGS+=-tags=interopnet
interopnet: build-devnets interopnet: build-devnets
wallabynet: GOFLAGS+=-tags=wallabynet
wallabynet: build-devnets
hyperspacenet: GOFLAGS+=-tags=hyperspacenet
hyperspacenet: build-devnets
lotus: $(BUILD_DEPS) lotus: $(BUILD_DEPS)
rm -f lotus rm -f lotus
$(GOCC) build $(GOFLAGS) -o lotus ./cmd/lotus $(GOCC) build $(GOFLAGS) -o lotus ./cmd/lotus

View File

@ -31,6 +31,7 @@ import (
lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner" 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/actors/builtin/power"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/node/repo/imports" "github.com/filecoin-project/lotus/node/repo/imports"
) )
@ -182,6 +183,9 @@ type FullNode interface {
// ChainBlockstoreInfo returns some basic information about the blockstore // ChainBlockstoreInfo returns some basic information about the blockstore
ChainBlockstoreInfo(context.Context) (map[string]interface{}, error) //perm:read 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 estimates gas fee cap
GasEstimateFeeCap(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error) //perm:read GasEstimateFeeCap(context.Context, *types.Message, int64, types.TipSetKey) (types.BigInt, error) //perm:read
@ -759,6 +763,77 @@ type FullNode interface {
NodeStatus(ctx context.Context, inclChainStatus bool) (NodeStatus, error) //perm:read 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 // CreateBackup creates node backup onder the specified file name. The
// method requires that the lotus daemon is running with the // method requires that the lotus daemon is running with the
// LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that // LOTUS_BACKUP_BASE_PATH environment variable set to some path, and that
@ -1252,3 +1327,21 @@ type PruneOpts struct {
MovingGC bool MovingGC bool
RetainState int64 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"`
}

View File

@ -22,7 +22,7 @@ import (
"github.com/filecoin-project/go-state-types/builtin/v9/miner" "github.com/filecoin-project/go-state-types/builtin/v9/miner"
abinetwork "github.com/filecoin-project/go-state-types/network" 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/chain/types"
"github.com/filecoin-project/lotus/storage/pipeline/sealiface" "github.com/filecoin-project/lotus/storage/pipeline/sealiface"
"github.com/filecoin-project/lotus/storage/sealer/fsutil" "github.com/filecoin-project/lotus/storage/sealer/fsutil"
@ -322,7 +322,7 @@ type StorageMiner interface {
CheckProvable(ctx context.Context, pp abi.RegisteredPoStProof, sectors []storiface.SectorRef) (map[abi.SectorNumber]string, error) //perm:admin 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 // 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 // to the miner actor with details of recovered sectors and returns the CID of messages. It honors the

View File

@ -41,6 +41,7 @@ import (
"github.com/filecoin-project/lotus/api/v0api" "github.com/filecoin-project/lotus/api/v0api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/node/repo/imports" "github.com/filecoin-project/lotus/node/repo/imports"
sealing "github.com/filecoin-project/lotus/storage/pipeline" sealing "github.com/filecoin-project/lotus/storage/pipeline"
@ -68,6 +69,7 @@ func init() {
} }
ExampleValues[reflect.TypeOf(c)] = c ExampleValues[reflect.TypeOf(c)] = c
ExampleValues[reflect.TypeOf(&c)] = &c
c2, err := cid.Decode("bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve") c2, err := cid.Decode("bafy2bzacebp3shtrn43k7g3unredz7fxn4gj533d3o43tqn2p2ipxxhrvchve")
if err != nil { if err != nil {
@ -298,7 +300,8 @@ func init() {
"title": "Lotus RPC API", "title": "Lotus RPC API",
"version": "1.2.1/generated=2020-11-22T08:22:42-06:00", "version": "1.2.1/generated=2020-11-22T08:22:42-06:00",
}, },
"methods": []interface{}{}}, "methods": []interface{}{},
},
) )
addExample(api.CheckStatusCode(0)) addExample(api.CheckStatusCode(0))
@ -335,7 +338,8 @@ func init() {
NumConnsInbound: 3, NumConnsInbound: 3,
NumConnsOutbound: 4, NumConnsOutbound: 4,
NumFD: 5, NumFD: 5,
}}) },
})
addExample(api.NetLimit{ addExample(api.NetLimit{
Memory: 123, Memory: 123,
StreamsInbound: 1, StreamsInbound: 1,
@ -346,6 +350,7 @@ func init() {
Conns: 4, Conns: 4,
FD: 5, FD: 5,
}) })
addExample(map[string]bitfield.BitField{ addExample(map[string]bitfield.BitField{
"": bitfield.NewFromSet([]uint64{5, 6, 7, 10}), "": bitfield.NewFromSet([]uint64{5, 6, 7, 10}),
}) })
@ -365,11 +370,40 @@ func init() {
Headers: nil, Headers: nil,
}, },
}) })
ethint := ethtypes.EthUint64(5)
addExample(ethint)
addExample(&ethint)
ethaddr, _ := ethtypes.ParseEthAddress("0x5CbEeCF99d3fDB3f25E309Cc264f240bb0664031")
addExample(ethaddr)
addExample(&ethaddr)
ethhash, _ := ethtypes.EthHashFromCid(c)
addExample(ethhash)
addExample(&ethhash)
ethFeeHistoryReward := [][]ethtypes.EthBigInt{}
addExample(&ethFeeHistoryReward)
addExample(&uuid.UUID{}) 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(&ethtypes.EthFilterSpec{
FromBlock: pstring("2301220"),
Address: []ethtypes.EthAddress{ethaddr},
})
} }
func GetAPIType(name, pkg string) (i interface{}, t reflect.Type, permStruct []reflect.Type) { func GetAPIType(name, pkg string) (i interface{}, t reflect.Type, permStruct []reflect.Type) {
switch pkg { switch pkg {
case "api": // latest case "api": // latest
switch name { switch name {
@ -439,7 +473,7 @@ func ExampleValue(method string, t, parent reflect.Type) interface{} {
case reflect.Ptr: case reflect.Ptr:
if t.Elem().Kind() == reflect.Struct { if t.Elem().Kind() == reflect.Struct {
es := exampleStruct(method, t.Elem(), t) es := exampleStruct(method, t.Elem(), t)
//ExampleValues[t] = es ExampleValues[t] = es
return es return es
} }
case reflect.Interface: case reflect.Interface:

View File

@ -37,6 +37,7 @@ import (
apitypes "github.com/filecoin-project/lotus/api/types" apitypes "github.com/filecoin-project/lotus/api/types"
miner0 "github.com/filecoin-project/lotus/chain/actors/builtin/miner" miner0 "github.com/filecoin-project/lotus/chain/actors/builtin/miner"
types "github.com/filecoin-project/lotus/chain/types" 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" alerting "github.com/filecoin-project/lotus/journal/alerting"
dtypes "github.com/filecoin-project/lotus/node/modules/dtypes" dtypes "github.com/filecoin-project/lotus/node/modules/dtypes"
imports "github.com/filecoin-project/lotus/node/repo/imports" 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) 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. // ChainGetGenesis mocks base method.
func (m *MockFullNode) ChainGetGenesis(arg0 context.Context) (*types.TipSet, error) { func (m *MockFullNode) ChainGetGenesis(arg0 context.Context) (*types.TipSet, error) {
m.ctrl.T.Helper() 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) 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. // GasEstimateFeeCap mocks base method.
func (m *MockFullNode) GasEstimateFeeCap(arg0 context.Context, arg1 *types.Message, arg2 int64, arg3 types.TipSetKey) (big.Int, error) { func (m *MockFullNode) GasEstimateFeeCap(arg0 context.Context, arg1 *types.Message, arg2 int64, arg3 types.TipSetKey) (big.Int, error) {
m.ctrl.T.Helper() 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) 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. // NetPeerInfo mocks base method.
func (m *MockFullNode) NetPeerInfo(arg0 context.Context, arg1 peer.ID) (*api.ExtendedPeerInfo, error) { func (m *MockFullNode) NetPeerInfo(arg0 context.Context, arg1 peer.ID) (*api.ExtendedPeerInfo, error) {
m.ctrl.T.Helper() 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) 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. // NodeStatus mocks base method.
func (m *MockFullNode) NodeStatus(arg0 context.Context, arg1 bool) (api.NodeStatus, error) { func (m *MockFullNode) NodeStatus(arg0 context.Context, arg1 bool) (api.NodeStatus, error) {
m.ctrl.T.Helper() m.ctrl.T.Helper()

View File

@ -33,9 +33,10 @@ import (
"github.com/filecoin-project/go-state-types/proof" "github.com/filecoin-project/go-state-types/proof"
apitypes "github.com/filecoin-project/lotus/api/types" 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" lminer "github.com/filecoin-project/lotus/chain/actors/builtin/miner"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/journal/alerting" "github.com/filecoin-project/lotus/journal/alerting"
"github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/modules/dtypes"
"github.com/filecoin-project/lotus/node/repo/imports" "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"` 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"` ChainGetGenesis func(p0 context.Context) (*types.TipSet, error) `perm:"read"`
ChainGetMessage func(p0 context.Context, p1 cid.Cid) (*types.Message, 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"` 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"` 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"` 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"` 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"` NodeStatus func(p0 context.Context, p1 bool) (NodeStatus, error) `perm:"read"`
PaychAllocateLane func(p0 context.Context, p1 address.Address) (uint64, error) `perm:"sign"` 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"` 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"` 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 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) { func (s *FullNodeStruct) ChainGetGenesis(p0 context.Context) (*types.TipSet, error) {
if s.Internal.ChainGetGenesis == nil { if s.Internal.ChainGetGenesis == nil {
return nil, ErrNotSupported return nil, ErrNotSupported
@ -1795,6 +1875,347 @@ func (s *FullNodeStub) CreateBackup(p0 context.Context, p1 string) error {
return ErrNotSupported 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) { func (s *FullNodeStruct) GasEstimateFeeCap(p0 context.Context, p1 *types.Message, p2 int64, p3 types.TipSetKey) (types.BigInt, error) {
if s.Internal.GasEstimateFeeCap == nil { if s.Internal.GasEstimateFeeCap == nil {
return *new(types.BigInt), ErrNotSupported return *new(types.BigInt), ErrNotSupported
@ -2279,6 +2700,28 @@ func (s *FullNodeStub) MsigSwapPropose(p0 context.Context, p1 address.Address, p
return nil, ErrNotSupported 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) { func (s *FullNodeStruct) NodeStatus(p0 context.Context, p1 bool) (NodeStatus, error) {
if s.Internal.NodeStatus == nil { if s.Internal.NodeStatus == nil {
return *new(NodeStatus), ErrNotSupported return *new(NodeStatus), ErrNotSupported
@ -4182,15 +4625,15 @@ func (s *StorageMinerStub) ComputeDataCid(p0 context.Context, p1 abi.UnpaddedPie
return *new(abi.PieceInfo), ErrNotSupported 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 { if s.Internal.ComputeProof == nil {
return *new([]builtin.PoStProof), ErrNotSupported return *new([]builtinactors.PoStProof), ErrNotSupported
} }
return s.Internal.ComputeProof(p0, p1, p2, p3, p4) 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) { func (s *StorageMinerStub) ComputeProof(p0 context.Context, p1 []builtinactors.ExtendedSectorInfo, p2 abi.PoStRandomness, p3 abi.ChainEpoch, p4 abinetwork.Version) ([]builtinactors.PoStProof, error) {
return *new([]builtin.PoStProof), ErrNotSupported return *new([]builtinactors.PoStProof), ErrNotSupported
} }
func (s *StorageMinerStruct) ComputeWindowPoSt(p0 context.Context, p1 uint64, p2 types.TipSetKey) ([]miner.SubmitWindowedPoStParams, error) { func (s *StorageMinerStruct) ComputeWindowPoSt(p0 context.Context, p1 uint64, p2 types.TipSetKey) ([]miner.SubmitWindowedPoStParams, error) {

View File

@ -338,6 +338,7 @@ type ForkUpgradeParams struct {
UpgradeOhSnapHeight abi.ChainEpoch UpgradeOhSnapHeight abi.ChainEpoch
UpgradeSkyrHeight abi.ChainEpoch UpgradeSkyrHeight abi.ChainEpoch
UpgradeSharkHeight abi.ChainEpoch UpgradeSharkHeight abi.ChainEpoch
UpgradeHyggeHeight abi.ChainEpoch
} }
type NonceMapType map[address.Address]uint64 type NonceMapType map[address.Address]uint64

View File

@ -905,6 +905,10 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp
walkCnt := new(int64) walkCnt := new(int64)
scanCnt := 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 } stopWalk := func(_ cid.Cid) error { return errStopWalk }
walkBlock := func(c cid.Cid) error { 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 { err = s.view(c, func(data []byte) error {
return hdr.UnmarshalCBOR(bytes.NewBuffer(data)) return hdr.UnmarshalCBOR(bytes.NewBuffer(data))
}) })
if err != nil { if err != nil {
return xerrors.Errorf("error unmarshaling block header (cid: %s): %w", c, err) 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 // message are retained if within the inclMsgs boundary
if hdr.Height >= inclMsgs && hdr.Height > 0 { if hdr.Height >= inclMsgs && hdr.Height > 0 {
if inclMsgs < inclState { if inclMsgs < inclState {
@ -981,6 +993,15 @@ func (s *SplitStore) walkChain(ts *types.TipSet, inclState, inclMsgs abi.ChainEp
return nil 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 { for len(toWalk) > 0 {
// walking can take a while, so check this with every opportunity // walking can take a while, so check this with every opportunity
if err := s.checkClosing(); err != nil { if err := s.checkClosing(); err != nil {

View File

@ -1,6 +1,6 @@
#!/bin/bash #!/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 set -e

Binary file not shown.

View 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

View File

@ -44,23 +44,24 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, { }, {
Network: "butterflynet", Network: "butterflynet",
Version: 10, Version: 10,
ManifestCid: MustParseCid("bafy2bzaceciz4ytt5gnn6gc4epez7v6xeg6efkgbvwfxkoa34o2gj3hp5f7zc"), ManifestCid: MustParseCid("bafy2bzaceav7txndea2xt6kvaosokp42vyjkhtplbb67tpkov3jbsvbwplnz4"),
Actors: map[string]cid.Cid{ Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzacedavorwsriewoddjlaganjpsk3o7zfts2wyid3clv5xnctacg37j2"), "account": MustParseCid("bafk2bzacec34ox7drngorgal3ujxat2a2dlsh7eissgiisrv2uubuub2avbe2"),
"cron": MustParseCid("bafk2bzacebtauucwaewxuzgxfpjtmn6xt3kya4om4ugyprlkhhkde76h7fkqg"), "cron": MustParseCid("bafk2bzaceb77n6gkytpkn2wguemnpfqfaynv7u6ci4j247leg2w3dhcoxa5ns"),
"datacap": MustParseCid("bafk2bzacebzdjapqwasq6woxkgq2nm2nre3v7cl2754xwiuo2cfhvsceq4cba"), "datacap": MustParseCid("bafk2bzacebj2ztqmlb7mmkggaqf66sv7gao5722vzmpnngiuncu4efpsjyhy4"),
"eam": MustParseCid("bafk2bzacecmr4zdbpfnemvgo446qby7x4y4v5cbfespt3f6ousv2hxnflyrlk"), "eam": MustParseCid("bafk2bzacecvl6xpmldfk5oyehqhmuasp7cbx3kh3y425curdy65hlmhovc4oi"),
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"), "ethaccount": MustParseCid("bafk2bzacec2wy3fknb63r5zili7qojvt4f3rvstweqvnjne5adarx3lskgz5m"),
"evm": MustParseCid("bafk2bzacebuewexvig54cuvsvwn4k4zr36tm2q5fel4ezq4v7363n2lmn362k"), "evm": MustParseCid("bafk2bzacebtoqzucrh7kvtxpo4ruzisey67z6t3z5cbff4c36du3dlm3aj4l6"),
"init": MustParseCid("bafk2bzacebww5gsctsk5hack2alkt4kh55bmpb4ywzbyyhoaskryymjj3snj6"), "init": MustParseCid("bafk2bzacebvc5t5u3opeyx4rxbeinshjsghjhttdbsyqifb4ikzpa2ic5mkhu"),
"multisig": MustParseCid("bafk2bzacec5k4wxvou34pyjd5kcsrbsfnlk4k753kkscg3ron2r7tsxollfsq"), "multisig": MustParseCid("bafk2bzaceckmb2bcw2m5o4hifhodrq2j6ow5nhouj5wpqsxpzntgveft3hplu"),
"paymentchannel": MustParseCid("bafk2bzacebzdeaxglaqpmegalakmxr6secjd24mu5llo4ctoy7pvom5upyuvs"), "paymentchannel": MustParseCid("bafk2bzacebsvkpbavcdjguev4dxfnjx5j5bqzeeyk3petwbkmfptoej5bqlqc"),
"reward": MustParseCid("bafk2bzaceb4hyabxnyrrsno5erqqwk5ynnjibblzfcaq3aotlz3ek4uu6dyla"), "placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
"storagemarket": MustParseCid("bafk2bzacedpocbf2lg2x2jg6arw2argnwmvo2hyjqvpkrgfu4khz5mtlzxz2o"), "reward": MustParseCid("bafk2bzacea3rkyhzmugj6ap3uv5m5jnhxt64y2775vo6vemdi5aafzxty3nmq"),
"storageminer": MustParseCid("bafk2bzaceacrumah7jdfc62bmvemob4lsh5yiohwodest2cgxakgnn24cenlk"), "storagemarket": MustParseCid("bafk2bzacebfacbnuauxhq63f5jbchoi2xwc5ljrxnwgj2xulkx4yzfu6i4lhg"),
"storagepower": MustParseCid("bafk2bzaceaxz6n5nywermfptnz6dc53vqsa42lic4rf66l4irm3mqfj4ak5ps"), "storageminer": MustParseCid("bafk2bzaceal4ct6gwlzl3owu6d4iiudf4ioxth5gn6cvm37enl465px2bhznk"),
"system": MustParseCid("bafk2bzaceb4w5bblgyu25ylytpmfrixjsk2ra6emd44j4mv42xfxbwnqloyzi"), "storagepower": MustParseCid("bafk2bzaceb5pdkt55d7wxjgmhvzvnlkuw5r6eamypgqm5kem5tz3sxddwtizw"),
"verifiedregistry": MustParseCid("bafk2bzacedbz2koeb6teewobcjdpgfv7qdae7utgoka6wzlkf6gronnis2nn2"), "system": MustParseCid("bafk2bzacecuu2y5b6r4jrj64w5yuh3klnoevrcnbdxozmtagdcyfve7oe27ri"),
"verifiedregistry": MustParseCid("bafk2bzacediez3q42tjeit7hbsglv33ltfeamoa43lftwsxh2nyov5ijhuihm"),
}, },
}, { }, {
Network: "calibrationnet", Network: "calibrationnet",
@ -100,23 +101,24 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, { }, {
Network: "calibrationnet", Network: "calibrationnet",
Version: 10, Version: 10,
ManifestCid: MustParseCid("bafy2bzaced7wbd43lvgc55xb37mkoo4ppev6ig4jj4j7dtswtjfjq4u5qmpck"), ManifestCid: MustParseCid("bafy2bzacebb4qaymahytofcakf3vcyuv4tnu4zsgxp4iikc6kkmfagtaierro"),
Actors: map[string]cid.Cid{ Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzacecq4owv5begvryvpsy4atfb2jnf7g7o4hxovtdb5a4jfkzacownli"), "account": MustParseCid("bafk2bzaceakcix46r7hh4wjhzaksnha6f5elbg62ld6dklz6ttkhisnppmoe2"),
"cron": MustParseCid("bafk2bzaced4uz5w5h5wksx4end27lphd4qc4kh7q336uyt46lba5ddynwftya"), "cron": MustParseCid("bafk2bzaceb5ezi5dlgxjmxffecrmgiajwseiblgivho5qnfejivuqxfclooma"),
"datacap": MustParseCid("bafk2bzacedoc7y4s5n3p2zo4bcmafcrellkakn2e3uyf5wb3mtbuqhvwqn2l4"), "datacap": MustParseCid("bafk2bzaceag4j2myqvwevm3mdtvmqoeguwtjheyezodjcpq5ugibjx6gtz65u"),
"eam": MustParseCid("bafk2bzacealpqjgz5qmucm3v6z6hn36igx7zijixhqrxwoj3g4bdgvyml3adi"), "eam": MustParseCid("bafk2bzacedwnuqthwpl3si5gs27xnxq7bcr5ucg3vg4utltfhnytaqzwlk33g"),
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"), "ethaccount": MustParseCid("bafk2bzacechx3zdc4yw7ehtelecwsp6hb2iguefusfccqxfmdinjjoa64ado4"),
"evm": MustParseCid("bafk2bzacedmlmyy2efbt4qk5ighawiychklhzc6pzyiwvpijwvxoq3xyxlgxw"), "evm": MustParseCid("bafk2bzaceaqtomr2odeyjabgkwnwfgm54b44cpshpkssn7nq35umzogkqqbee"),
"init": MustParseCid("bafk2bzaceaqcfmfylwdemq5bdcelydpf6iqfct4p7b2zwtmqyhuxn522yvic2"), "init": MustParseCid("bafk2bzacebtqjmdudvfl5cq6yqswortlc46cjpz36qj5igzfglu55kppuovyw"),
"multisig": MustParseCid("bafk2bzacebuh55hkbkobmmoaoduruss5nsh6e2gtqtdbqsmw6e7k5vg6heyrm"), "multisig": MustParseCid("bafk2bzaceb2hlrmljz26gecv7zj5ymeleiuebf6mnvc7vng3qbcxvxagrlc22"),
"paymentchannel": MustParseCid("bafk2bzacedcpzw7prdoxnaclcvmtwr6yf54zi4bzzwe5w3xknh72ji6p3qfc6"), "paymentchannel": MustParseCid("bafk2bzacecbn4m6evxxoalujyt4wnas3hdttffzjee5qjp62w7dsjdoeuhzka"),
"reward": MustParseCid("bafk2bzaced74ym6j424zzbr6millasfcyl3r4zm5fnauasrwn3ti6fdarbkym"), "placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
"storagemarket": MustParseCid("bafk2bzacec7delr2q42yj4wu3daa5xjz4zezeivphtx3xwyvpgwpdnfoevhh2"), "reward": MustParseCid("bafk2bzaceds2kn4fn27nwlxx2raawldkytlro6i2qeh6rdtmme6ybd4otpwqq"),
"storageminer": MustParseCid("bafk2bzaced7isnew5lhu237pdtwaqmbv65qqvfmmnve2c5yfobtfqw2fptuvc"), "storagemarket": MustParseCid("bafk2bzacec35rrhgiqqrwqjtuhoseg7e4g67sqaa74b2x2p7f37ylfulc672i"),
"storagepower": MustParseCid("bafk2bzacebe5frk6gcgzcvzkxavhhbs3id3iyacybn7y7gxwzgl5t6zawzswg"), "storageminer": MustParseCid("bafk2bzaceaiwkboswmk4kmzctnzd5txf2axdvladlf6x5as7ey7avxa5dgfd4"),
"system": MustParseCid("bafk2bzacectivaezqijucle5s2f7xeui5uxig7bnk7fe4vsvz3xu7agjtb2ge"), "storagepower": MustParseCid("bafk2bzaceb2nlgx5aw2psgiedc7oqefs6mttwcloczsbucxtit55zzpbgr4fc"),
"verifiedregistry": MustParseCid("bafk2bzaceczgwckte4exultjxyzgzoo6m6r5coyphnlappi4clethhhybslxc"), "system": MustParseCid("bafk2bzacecki2gyvfguathvwva4ilovedftfuxvk3rhuw4y2t4aawkm2e5ttq"),
"verifiedregistry": MustParseCid("bafk2bzacebvicauwopayihp5jjegtma26nuhubauya73tkhpdfs27xwjutn4w"),
}, },
}, { }, {
Network: "caterpillarnet", Network: "caterpillarnet",
@ -156,23 +158,24 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, { }, {
Network: "caterpillarnet", Network: "caterpillarnet",
Version: 10, Version: 10,
ManifestCid: MustParseCid("bafy2bzacea5csj2os7h76a6yvf6shgpwkysawijxemk5uvvzejxrwjo6ir4yg"), ManifestCid: MustParseCid("bafy2bzacedktxutlehqmx2uryphph6dln4wbgy6yfsj7un36b2u7l7a32n3km"),
Actors: map[string]cid.Cid{ Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzacea7tpruyxdgyz4xa7curiphwdw4abmspft3ee24puruazdcl3tq5c"), "account": MustParseCid("bafk2bzaceaoina2vmmq24ij5kqbgawjrlnxkmj6arzucoigabt25ch6cdvbyc"),
"cron": MustParseCid("bafk2bzacebc6kkj7kzsicm5baszjgd37b4b3kijsffqmmkhhjlyd7zhkwfcqm"), "cron": MustParseCid("bafk2bzaceancnphwoym4pmzatrzfxo3bac72gk4bjgaqxedrigfrua62an3n2"),
"datacap": MustParseCid("bafk2bzaceddcmwl6po2jd3tfkkgv4zvub7i47gsx33pkqdspqhgvhe4npc4as"), "datacap": MustParseCid("bafk2bzaceaoebtmqyqvyv7oq7ehdkhl6fxjamz5fjdje7axslxsc7rhqchcdm"),
"eam": MustParseCid("bafk2bzaceccsvcww2rmqnh4plkq6oapqaeqbhydrtup54z4dwunolz5tpgtb4"), "eam": MustParseCid("bafk2bzaceazfxudfagmhdmwx46sjeyqoba3quy7cllqv2nuksh3ikc6gw63yg"),
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"), "ethaccount": MustParseCid("bafk2bzaceblsm6aaymb2ua64eqbe32uyxdoyqzger5recw6k4p43yeu2oyigi"),
"evm": MustParseCid("bafk2bzacea5sig3zpxfkqppoj3t344cvuhzvkx6ge2isgdzc34rfpng2ogdje"), "evm": MustParseCid("bafk2bzacea7jveqmq5u6ijabkbuujtgqzmy3p5zl5x45frnygio3hqqnabbso"),
"init": MustParseCid("bafk2bzacedtby353aho7itoyoj7w6moydmigjm3sgy6djgnfxqehlpae4vcc2"), "init": MustParseCid("bafk2bzacecdewh4goftyp2cmuq3zpkyjinv6faysksjgqxtbk2j5dljv75rgq"),
"multisig": MustParseCid("bafk2bzacedyguvwz5zfveqoqicn3j6lkdzipf247nhvdi6dvmahulr7nzgox6"), "multisig": MustParseCid("bafk2bzacecpscu24o2fwlspi64k3fiaufeh3nnrv6wgumvaeco2jduhposcf4"),
"paymentchannel": MustParseCid("bafk2bzaceavaatmmnsz3v3ksopcbu6jx4iq7u7nnmqbclsiabsfkfu3zfpmka"), "paymentchannel": MustParseCid("bafk2bzacedxc3fy436wlebsusgwcwqf6lzo7yv5iugy75z5hwrdt33pq2rhho"),
"reward": MustParseCid("bafk2bzacecrphs4avteik4yejsqwkpy5bcqramdhnzykbfq3uu2qalj2p26ti"), "placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
"storagemarket": MustParseCid("bafk2bzaceajby2jb5m3fenzarum374zxdzuyrpkspfljwovu7c3hvyceqd5sa"), "reward": MustParseCid("bafk2bzacebzvjtzzuo6ijkbx2yx3ly6vlrgw37fymasdwcdymlxc26znib2og"),
"storageminer": MustParseCid("bafk2bzacebqtn7jdvk756ighri5ajro6gjepnef3c6rxupbbgkth62zytiy5s"), "storagemarket": MustParseCid("bafk2bzaceabdr5l4qluc4rgxjxo4xnoyc5e6slp7s3fojhnv4ng3swu7qv556"),
"storagepower": MustParseCid("bafk2bzacedwlo32brlalpovfkkk7qwo3ou2kpgv2bf7fioy5srn7uejmn7n46"), "storageminer": MustParseCid("bafk2bzaceclwbgfqr7wqepi6xkpoqz2bl6p22mlbmsgs4zarxki2cub5rspxy"),
"system": MustParseCid("bafk2bzacebbt63h26x5vw5fdo2pmdb4q65u3t6lilkugvmjar6zfsc7ethxsi"), "storagepower": MustParseCid("bafk2bzacean3trpjoxvwztrmbw7lx6osapicxzclyz2cgou4upq432norjnaq"),
"verifiedregistry": MustParseCid("bafk2bzacecr5kbyypdxnxlepzk5sji2k72t454vto5ok4owfcuwfpeyivjtu4"), "system": MustParseCid("bafk2bzacedeexlnmp677eauba76trar47p2zddbspiodri5aof6ccasyicxxo"),
"verifiedregistry": MustParseCid("bafk2bzaceayctmu2avbckz4scuep3ocxsw5r3eqxz7wu27volaxnvfvoxjhbq"),
}, },
}, { }, {
Network: "devnet", Network: "devnet",
@ -212,23 +215,46 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, { }, {
Network: "devnet", Network: "devnet",
Version: 10, Version: 10,
ManifestCid: MustParseCid("bafy2bzacea73thrlpfejrswlcu5uhe7rcgdewvmrcwoef6jzngsba3i4v5ibi"), ManifestCid: MustParseCid("bafy2bzacea2wblucgi2tztgk52fap2wsjddrrobito5zdklqdhpdwhmyr7lbk"),
Actors: map[string]cid.Cid{ Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzaceau2o55aripm7kqrbzzog72zcduv5psnxzpohx5rdkykepc4z7aag"), "account": MustParseCid("bafk2bzacealrkumvvuyeefrnedyh2ilgozgrdp5canubuakp723pczjdcogvw"),
"cron": MustParseCid("bafk2bzacec5qc5xluwikf4lolfa4oe356iwep25tiezbxfdyg5jib54rhlh6q"), "cron": MustParseCid("bafk2bzacedcfqpqgwj4tgtccliqzwnjbxiceyc3lzylnf6owu54etiv3udjxi"),
"datacap": MustParseCid("bafk2bzacebo47u6q3xou5exsecjpa4rpfqjfm7vyhz4qlr3nk7p46trsk4occ"), "datacap": MustParseCid("bafk2bzacear73heimtdso2qnw77gx6lzqmnr5f5etlggwevut5di6d7nzaoqu"),
"eam": MustParseCid("bafk2bzacea6yeptevserd7ayf4ahokor4sdpizpxpbqwkuvvhzdkon672shsm"), "eam": MustParseCid("bafk2bzacecff4dgsqjcele3zejp77weofbqkef57r2tcy4alkx7e7n3kbkmyy"),
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"), "ethaccount": MustParseCid("bafk2bzacec75pm3q66lsex2mqpm7fax7h6bfbkpwodf4o5gzgnrc2cdifbvfw"),
"evm": MustParseCid("bafk2bzacebi46zgjili4luu3nqy6mno5k4skvo4cvs7genhkdfaukhtw7xirw"), "evm": MustParseCid("bafk2bzaceacbkauvu7ia3euoz5jfdrkw5s7mk4ga5byf3oqndxeaxyxhgnk4m"),
"init": MustParseCid("bafk2bzacedvf2bij6jovem2dfzkz347yvmydxj7vlgaiagosz5t3c5jyy43zu"), "init": MustParseCid("bafk2bzacebtc7p3fq4d7m76jphagzpav2kfxfok7d56wrkek4zqyfqvtpihwm"),
"multisig": MustParseCid("bafk2bzacecukolwx6y5pcajnxg2aawiubgxo5zyj24a23zg5t4qu3k4qbofh4"), "multisig": MustParseCid("bafk2bzaceci3czx4l42u22iozsgg6zkls5wdtrztekmzy4qnybg4qlv4b3qli"),
"paymentchannel": MustParseCid("bafk2bzacecwyih7nodrwsw5vyl5zk7fapklje76jpowqjr6x6br2bm55smqqy"), "paymentchannel": MustParseCid("bafk2bzacea54hgf2czdhlxvn66pyoon5cw3fwdlwx4kp4fwftv2tat4r4nnqg"),
"reward": MustParseCid("bafk2bzacea6vfrcprxg2i4l5qnigf4c6pyvnjxpzfqr4pmph3elif7sfidrei"), "placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
"storagemarket": MustParseCid("bafk2bzaceahradb3od4ahs46x6yriwvm36iabgtohhoiolubsumto5eravzbu"), "reward": MustParseCid("bafk2bzacebd7ia2qfpxob2enuazpy3yc2wpach5rq2qbm7uwgknyzqqruefmm"),
"storageminer": MustParseCid("bafk2bzacedekivqgvqapbepvzn6jte3xyymyg5yjuwy42xvboa6rcqnzgo74u"), "storagemarket": MustParseCid("bafk2bzaceam7ns7axlv3sghrwdo7kriw2hrlblim2pingllnvatqu2xfjfhgs"),
"storagepower": MustParseCid("bafk2bzacedkmiosllqqqarmr53twspyswdvsm7givwczgo3qqsxzpad4hzjma"), "storageminer": MustParseCid("bafk2bzacecbfmgzg5unc3ia7yme75psji2j6uhalt5jco6niu6wcn3pdufavy"),
"system": MustParseCid("bafk2bzaceagdymtxb4lxqqjgmnphbgdtdgveuuqaouswpzagj4bpbon3ptop4"), "storagepower": MustParseCid("bafk2bzacedxzvoqa3a4lzajoke75q2ujhmazm4inb7robfikgtywr4sp6mgcy"),
"verifiedregistry": MustParseCid("bafk2bzacec556wsqldm22k2abshvvnsrawlm3bbqkwzht6ubcj76m2jsy3azi"), "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", Network: "mainnet",
@ -268,23 +294,24 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, { }, {
Network: "mainnet", Network: "mainnet",
Version: 10, Version: 10,
ManifestCid: MustParseCid("bafy2bzaceduyggnyqhlr346hfw32tbobzrvhzhill33zhe7jw64pmwjci2xoc"), ManifestCid: MustParseCid("bafy2bzacedjq47v3yxxptl3vvtpin4optnhoe7ynxjncuhpak2ifdvff2mrfy"),
Actors: map[string]cid.Cid{ Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzacedmr3wxl7qmhquageorrt3aavbzqfpm7eymxidakwuhaobu7dseqs"), "account": MustParseCid("bafk2bzaceb7wftmnoa5zbeu6jsrzvqpjfd7kudhueve6duwxcflcaqeagqg6g"),
"cron": MustParseCid("bafk2bzaceblekxapm5nnqnxmw3mk27236iyutvbhhpsc3fyde7zi7guccn7cc"), "cron": MustParseCid("bafk2bzacean2xecc6kfbrueglsujjqswz5nvjstmtvdq2zc5vk4cbh6gvgxcq"),
"datacap": MustParseCid("bafk2bzacedu4jevyvqsilq7bq4uhegbkm75muwebc5ifqpfaojwhexf2j4i6a"), "datacap": MustParseCid("bafk2bzacear4esja4asfsdeqto6o5cjn5dbgxmzvu2uel36tzdp2s26fkte4y"),
"eam": MustParseCid("bafk2bzacedc7224twbolvdq6iwc7ybdpah2ywe3ueo33jv67ecimndinle374"), "eam": MustParseCid("bafk2bzacectduzxzk23xffgohmsmq4gisl4etaguq2xe6h52y7aiaaibmi2pg"),
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"), "ethaccount": MustParseCid("bafk2bzacecqoxzy2p3i46ncuvw6wzlesaw5iobqpp7nmjtkbxyiwblg4frzmg"),
"evm": MustParseCid("bafk2bzaceaggldo6wmkvp5innv4pnjv4xnpedspzofvma3dhu7vk45hh5djoq"), "evm": MustParseCid("bafk2bzacecgz6klga2lwjp3d3iyzkzm4td5aefeaymmn3rmixgg7a4vwoewcu"),
"init": MustParseCid("bafk2bzacedutlaebaczkdi4vqvt3xim24u3whleqk2r4lufjd5jnmxcosea6q"), "init": MustParseCid("bafk2bzacebzrlucqk23kkjv26srpzjgztx7qjm23suqbyzu2qdto5jbpifm7y"),
"multisig": MustParseCid("bafk2bzaceatiqxjwtugpzus3s52zoggnrftxqn7kiw3obvjgkjvtd6zr3636q"), "multisig": MustParseCid("bafk2bzacedls4tgmkfkasgcsfrtnkjoi6yoze5yq4cafqzbjvbty5gfeut4n4"),
"paymentchannel": MustParseCid("bafk2bzacebyviac6i43gtsvmjfg6mzcp6rwgz44axidc7m432btbmvt7i2m2g"), "paymentchannel": MustParseCid("bafk2bzaceazuokt65n3hqjgmwmgoi6gpcvete2b46nlecnynjkgrzp4wnl4ii"),
"reward": MustParseCid("bafk2bzacecbcnlvk2izojpfoaksitqenhzaofn6ynxx5pegl4y45wjlouexdi"), "placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
"storagemarket": MustParseCid("bafk2bzacebobteeoz2jycplgtydfyltzughegz2sopn6pzy2udjfvuo77joyk"), "reward": MustParseCid("bafk2bzacecqjpnbxravwqb7liwxowb5bdml4x2qboo5vqxk7slprq3eo4ujp2"),
"storageminer": MustParseCid("bafk2bzacecwcypas3y6u4rya7qolfwmou437xgrjxh7mnnim7bo3nhk4dscxw"), "storagemarket": MustParseCid("bafk2bzacecuedinzm256nup2pbsdrnxerfk33hqxhakupb3c26fwk576ehgiw"),
"storagepower": MustParseCid("bafk2bzacec62kids6rcrdmdeqhwiz3s5rs35s5gn25ilwemgmm6jqnr2rnaaq"), "storageminer": MustParseCid("bafk2bzaceb4c7iqlmk4lgnkccpdvzdv6kbwqz2leyluuehh2ino2m6e5cd7d6"),
"system": MustParseCid("bafk2bzacecj3c4bjbs2xfttn7zqle7yocqh47u2s7hwuxrsn7fi5h74tcyxoc"), "storagepower": MustParseCid("bafk2bzacedkwcuzvlx43nbwdwms5smerdaeja45rh7d646k4nc4s5toyryuxi"),
"verifiedregistry": MustParseCid("bafk2bzacedgf7zbnlste5ukzueduemkimiit64scz7lvebztufx5jxtx6gkz2"), "system": MustParseCid("bafk2bzacedexhpixywvxk37jyp3sehcqmomyq4kpxu3wjhrehawyjhv6grav2"),
"verifiedregistry": MustParseCid("bafk2bzacebsnm343frbrfted3vbia4to7iiav4qm3tvpkcbsgkd5fynop3q7s"),
}, },
}, { }, {
Network: "testing", Network: "testing",
@ -324,23 +351,24 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, { }, {
Network: "testing", Network: "testing",
Version: 10, Version: 10,
ManifestCid: MustParseCid("bafy2bzacearlgbespxi2zdrybtp2rrbwscmtbyou5qa2egbdvcz6v2yjjqvjo"), ManifestCid: MustParseCid("bafy2bzacececfnvx4hay5b6yhtkxdqgkauupeqpwnlgainug6blp2isihwtww"),
Actors: map[string]cid.Cid{ Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzaceba6me5ipkcijuhyypnzjydhv3ebi2ctailar7mtzlk4vk3rbxfee"), "account": MustParseCid("bafk2bzaceb56iceglbwg3s2skdjj5vhak7j6srlaxvd7v6hzvxpccwsrvfaxi"),
"cron": MustParseCid("bafk2bzacea6k2mai2xnakygqvbigivfrvv5q7d34qrzjv2crkqtwbjxnxmkbe"), "cron": MustParseCid("bafk2bzacearjb3buxy4jwhcn4jeqbof3dinsh52zyj74djkfghmjdoxbsvjkq"),
"datacap": MustParseCid("bafk2bzaceah4oxcgck6bcfkzctm2klpvmltyidq7uxnlkcap6ypi3lnkcvrqk"), "datacap": MustParseCid("bafk2bzacec2dghsnwhyhquwkbsfcct53pgglxzgmw7j66y3keniklbiq4q7ti"),
"eam": MustParseCid("bafk2bzacedjtkvocrnkrot2oztsfrxtpwl32wwbmbkrjfbbm4xipwzrhhxn5c"), "eam": MustParseCid("bafk2bzacedojoymbgz275lzvtlpaf2thoydz7fb274mhvadbpk2thbgpye72s"),
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"), "ethaccount": MustParseCid("bafk2bzaceddhvqqkwc4p7exdgv2bwefkk3lnq2rw6chvar7hdeowahtjdmznw"),
"evm": MustParseCid("bafk2bzaced6vhabkr2ojpjzsybrq5yvksjzpjk6yei6fwobkwwydlj5f473pw"), "evm": MustParseCid("bafk2bzacecgzk3ompisq5n7oualijioce6nhsm6zwil7p5p57nojuyrdckti2"),
"init": MustParseCid("bafk2bzaceaib3o5e7wop7kwjirgpferqarmngrgjkur2yhdnwplctidpxsgme"), "init": MustParseCid("bafk2bzaceacdto7l5qp65ukclc3qqlfpv3tdio7u5lxufg2uc3hrx5hpqt2x2"),
"multisig": MustParseCid("bafk2bzaced4z3awacxumq6yr33a3adu2legb7colahgvqpmigs3fvvjxs3byc"), "multisig": MustParseCid("bafk2bzacebw6ujt54gyhxvo5jmimg3z54crmfzbbcr677ljqmmb2ejh6srlsm"),
"paymentchannel": MustParseCid("bafk2bzaceb6mfi24mpzt7qlkratj2tdtqo7aia67zcztuslrxcjaycz6fnai6"), "paymentchannel": MustParseCid("bafk2bzacebfht4drwm5aagcx4kvuiwclldd6rnosce42474u4asnurjqyxhna"),
"reward": MustParseCid("bafk2bzacebngh5kwtem4ncarpjtxhs4rwyoficttkgxlsjtiz5ucdi4p3czoc"), "placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
"storagemarket": MustParseCid("bafk2bzacecnsibyil62jfq2gbkoe6c2epehfcrxzjmqjnwz7kxab2hkbu3lks"), "reward": MustParseCid("bafk2bzacedqmiebckz7xqs7f7gcj67wzzpko2q3jhom6rwtopogv7iz5bnwlu"),
"storageminer": MustParseCid("bafk2bzacedzw4vkrt3sdkhagpvn62pknyyjkcrzewncvtvae5qgwe6ulzx4a4"), "storagemarket": MustParseCid("bafk2bzaceam3n2xjbvkyyifw7jvkc4z4lxvblnbmx4ruzr5lpesgmpuhbmb2w"),
"storagepower": MustParseCid("bafk2bzacedxgadibot6nzvripqt3z5shvjsoscupinejnsvswq4cbeskblwyy"), "storageminer": MustParseCid("bafk2bzacebcbyuzniiqksk47v7zyfc56noblbsmlqblv3n6s7l5un3heigdwk"),
"system": MustParseCid("bafk2bzacedm24avrmp5o5odhpad43qeglooflygwh4ah7qnzbij2h4c3v6cge"), "storagepower": MustParseCid("bafk2bzacechzbqmunxv6o2zgp4uicswapmgexc3uejco2n2r7cirbijrbgewc"),
"verifiedregistry": MustParseCid("bafk2bzaceapq3j6ww3ofytwq3pz3obumaqsyg3wrm6tksdh7op23a72co3rya"), "system": MustParseCid("bafk2bzaceb6obdybgoyjvdfxvxg5uxhrpnoixtbof663dllo2eelcuvsfycew"),
"verifiedregistry": MustParseCid("bafk2bzacedlogwaofqaqou4pckoatwei2ulbz3ucjmbsm3lfwuw3tr7g5opjc"),
}, },
}, { }, {
Network: "testing-fake-proofs", Network: "testing-fake-proofs",
@ -380,22 +408,23 @@ var EmbeddedBuiltinActorsMetadata []*BuiltinActorsMetadata = []*BuiltinActorsMet
}, { }, {
Network: "testing-fake-proofs", Network: "testing-fake-proofs",
Version: 10, Version: 10,
ManifestCid: MustParseCid("bafy2bzacea4irr2oxhclwt4mvtrevbzb7mbqddcebjz7bkqjq6eoflpfhencc"), ManifestCid: MustParseCid("bafy2bzacec4yawvg2rbdvzlez4lyf4e7ysjfjdrg5mpclvvwxt7texyeeletg"),
Actors: map[string]cid.Cid{ Actors: map[string]cid.Cid{
"account": MustParseCid("bafk2bzaceba6me5ipkcijuhyypnzjydhv3ebi2ctailar7mtzlk4vk3rbxfee"), "account": MustParseCid("bafk2bzaceb56iceglbwg3s2skdjj5vhak7j6srlaxvd7v6hzvxpccwsrvfaxi"),
"cron": MustParseCid("bafk2bzacea6k2mai2xnakygqvbigivfrvv5q7d34qrzjv2crkqtwbjxnxmkbe"), "cron": MustParseCid("bafk2bzacearjb3buxy4jwhcn4jeqbof3dinsh52zyj74djkfghmjdoxbsvjkq"),
"datacap": MustParseCid("bafk2bzaceah4oxcgck6bcfkzctm2klpvmltyidq7uxnlkcap6ypi3lnkcvrqk"), "datacap": MustParseCid("bafk2bzacec2dghsnwhyhquwkbsfcct53pgglxzgmw7j66y3keniklbiq4q7ti"),
"eam": MustParseCid("bafk2bzacedjtkvocrnkrot2oztsfrxtpwl32wwbmbkrjfbbm4xipwzrhhxn5c"), "eam": MustParseCid("bafk2bzacedojoymbgz275lzvtlpaf2thoydz7fb274mhvadbpk2thbgpye72s"),
"embryo": MustParseCid("bafk2bzacebj2mj5zlcs3yjlgpbznzistfjkdlwaoncjziliqrxqavvz4dcvnk"), "ethaccount": MustParseCid("bafk2bzaceddhvqqkwc4p7exdgv2bwefkk3lnq2rw6chvar7hdeowahtjdmznw"),
"evm": MustParseCid("bafk2bzaced6vhabkr2ojpjzsybrq5yvksjzpjk6yei6fwobkwwydlj5f473pw"), "evm": MustParseCid("bafk2bzacecgzk3ompisq5n7oualijioce6nhsm6zwil7p5p57nojuyrdckti2"),
"init": MustParseCid("bafk2bzaceaib3o5e7wop7kwjirgpferqarmngrgjkur2yhdnwplctidpxsgme"), "init": MustParseCid("bafk2bzaceacdto7l5qp65ukclc3qqlfpv3tdio7u5lxufg2uc3hrx5hpqt2x2"),
"multisig": MustParseCid("bafk2bzaced4z3awacxumq6yr33a3adu2legb7colahgvqpmigs3fvvjxs3byc"), "multisig": MustParseCid("bafk2bzacebw6ujt54gyhxvo5jmimg3z54crmfzbbcr677ljqmmb2ejh6srlsm"),
"paymentchannel": MustParseCid("bafk2bzaceb6mfi24mpzt7qlkratj2tdtqo7aia67zcztuslrxcjaycz6fnai6"), "paymentchannel": MustParseCid("bafk2bzacebfht4drwm5aagcx4kvuiwclldd6rnosce42474u4asnurjqyxhna"),
"reward": MustParseCid("bafk2bzacebngh5kwtem4ncarpjtxhs4rwyoficttkgxlsjtiz5ucdi4p3czoc"), "placeholder": MustParseCid("bafk2bzacedv773z6clfjh7wxvlqd6ki7bncztt73org7apnnt2acjigrjdg4a"),
"storagemarket": MustParseCid("bafk2bzacecnsibyil62jfq2gbkoe6c2epehfcrxzjmqjnwz7kxab2hkbu3lks"), "reward": MustParseCid("bafk2bzacedqmiebckz7xqs7f7gcj67wzzpko2q3jhom6rwtopogv7iz5bnwlu"),
"storageminer": MustParseCid("bafk2bzaceb4grddnw54gczgcdak5a2gqvwed66mhibbug6qu4jy35bf45jltg"), "storagemarket": MustParseCid("bafk2bzaceam3n2xjbvkyyifw7jvkc4z4lxvblnbmx4ruzr5lpesgmpuhbmb2w"),
"storagepower": MustParseCid("bafk2bzacedp2dnbk4bg3hhaeztre4q3jv7eqs267rlafszpggb2njjn3x5eru"), "storageminer": MustParseCid("bafk2bzaceataoi4vlifq2roanrfjt2f2cql2dq4osjs5i3nt4v76462mtrcm2"),
"system": MustParseCid("bafk2bzacedm24avrmp5o5odhpad43qeglooflygwh4ah7qnzbij2h4c3v6cge"), "storagepower": MustParseCid("bafk2bzacede4nq6cbym2z7p5vc2gwbxhnd34qxtd7sy4rmwula3kk6yhbqtve"),
"verifiedregistry": MustParseCid("bafk2bzaceapq3j6ww3ofytwq3pz3obumaqsyg3wrm6tksdh7op23a72co3rya"), "system": MustParseCid("bafk2bzaceb6obdybgoyjvdfxvxg5uxhrpnoixtbof663dllo2eelcuvsfycew"),
"verifiedregistry": MustParseCid("bafk2bzacedlogwaofqaqou4pckoatwei2ulbz3ucjmbsm3lfwuw3tr7g5opjc"),
}, },
}} }}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -21,6 +21,7 @@ const GenesisFile = ""
var NetworkBundle = "devnet" var NetworkBundle = "devnet"
var BundleOverrides map[actorstypes.Version]string var BundleOverrides map[actorstypes.Version]string
var ActorDebugging = true
const GenesisNetworkVersion = network.Version18 const GenesisNetworkVersion = network.Version18
@ -58,6 +59,8 @@ var UpgradeSkyrHeight = abi.ChainEpoch(-19)
var UpgradeSharkHeight = abi.ChainEpoch(-20) var UpgradeSharkHeight = abi.ChainEpoch(-20)
var UpgradeHyggeHeight = abi.ChainEpoch(-21)
var DrandSchedule = map[abi.ChainEpoch]DrandEnum{ var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet, 0: DrandMainnet,
} }
@ -110,6 +113,7 @@ func init() {
UpgradeOhSnapHeight = getUpgradeHeight("LOTUS_OHSNAP_HEIGHT", UpgradeOhSnapHeight) UpgradeOhSnapHeight = getUpgradeHeight("LOTUS_OHSNAP_HEIGHT", UpgradeOhSnapHeight)
UpgradeSkyrHeight = getUpgradeHeight("LOTUS_SKYR_HEIGHT", UpgradeSkyrHeight) UpgradeSkyrHeight = getUpgradeHeight("LOTUS_SKYR_HEIGHT", UpgradeSkyrHeight)
UpgradeSharkHeight = getUpgradeHeight("LOTUS_SHARK_HEIGHT", UpgradeSharkHeight) UpgradeSharkHeight = getUpgradeHeight("LOTUS_SHARK_HEIGHT", UpgradeSharkHeight)
UpgradeHyggeHeight = getUpgradeHeight("LOTUS_HYGGE_HEIGHT", UpgradeHyggeHeight)
BuildType |= Build2k BuildType |= Build2k
@ -130,4 +134,8 @@ const InteractivePoRepConfidence = 6
const BootstrapPeerThreshold = 1 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 var WhitelistedBlock = cid.Undef

View File

@ -23,6 +23,7 @@ const GenesisNetworkVersion = network.Version16
var NetworkBundle = "butterflynet" var NetworkBundle = "butterflynet"
var BundleOverrides map[actorstypes.Version]string var BundleOverrides map[actorstypes.Version]string
var ActorDebugging = false
const BootstrappersFile = "butterflynet.pi" const BootstrappersFile = "butterflynet.pi"
const GenesisFile = "butterflynet.car" const GenesisFile = "butterflynet.car"
@ -49,7 +50,8 @@ const UpgradeHyperdriveHeight = -16
const UpgradeChocolateHeight = -17 const UpgradeChocolateHeight = -17
const UpgradeOhSnapHeight = -18 const UpgradeOhSnapHeight = -18
const UpgradeSkyrHeight = -19 const UpgradeSkyrHeight = -19
const UpgradeSharkHeight = abi.ChainEpoch(600) const UpgradeSharkHeight = abi.ChainEpoch(-20)
const UpgradeHyggeHeight = abi.ChainEpoch(600)
var SupportedProofTypes = []abi.RegisteredSealProof{ var SupportedProofTypes = []abi.RegisteredSealProof{
abi.RegisteredSealProof_StackedDrg512MiBV1, 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 // BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
const BootstrapPeerThreshold = 2 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 var WhitelistedBlock = cid.Undef

View File

@ -4,6 +4,7 @@
package build package build
import ( import (
"math"
"os" "os"
"strconv" "strconv"
@ -26,6 +27,7 @@ const GenesisNetworkVersion = network.Version0
var NetworkBundle = "calibrationnet" var NetworkBundle = "calibrationnet"
var BundleOverrides map[actorstypes.Version]string var BundleOverrides map[actorstypes.Version]string
var ActorDebugging = false
const BootstrappersFile = "calibnet.pi" const BootstrappersFile = "calibnet.pi"
const GenesisFile = "calibnet.car" const GenesisFile = "calibnet.car"
@ -69,6 +71,8 @@ const UpgradeSkyrHeight = 510
const UpgradeSharkHeight = 16800 // 6 days after genesis const UpgradeSharkHeight = 16800 // 6 days after genesis
const UpgradeHyggeHeight = math.MaxInt64
var SupportedProofTypes = []abi.RegisteredSealProof{ var SupportedProofTypes = []abi.RegisteredSealProof{
abi.RegisteredSealProof_StackedDrg32GiBV1, abi.RegisteredSealProof_StackedDrg32GiBV1,
abi.RegisteredSealProof_StackedDrg64GiBV1, 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 // BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
const BootstrapPeerThreshold = 4 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 var WhitelistedBlock = cid.Undef

View 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

View File

@ -20,6 +20,7 @@ import (
var NetworkBundle = "caterpillarnet" var NetworkBundle = "caterpillarnet"
var BundleOverrides map[actorstypes.Version]string var BundleOverrides map[actorstypes.Version]string
var ActorDebugging = false
const BootstrappersFile = "interopnet.pi" const BootstrappersFile = "interopnet.pi"
const GenesisFile = "interopnet.car" const GenesisFile = "interopnet.car"
@ -49,7 +50,9 @@ var UpgradeChocolateHeight = abi.ChainEpoch(-17)
var UpgradeOhSnapHeight = abi.ChainEpoch(-18) var UpgradeOhSnapHeight = abi.ChainEpoch(-18)
var UpgradeSkyrHeight = abi.ChainEpoch(-19) 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{ var DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet, 0: DrandMainnet,
@ -104,6 +107,7 @@ func init() {
UpgradeOhSnapHeight = getUpgradeHeight("LOTUS_OHSNAP_HEIGHT", UpgradeOhSnapHeight) UpgradeOhSnapHeight = getUpgradeHeight("LOTUS_OHSNAP_HEIGHT", UpgradeOhSnapHeight)
UpgradeSkyrHeight = getUpgradeHeight("LOTUS_SKYR_HEIGHT", UpgradeSkyrHeight) UpgradeSkyrHeight = getUpgradeHeight("LOTUS_SKYR_HEIGHT", UpgradeSkyrHeight)
UpgradeSharkHeight = getUpgradeHeight("LOTUS_SHARK_HEIGHT", UpgradeSharkHeight) UpgradeSharkHeight = getUpgradeHeight("LOTUS_SHARK_HEIGHT", UpgradeSharkHeight)
UpgradeHyggeHeight = getUpgradeHeight("LOTUS_HYGGE_HEIGHT", UpgradeHyggeHeight)
BuildType |= BuildInteropnet BuildType |= BuildInteropnet
SetAddressNetwork(address.Testnet) 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 // BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
const BootstrapPeerThreshold = 2 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 var WhitelistedBlock = cid.Undef

View File

@ -1,5 +1,5 @@
//go:build !debug && !2k && !testground && !calibnet && !butterflynet && !interopnet //go:build !debug && !2k && !testground && !calibnet && !butterflynet && !interopnet && !wallabynet && !hyperspacenet
// +build !debug,!2k,!testground,!calibnet,!butterflynet,!interopnet // +build !debug,!2k,!testground,!calibnet,!butterflynet,!interopnet,!wallabynet,!hyperspacenet
package build 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. // NOTE: DO NOT change this unless you REALLY know what you're doing. This is consensus critical.
var BundleOverrides map[actorstypes.Version]string 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 GenesisNetworkVersion = network.Version0
const BootstrappersFile = "mainnet.pi" const BootstrappersFile = "mainnet.pi"
@ -56,6 +59,7 @@ const UpgradePersianHeight = UpgradeCalicoHeight + (builtin2.EpochsInHour * 60)
const UpgradeOrangeHeight = 336458 const UpgradeOrangeHeight = 336458
// 2020-12-22T02:00:00Z // 2020-12-22T02:00:00Z
// var because of wdpost_test.go
var UpgradeClausHeight = abi.ChainEpoch(343200) var UpgradeClausHeight = abi.ChainEpoch(343200)
// 2021-03-04T00:00:30Z // 2021-03-04T00:00:30Z
@ -80,7 +84,10 @@ const UpgradeOhSnapHeight = 1594680
const UpgradeSkyrHeight = 1960320 const UpgradeSkyrHeight = 1960320
// 2022-11-30T14:00:00Z // 2022-11-30T14:00:00Z
var UpgradeSharkHeight = abi.ChainEpoch(2383680) const UpgradeSharkHeight = 2383680
// ??????????????
var UpgradeHyggeHeight = abi.ChainEpoch(math.MaxInt64)
var SupportedProofTypes = []abi.RegisteredSealProof{ var SupportedProofTypes = []abi.RegisteredSealProof{
abi.RegisteredSealProof_StackedDrg32GiBV1, abi.RegisteredSealProof_StackedDrg32GiBV1,
@ -95,8 +102,8 @@ func init() {
SetAddressNetwork(address.Mainnet) SetAddressNetwork(address.Mainnet)
} }
if os.Getenv("LOTUS_DISABLE_SHARK") == "1" { if os.Getenv("LOTUS_DISABLE_HYGGE") == "1" {
UpgradeSharkHeight = math.MaxInt64 UpgradeHyggeHeight = math.MaxInt64
} }
// NOTE: DO NOT change this unless you REALLY know what you're doing. This is not consensus critical, however, // 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 // BootstrapPeerThreshold is the minimum number peers we need to track for a sync worker to start
const BootstrapPeerThreshold = 4 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 // we skip checks on message validity in this block to sidestep the zero-bls signature
var WhitelistedBlock = MustParseCid("bafy2bzaceapyg2uyzk7vueh3xccxkuwbz3nxewjyguoxvhx77malc2lzn2ybi") var WhitelistedBlock = MustParseCid("bafy2bzaceapyg2uyzk7vueh3xccxkuwbz3nxewjyguoxvhx77malc2lzn2ybi")

View File

@ -108,6 +108,7 @@ var (
UpgradeOhSnapHeight abi.ChainEpoch = -17 UpgradeOhSnapHeight abi.ChainEpoch = -17
UpgradeSkyrHeight abi.ChainEpoch = -18 UpgradeSkyrHeight abi.ChainEpoch = -18
UpgradeSharkHeight abi.ChainEpoch = -19 UpgradeSharkHeight abi.ChainEpoch = -19
UpgradeHyggeHeight abi.ChainEpoch = -20
DrandSchedule = map[abi.ChainEpoch]DrandEnum{ DrandSchedule = map[abi.ChainEpoch]DrandEnum{
0: DrandMainnet, 0: DrandMainnet,
@ -116,6 +117,7 @@ var (
GenesisNetworkVersion = network.Version0 GenesisNetworkVersion = network.Version0
NetworkBundle = "devnet" NetworkBundle = "devnet"
BundleOverrides map[actorstypes.Version]string BundleOverrides map[actorstypes.Version]string
ActorDebugging = true
NewestNetworkVersion = network.Version16 NewestNetworkVersion = network.Version16
ActorUpgradeNetworkVersion = network.Version16 ActorUpgradeNetworkVersion = network.Version16
@ -129,3 +131,7 @@ var (
) )
const BootstrapPeerThreshold = 1 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
View 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

View File

@ -13,6 +13,8 @@ const (
BuildCalibnet = 0x4 BuildCalibnet = 0x4
BuildInteropnet = 0x5 BuildInteropnet = 0x5
BuildButterflynet = 0x7 BuildButterflynet = 0x7
BuildWallabynet = 0x8
BuildHyperspacenet = 0x9
) )
func BuildTypeString() string { func BuildTypeString() string {
@ -31,6 +33,10 @@ func BuildTypeString() string {
return "+interopnet" return "+interopnet"
case BuildButterflynet: case BuildButterflynet:
return "+butterflynet" return "+butterflynet"
case BuildWallabynet:
return "+wallabynet"
case BuildHyperspacenet:
return "+hyperspacenet"
default: default:
return "+huh?" return "+huh?"
} }

View File

@ -274,6 +274,33 @@ func IsPaymentChannelActor(c cid.Cid) bool {
return false 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 { func makeAddress(addr string) address.Address {
ret, err := address.NewFromString(addr) ret, err := address.NewFromString(addr)
if err != nil { if err != nil {

View File

@ -153,6 +153,33 @@ func IsPaymentChannelActor(c cid.Cid) bool {
return false 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 { func makeAddress(addr string) address.Address {
ret, err := address.NewFromString(addr) ret, err := address.NewFromString(addr)
if err != nil { if err != nil {

View File

@ -13,11 +13,15 @@ import (
account10 "github.com/filecoin-project/go-state-types/builtin/v10/account" account10 "github.com/filecoin-project/go-state-types/builtin/v10/account"
cron10 "github.com/filecoin-project/go-state-types/builtin/v10/cron" cron10 "github.com/filecoin-project/go-state-types/builtin/v10/cron"
datacap10 "github.com/filecoin-project/go-state-types/builtin/v10/datacap" 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" _init10 "github.com/filecoin-project/go-state-types/builtin/v10/init"
market10 "github.com/filecoin-project/go-state-types/builtin/v10/market" market10 "github.com/filecoin-project/go-state-types/builtin/v10/market"
miner10 "github.com/filecoin-project/go-state-types/builtin/v10/miner" miner10 "github.com/filecoin-project/go-state-types/builtin/v10/miner"
multisig10 "github.com/filecoin-project/go-state-types/builtin/v10/multisig" multisig10 "github.com/filecoin-project/go-state-types/builtin/v10/multisig"
paych10 "github.com/filecoin-project/go-state-types/builtin/v10/paych" 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" power10 "github.com/filecoin-project/go-state-types/builtin/v10/power"
reward10 "github.com/filecoin-project/go-state-types/builtin/v10/reward" reward10 "github.com/filecoin-project/go-state-types/builtin/v10/reward"
system10 "github.com/filecoin-project/go-state-types/builtin/v10/system" system10 "github.com/filecoin-project/go-state-types/builtin/v10/system"
@ -265,6 +269,7 @@ func MakeRegistry(av actorstypes.Version) []RegistryEntry {
methods: datacap9.Methods, methods: datacap9.Methods,
state: new(datacap9.State), state: new(datacap9.State),
}) })
} }
} }
@ -343,6 +348,32 @@ func MakeRegistry(av actorstypes.Version) []RegistryEntry {
methods: datacap10.Methods, methods: datacap10.Methods,
state: new(datacap10.State), 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,
})
} }
} }

View File

@ -25,6 +25,12 @@ import (
{{if (ge . 9)}} {{if (ge . 9)}}
datacap{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/datacap" datacap{{.}} "github.com/filecoin-project/go-state-types/builtin/v{{.}}/datacap"
{{end}} {{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}} {{end}}
"github.com/filecoin-project/go-state-types/cbor" "github.com/filecoin-project/go-state-types/cbor"
rtt "github.com/filecoin-project/go-state-types/rt" rtt "github.com/filecoin-project/go-state-types/rt"
@ -174,6 +180,32 @@ func MakeRegistry(av actorstypes.Version) []RegistryEntry {
methods: datacap{{.}}.Methods, methods: datacap{{.}}.Methods,
state: new(datacap{{.}}.State), state: new(datacap{{.}}.State),
}){{end}} }){{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}} {{end}}

View File

@ -93,6 +93,7 @@ func (t *TipSetExecutor) ApplyBlocks(ctx context.Context,
vmopt := &vm.VMOpts{ vmopt := &vm.VMOpts{
StateBase: base, StateBase: base,
Epoch: e, Epoch: e,
Timestamp: ts.MinTimestamp(),
Rand: r, Rand: r,
Bstore: sm.ChainStore().StateBlockstore(), Bstore: sm.ChainStore().StateBlockstore(),
Actors: NewActorRegistry(), Actors: NewActorRegistry(),

View File

@ -14,6 +14,7 @@ import (
cbor "github.com/ipfs/go-ipld-cbor" cbor "github.com/ipfs/go-ipld-cbor"
logging "github.com/ipfs/go-log/v2" logging "github.com/ipfs/go-log/v2"
pubsub "github.com/libp2p/go-libp2p-pubsub" pubsub "github.com/libp2p/go-libp2p-pubsub"
"github.com/multiformats/go-varint"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"go.opencensus.io/stats" "go.opencensus.io/stats"
"go.opencensus.io/trace" "go.opencensus.io/trace"
@ -21,6 +22,7 @@ import (
"github.com/filecoin-project/go-address" "github.com/filecoin-project/go-address"
"github.com/filecoin-project/go-state-types/abi" "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/crypto"
"github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/go-state-types/network"
blockadt "github.com/filecoin-project/specs-actors/actors/util/adt" 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 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 // 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 { 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) 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") return xerrors.New("Sender must be an account actor")
} }
nonces[sender] = act.Nonce nonces[sender] = act.Nonce
@ -542,25 +577,23 @@ func (filec *FilecoinEC) checkBlockMessages(ctx context.Context, b *types.FullBl
smArr := blockadt.MakeEmptyArray(tmpstore) smArr := blockadt.MakeEmptyArray(tmpstore)
for i, m := range b.SecpkMessages { for i, m := range b.SecpkMessages {
if filec.sm.GetNetworkVersion(ctx, b.Header.Height) >= network.Version14 { if nv >= network.Version14 && !chain.IsValidSecpkSigType(nv, m.Signature.Type) {
if m.Signature.Type != crypto.SigTypeSecp256k1 { return xerrors.Errorf("block had invalid signed message at index %d: %w", i, err)
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err)
}
} }
if err := checkMsg(m); err != nil { if err := checkMsg(m); err != nil {
return xerrors.Errorf("block had invalid secpk message at index %d: %w", i, err) 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 // `From` being an account actor is only validated inside the `vm.ResolveToDeterministicAddr` call
// in `StateManager.ResolveToKeyAddress` here (and not in `checkMsg`). // in `StateManager.ResolveToDeterministicAddress` here (and not in `checkMsg`).
kaddr, err := filec.sm.ResolveToKeyAddress(ctx, m.Message.From, baseTs) kaddr, err := filec.sm.ResolveToDeterministicAddress(ctx, m.Message.From, baseTs)
if err != nil { if err != nil {
return xerrors.Errorf("failed to resolve key addr: %w", err) return xerrors.Errorf("failed to resolve key addr: %w", err)
} }
if err := sigs.Verify(&m.Signature, kaddr, m.Message.Cid().Bytes()); err != nil { if err := chain.AuthenticateMessage(m, kaddr); err != nil {
return xerrors.Errorf("secpk message %s has invalid signature: %w", m.Cid(), err) return xerrors.Errorf("failed to validate signature: %w", err)
} }
c, err := store.PutMessage(ctx, tmpbs, m) c, err := store.PutMessage(ctx, tmpbs, m)

View File

@ -9,6 +9,7 @@ import (
"github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/chain"
"github.com/filecoin-project/lotus/chain/consensus" "github.com/filecoin-project/lotus/chain/consensus"
"github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
@ -54,6 +55,7 @@ func (filec *FilecoinEC) CreateBlock(ctx context.Context, w api.Wallet, bt *api.
var blsMsgCids, secpkMsgCids []cid.Cid var blsMsgCids, secpkMsgCids []cid.Cid
var blsSigs []crypto.Signature var blsSigs []crypto.Signature
nv := filec.sm.GetNetworkVersion(ctx, bt.Epoch)
for _, msg := range bt.Messages { for _, msg := range bt.Messages {
if msg.Signature.Type == crypto.SigTypeBLS { if msg.Signature.Type == crypto.SigTypeBLS {
blsSigs = append(blsSigs, msg.Signature) 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) 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) c, err := filec.sm.ChainStore().PutMessage(ctx, msg)
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -18,8 +18,10 @@ import (
"github.com/filecoin-project/go-state-types/abi" "github.com/filecoin-project/go-state-types/abi"
actorstypes "github.com/filecoin-project/go-state-types/actors" actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/go-state-types/big" "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" 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/manifest"
"github.com/filecoin-project/go-state-types/migration"
"github.com/filecoin-project/go-state-types/network" "github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/go-state-types/rt" "github.com/filecoin-project/go-state-types/rt"
gstStore "github.com/filecoin-project/go-state-types/store" gstStore "github.com/filecoin-project/go-state-types/store"
@ -232,8 +234,18 @@ func DefaultUpgradeSchedule() stmgr.UpgradeSchedule {
StopWithin: 5, StopWithin: 5,
}}, }},
Expensive: true, 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 { for _, u := range updates {
@ -1580,11 +1592,110 @@ func upgradeActorsV9Common(
func UpgradeActorsV10(ctx context.Context, sm *stmgr.StateManager, cache stmgr.MigrationCache, cb stmgr.ExecMonitor, 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) { 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 config := migration.Config{
// - the init actor state to include the (empty) installed actors field MaxWorkers: uint(workerCount),
// - state tree migration to v5 JobQueueSize: 1000,
return cid.Undef, fmt.Errorf("IMPLEMENTME: v10 migration") 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 // Example upgrade function if upgrade requires only code changes

View 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
}

View 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
}

View 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{}
}

View 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)
})
}
}

View 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
}

View 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
}

View 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
}

View File

@ -468,10 +468,6 @@ func (cg *ChainGen) NextTipSetFromMinersWithMessagesAndNulls(base *types.TipSet,
return nil, xerrors.Errorf("making a block for next tipset failed: %w", err) 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) blks = append(blks, fblk)
} }
} }

View File

@ -123,12 +123,7 @@ Genesis: {
func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template genesis.Template) (*state.StateTree, map[address.Address]address.Address, error) { func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template genesis.Template) (*state.StateTree, map[address.Address]address.Address, error) {
// Create empty state tree // Create empty state tree
cst := cbor.NewCborStore(bs) 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) sv, err := state.VersionForNetwork(template.NetworkVersion)
if err != nil { if err != nil {
@ -238,15 +233,12 @@ func MakeInitialStateTree(ctx context.Context, bs bstore.Blockstore, template ge
// Create accounts // Create accounts
for _, info := range template.Accounts { for _, info := range template.Accounts {
switch info.Type { switch info.Type {
case genesis.TAccount: case genesis.TAccount:
if err := CreateAccountActor(ctx, cst, state, info, keyIDs, av); err != nil { if err := CreateAccountActor(ctx, cst, state, info, keyIDs, av); err != nil {
return nil, nil, xerrors.Errorf("failed to create account actor: %w", err) return nil, nil, xerrors.Errorf("failed to create account actor: %w", err)
} }
case genesis.TMultisig: case genesis.TMultisig:
ida, err := address.NewIDAddress(uint64(idStart)) ida, err := address.NewIDAddress(uint64(idStart))
if err != nil { if err != nil {
return nil, nil, err 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) 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) stateroot, err := st.Flush(ctx)
if err != nil { if err != nil {
return nil, xerrors.Errorf("flush state tree failed: %w", err) 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) 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) stateroot, err = SetupStorageMiners(ctx, cs, sys, stateroot, template.Miners, template.NetworkVersion)
if err != nil { if err != nil {
return nil, xerrors.Errorf("setup miners failed: %w", err) 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)) store := adt.WrapStore(ctx, cbor.NewCborStore(bs))
emptyroot, err := adt0.MakeEmptyArray(store).Root() emptyroot, err := adt0.MakeEmptyArray(store).Root()
if err != nil { if err != nil {

View 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
}

View File

@ -33,12 +33,13 @@ import (
"github.com/filecoin-project/lotus/api" "github.com/filecoin-project/lotus/api"
"github.com/filecoin-project/lotus/build" "github.com/filecoin-project/lotus/build"
"github.com/filecoin-project/lotus/chain"
"github.com/filecoin-project/lotus/chain/consensus/filcns"
"github.com/filecoin-project/lotus/chain/stmgr" "github.com/filecoin-project/lotus/chain/stmgr"
"github.com/filecoin-project/lotus/chain/store" "github.com/filecoin-project/lotus/chain/store"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/journal" "github.com/filecoin-project/lotus/journal"
"github.com/filecoin-project/lotus/lib/sigs"
"github.com/filecoin-project/lotus/metrics" "github.com/filecoin-project/lotus/metrics"
"github.com/filecoin-project/lotus/node/modules/dtypes" "github.com/filecoin-project/lotus/node/modules/dtypes"
) )
@ -476,7 +477,7 @@ func (mp *MessagePool) resolveToKey(ctx context.Context, addr address.Address) (
} }
// resolve the 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 { if err != nil {
return address.Undef, err return address.Undef, err
} }
@ -772,11 +773,9 @@ func sigCacheKey(m *types.SignedMessage) (string, error) {
if len(m.Signature.Data) != ffi.SignatureBytes { if len(m.Signature.Data) != ffi.SignatureBytes {
return "", fmt.Errorf("bls signature incorrectly sized") return "", fmt.Errorf("bls signature incorrectly sized")
} }
hashCache := blake2b.Sum256(append(m.Cid().Bytes(), m.Signature.Data...)) hashCache := blake2b.Sum256(append(m.Cid().Bytes(), m.Signature.Data...))
return string(hashCache[:]), nil return string(hashCache[:]), nil
case crypto.SigTypeSecp256k1: case crypto.SigTypeSecp256k1, crypto.SigTypeDelegated:
return string(m.Cid().Bytes()), nil return string(m.Cid().Bytes()), nil
default: default:
return "", xerrors.Errorf("unrecognized signature type: %d", m.Signature.Type) return "", xerrors.Errorf("unrecognized signature type: %d", m.Signature.Type)
@ -795,8 +794,8 @@ func (mp *MessagePool) VerifyMsgSig(m *types.SignedMessage) error {
return nil return nil
} }
if err := sigs.Verify(&m.Signature, m.Message.From, m.Message.Cid().Bytes()); err != nil { if err := chain.AuthenticateMessage(m, m.Message.From); err != nil {
return err return xerrors.Errorf("failed to validate signature: %w", err)
} }
mp.sigValCache.Add(sck, struct{}{}) mp.sigValCache.Add(sck, struct{}{})
@ -853,18 +852,32 @@ func (mp *MessagePool) addTs(ctx context.Context, m *types.SignedMessage, curTs
mp.lk.Lock() mp.lk.Lock()
defer mp.lk.Unlock() 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) publish, err := mp.verifyMsgBeforeAdd(ctx, m, curTs, local)
if err != nil { if err != nil {
return false, err return false, xerrors.Errorf("verify msg failed: %w", err)
} }
if err := mp.checkBalance(ctx, m, curTs); err != nil { 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) err = mp.addLocked(ctx, m, !local, untrusted)
if err != nil { if err != nil {
return false, err return false, xerrors.Errorf("failed to add locked: %w", err)
} }
if local { if local {

View File

@ -155,14 +155,14 @@ func (tma *testMpoolAPI) GetActorAfter(addr address.Address, ts *types.TipSet) (
} }
return &types.Actor{ return &types.Actor{
Code: builtin2.StorageMarketActorCodeID, Code: builtin2.AccountActorCodeID,
Nonce: nonce, Nonce: nonce,
Balance: balance, Balance: balance,
}, nil }, nil
} }
func (tma *testMpoolAPI) StateAccountKeyAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { 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 { 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 address.Undef, fmt.Errorf("given address was not a key addr")
} }
return addr, nil return addr, nil

View File

@ -28,7 +28,7 @@ type Provider interface {
PutMessage(ctx context.Context, m types.ChainMsg) (cid.Cid, error) PutMessage(ctx context.Context, m types.ChainMsg) (cid.Cid, error)
PubSubPublish(string, []byte) error PubSubPublish(string, []byte) error
GetActorAfter(address.Address, *types.TipSet) (*types.Actor, 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 StateNetworkVersion(context.Context, abi.ChainEpoch) network.Version
MessagesForBlock(context.Context, *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error) MessagesForBlock(context.Context, *types.BlockHeader) ([]*types.Message, []*types.SignedMessage, error)
MessagesForTipset(context.Context, *types.TipSet) ([]types.ChainMsg, error) MessagesForTipset(context.Context, *types.TipSet) ([]types.ChainMsg, error)
@ -102,8 +102,8 @@ func (mpp *mpoolProvider) GetActorAfter(addr address.Address, ts *types.TipSet)
return st.GetActor(addr) return st.GetActor(addr)
} }
func (mpp *mpoolProvider) StateAccountKeyAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) { func (mpp *mpoolProvider) StateDeterministicAddressAtFinality(ctx context.Context, addr address.Address, ts *types.TipSet) (address.Address, error) {
return mpp.sm.ResolveToKeyAddressAtFinality(ctx, addr, ts) return mpp.sm.ResolveToDeterministicAddressAtFinality(ctx, addr, ts)
} }
func (mpp *mpoolProvider) StateNetworkVersion(ctx context.Context, height abi.ChainEpoch) network.Version { func (mpp *mpoolProvider) StateNetworkVersion(ctx context.Context, height abi.ChainEpoch) network.Version {

View File

@ -97,7 +97,7 @@ func (sm *selectedMessages) tryToAdd(mc *msgChain) bool {
sm.msgs = append(sm.msgs, mc.msgs...) sm.msgs = append(sm.msgs, mc.msgs...)
sm.blsLimit -= l sm.blsLimit -= l
sm.gasLimit -= mc.gasLimit sm.gasLimit -= mc.gasLimit
} else if mc.sigType == crypto.SigTypeSecp256k1 { } else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated {
if sm.secpLimit < l { if sm.secpLimit < l {
return false return false
} }
@ -123,7 +123,7 @@ func (sm *selectedMessages) tryToAddWithDeps(mc *msgChain, mp *MessagePool, base
if mc.sigType == crypto.SigTypeBLS { if mc.sigType == crypto.SigTypeBLS {
smMsgLimit = sm.blsLimit smMsgLimit = sm.blsLimit
} else if mc.sigType == crypto.SigTypeSecp256k1 { } else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated {
smMsgLimit = sm.secpLimit smMsgLimit = sm.secpLimit
} else { } else {
return false return false
@ -174,7 +174,7 @@ func (sm *selectedMessages) tryToAddWithDeps(mc *msgChain, mp *MessagePool, base
if mc.sigType == crypto.SigTypeBLS { if mc.sigType == crypto.SigTypeBLS {
sm.blsLimit -= chainMsgLimit sm.blsLimit -= chainMsgLimit
} else if mc.sigType == crypto.SigTypeSecp256k1 { } else if mc.sigType == crypto.SigTypeSecp256k1 || mc.sigType == crypto.SigTypeDelegated {
sm.secpLimit -= chainMsgLimit sm.secpLimit -= chainMsgLimit
} }
@ -187,7 +187,7 @@ func (sm *selectedMessages) trimChain(mc *msgChain, mp *MessagePool, baseFee typ
if msgLimit > sm.blsLimit { if msgLimit > sm.blsLimit {
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 { if msgLimit > sm.secpLimit {
msgLimit = sm.secpLimit msgLimit = sm.secpLimit
} }

View File

@ -31,6 +31,7 @@ import (
"github.com/filecoin-project/lotus/chain/types/mock" "github.com/filecoin-project/lotus/chain/types/mock"
"github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/chain/wallet"
_ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "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/lib/sigs/secp"
) )

53
chain/signatures.go Normal file
View 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
}
}

View File

@ -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 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) { 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 return nil, err
} }
worker, err := sm.ResolveToKeyAddress(ctx, info.Worker, ts) worker, err := sm.ResolveToDeterministicAddress(ctx, info.Worker, ts)
if err != nil { if err != nil {
return nil, xerrors.Errorf("resolving worker address: %w", err) return nil, xerrors.Errorf("resolving worker address: %w", err)
} }

View File

@ -143,6 +143,7 @@ func (sm *StateManager) callInternal(ctx context.Context, msg *types.Message, pr
vmopt := &vm.VMOpts{ vmopt := &vm.VMOpts{
StateBase: stateCid, StateBase: stateCid,
Epoch: vmHeight, Epoch: vmHeight,
Timestamp: ts.MinTimestamp(),
Rand: rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon, nvGetter), Rand: rand.NewStateRand(sm.cs, ts.Cids(), sm.beacon, nvGetter),
Bstore: buffStore, Bstore: buffStore,
Actors: sm.tsExec.NewActorRegistry(), Actors: sm.tsExec.NewActorRegistry(),
@ -199,7 +200,7 @@ func (sm *StateManager) callInternal(ctx context.Context, msg *types.Message, pr
var ret *vm.ApplyRet var ret *vm.ApplyRet
var gasInfo api.MsgGasCost var gasInfo api.MsgGasCost
if checkGas { if checkGas {
fromKey, err := sm.ResolveToKeyAddress(ctx, msg.From, ts) fromKey, err := sm.ResolveToDeterministicAddress(ctx, msg.From, ts)
if err != nil { if err != nil {
return nil, xerrors.Errorf("could not resolve key: %w", err) 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), 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) ret, err = vmi.ApplyMessage(ctx, msgApply)

View File

@ -48,7 +48,7 @@ func (s *RPCStateManager) LookupID(ctx context.Context, addr address.Address, ts
return s.gapi.StateLookupID(ctx, addr, ts.Key()) 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()) return s.gapi.StateAccountKey(ctx, addr, ts.Key())
} }

View File

@ -42,7 +42,7 @@ type StateManagerAPI interface {
GetPaychState(ctx context.Context, addr address.Address, ts *types.TipSet) (*types.Actor, paych.State, error) 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) 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) 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 { type versionSpec struct {
@ -207,11 +207,11 @@ func (sm *StateManager) Beacon() beacon.Schedule {
return sm.beacon 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. // 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() { switch addr.Protocol() {
case address.BLS, address.SECP256K1: case address.BLS, address.SECP256K1, address.Delegated:
return addr, nil return addr, nil
case address.Actor: case address.Actor:
return address.Undef, xerrors.New("cannot resolve actor address to key address") 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) 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 { if err == nil {
return resolved, 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 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. // 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() { switch addr.Protocol() {
case address.BLS, address.SECP256K1: case address.BLS, address.SECP256K1, address.Delegated:
return addr, nil return addr, nil
case address.Actor: case address.Actor:
return address.Undef, xerrors.New("cannot resolve actor address to key address") 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 { if err == nil {
return resolved, 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) { 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 { if err != nil {
return pubk, xerrors.Errorf("failed to resolve address to key address: %w", err) return pubk, xerrors.Errorf("failed to resolve address to key address: %w", err)
} }

View File

@ -2,6 +2,7 @@ package stmgr
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"reflect" "reflect"
@ -27,6 +28,8 @@ import (
"github.com/filecoin-project/lotus/node/modules/dtypes" "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) { 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) act, err := sm.LoadActor(ctx, to, ts)
if err != nil { 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] m, found := sm.tsExec.NewActorRegistry().Methods[act.Code][method]
if !found { 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 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) { func GetParamType(ar *vm.ActorRegistry, actCode cid.Cid, method abi.MethodNum) (cbg.CBORUnmarshaler, error) {
m, found := ar.Methods[actCode][method] m, found := ar.Methods[actCode][method]
if !found { 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 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{ vmopt := &vm.VMOpts{
StateBase: base, StateBase: base,
Epoch: height, Epoch: height,
Timestamp: ts.MinTimestamp(),
Rand: r, Rand: r,
Bstore: sm.cs.StateBlockstore(), Bstore: sm.cs.StateBlockstore(),
Actors: sm.tsExec.NewActorRegistry(), Actors: sm.tsExec.NewActorRegistry(),

View File

@ -1,6 +1,7 @@
package store package store
import ( import (
"bytes"
"context" "context"
"encoding/json" "encoding/json"
"errors" "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 { func (cs *ChainStore) PutTipSet(ctx context.Context, ts *types.TipSet) error {
for _, b := range ts.Blocks() { if err := cs.PersistTipset(ctx, ts); err != nil {
if err := cs.PersistBlockHeaders(ctx, b); err != nil { return xerrors.Errorf("failed to persist tipset: %w", err)
return err
}
} }
expanded, err := cs.expandTipset(ctx, ts.Blocks()[0]) 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 { if err := cs.writeHead(ctx, ts); err != nil {
log.Errorf("failed to write chain head: %s", err) log.Errorf("failed to write chain head: %s", err)
return nil return err
} }
return nil return nil
@ -958,7 +957,24 @@ func (cs *ChainStore) AddToTipSetTracker(ctx context.Context, b *types.BlockHead
return nil 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)) sbs := make([]block.Block, len(b))
for i, header := range b { for i, header := range b {
@ -1026,23 +1042,6 @@ func (cs *ChainStore) expandTipset(ctx context.Context, b *types.BlockHeader) (*
return types.NewTipSet(all) 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) { func (cs *ChainStore) GetGenesis(ctx context.Context) (*types.BlockHeader, error) {
data, err := cs.metadataDs.Get(ctx, dstore.NewKey("0")) data, err := cs.metadataDs.Get(ctx, dstore.NewKey("0"))
if err != nil { if err != nil {
@ -1165,6 +1164,24 @@ func (cs *ChainStore) GetTipsetByHeight(ctx context.Context, h abi.ChainEpoch, t
return cs.LoadTipSet(ctx, lbts.Parents()) 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 func (cs *ChainStore) Weight(ctx context.Context, hts *types.TipSet) (types.BigInt, error) { // todo remove
return cs.weight(ctx, cs.StateBlockstore(), hts) return cs.weight(ctx, cs.StateBlockstore(), hts)
} }

View File

@ -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 // TODO: IMPORTANT(GARBAGE) this needs to be put in the 'temporary' side of
// the blockstore // 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) log.Warn("failed to persist incoming block header: ", err)
return false return false
} }
@ -1145,7 +1145,7 @@ func persistMessages(ctx context.Context, bs bstore.Blockstore, bst *exchange.Co
} }
} }
for _, m := range bst.Secpk { 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) return xerrors.Errorf("unknown signature type on message %s: %q", m.Cid(), m.Signature.Type)
} }
//log.Infof("putting secp256k1 message: %s", m.Cid()) //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) ss.SetStage(api.StagePersistHeaders)
toPersist := make([]*types.BlockHeader, 0, len(headers)*int(build.BlocksPerEpoch))
for _, ts := range headers { for _, ts := range headers {
toPersist = append(toPersist, ts.Blocks()...) if err := syncer.store.PersistTipset(ctx, ts); err != nil {
} err = xerrors.Errorf("failed to persist synced tipset to the chainstore: %w", err)
if err := syncer.store.PersistBlockHeaders(ctx, toPersist...); err != nil {
err = xerrors.Errorf("failed to persist synced blocks to the chainstore: %w", err)
ss.Error(err) ss.Error(err)
return err return err
} }
toPersist = nil }
ss.SetStage(api.StageMessages) ss.SetStage(api.StageMessages)

View File

@ -306,13 +306,13 @@ func (tu *syncTestUtil) addSourceNode(gen int) {
require.NoError(tu.t, err) require.NoError(tu.t, err)
tu.t.Cleanup(func() { _ = stop(context.Background()) }) tu.t.Cleanup(func() { _ = stop(context.Background()) })
lastTs := blocks[len(blocks)-1].Blocks lastTs := blocks[len(blocks)-1]
for _, lastB := range lastTs {
cs := out.(*impl.FullNodeAPI).ChainAPI.Chain cs := out.(*impl.FullNodeAPI).ChainAPI.Chain
for _, lastB := range lastTs.Blocks {
require.NoError(tu.t, cs.AddToTipSetTracker(context.Background(), lastB.Header)) 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.genesis = genesis
tu.blocks = blocks tu.blocks = blocks

View File

@ -26,7 +26,7 @@ type ActorV5 struct {
Head cid.Cid Head cid.Cid
Nonce uint64 Nonce uint64
Balance BigInt Balance BigInt
// Predictable Address // Deterministic Address.
Address *address.Address Address *address.Address
} }

View File

@ -15,7 +15,6 @@ import (
address "github.com/filecoin-project/go-address" address "github.com/filecoin-project/go-address"
abi "github.com/filecoin-project/go-state-types/abi" abi "github.com/filecoin-project/go-state-types/abi"
crypto "github.com/filecoin-project/go-state-types/crypto" 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" proof "github.com/filecoin-project/go-state-types/proof"
) )
@ -1289,154 +1288,6 @@ func (t *ActorV5) UnmarshalCBOR(r io.Reader) (err error) {
return nil 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} var lengthBufBlockMsg = []byte{131}
func (t *BlockMsg) MarshalCBOR(w io.Writer) error { func (t *BlockMsg) MarshalCBOR(w io.Writer) error {
@ -1986,3 +1837,224 @@ func (t *StateInfo0) UnmarshalCBOR(r io.Reader) (err error) {
return nil 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
}

View 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
}

File diff suppressed because one or more lines are too long

View 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, &params); 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
}

View 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
View 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
}

View 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
View 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
)

View File

@ -39,6 +39,8 @@ func (kt *KeyType) UnmarshalJSON(bb []byte) error {
*kt = KTBLS *kt = KTBLS
case crypto.SigTypeSecp256k1: case crypto.SigTypeSecp256k1:
*kt = KTSecp256k1 *kt = KTSecp256k1
case crypto.SigTypeDelegated:
*kt = KTDelegated
default: default:
return fmt.Errorf("unknown sigtype: %d", bst) return fmt.Errorf("unknown sigtype: %d", bst)
} }
@ -51,6 +53,7 @@ const (
KTBLS KeyType = "bls" KTBLS KeyType = "bls"
KTSecp256k1 KeyType = "secp256k1" KTSecp256k1 KeyType = "secp256k1"
KTSecp256k1Ledger KeyType = "secp256k1-ledger" KTSecp256k1Ledger KeyType = "secp256k1-ledger"
KTDelegated KeyType = "delegated"
) )
// KeyInfo is used for storing keys in KeyStore // KeyInfo is used for storing keys in KeyStore

View File

@ -3,15 +3,59 @@ package types
import ( import (
"bytes" "bytes"
"github.com/ipfs/go-cid"
"github.com/filecoin-project/go-state-types/exitcode" "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 { type MessageReceipt struct {
version MessageReceiptVersion
ExitCode exitcode.ExitCode ExitCode exitcode.ExitCode
Return []byte Return []byte
GasUsed int64 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 { 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))
} }

View 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
}

View 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)
}

View File

@ -196,8 +196,23 @@ func (ts *TipSet) MinTicket() *Ticket {
} }
func (ts *TipSet) MinTimestamp() uint64 { func (ts *TipSet) MinTimestamp() uint64 {
minTs := ts.Blocks()[0].Timestamp if ts == nil {
for _, bh := range ts.Blocks()[1:] { 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 { if bh.Timestamp < minTs {
minTs = bh.Timestamp minTs = bh.Timestamp
} }

View File

@ -24,6 +24,8 @@ type StateTree interface {
SetActor(addr address.Address, act *Actor) error SetActor(addr address.Address, act *Actor) error
// GetActor returns the actor from any type of `addr` provided. // GetActor returns the actor from any type of `addr` provided.
GetActor(addr address.Address) (*Actor, error) GetActor(addr address.Address) (*Actor, error)
Version() StateTreeVersion
} }
type storageWrapper struct { type storageWrapper struct {

View File

@ -19,6 +19,7 @@ import (
"github.com/filecoin-project/lotus/chain/vectors" "github.com/filecoin-project/lotus/chain/vectors"
"github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/chain/wallet"
_ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "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/lib/sigs/secp"
) )

View File

@ -24,6 +24,7 @@ import (
actorstypes "github.com/filecoin-project/go-state-types/actors" actorstypes "github.com/filecoin-project/go-state-types/actors"
"github.com/filecoin-project/go-state-types/exitcode" "github.com/filecoin-project/go-state-types/exitcode"
"github.com/filecoin-project/go-state-types/manifest" "github.com/filecoin-project/go-state-types/manifest"
"github.com/filecoin-project/go-state-types/network"
"github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/blockstore"
"github.com/filecoin-project/lotus/build" "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 return address.Undef, gasUsed, err
} }
raddr, err := ResolveToKeyAddr(stateTree, cstWithGas, info.Worker) raddr, err := ResolveToDeterministicAddr(stateTree, cstWithGas, info.Worker)
if err != nil { if err != nil {
return address.Undef, gasUsed, err return address.Undef, gasUsed, err
} }
@ -285,6 +286,7 @@ func (x *FvmExtern) workerKeyAtLookback(ctx context.Context, minerId address.Add
type FVM struct { type FVM struct {
fvm *ffi.FVM fvm *ffi.FVM
nv network.Version
} }
func defaultFVMOpts(ctx context.Context, opts *VMOpts) (*ffi.FVMOpts, error) { 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,
}, },
Epoch: opts.Epoch, Epoch: opts.Epoch,
Timestamp: opts.Timestamp,
ChainID: build.Eip155ChainId,
BaseFee: opts.BaseFee, BaseFee: opts.BaseFee,
BaseCircSupply: circToReport, BaseCircSupply: circToReport,
NetworkVersion: opts.NetworkVersion, NetworkVersion: opts.NetworkVersion,
StateBase: opts.StateBase, StateBase: opts.StateBase,
Tracing: opts.Tracing || EnableDetailedTracing, Tracing: opts.Tracing || EnableDetailedTracing,
Debug: build.ActorDebugging,
}, nil }, nil
} }
@ -324,20 +329,6 @@ func NewFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
return nil, xerrors.Errorf("creating fvm opts: %w", err) 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) fvm, err := ffi.CreateFVM(fvmOpts)
if err != nil { if err != nil {
@ -346,6 +337,7 @@ func NewFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
return &FVM{ return &FVM{
fvm: fvm, fvm: fvm,
nv: opts.NetworkVersion,
}, nil }, nil
} }
@ -448,6 +440,7 @@ func NewDebugFVM(ctx context.Context, opts *VMOpts) (*FVM, error) {
return &FVM{ return &FVM{
fvm: fvm, fvm: fvm,
nv: opts.NetworkVersion,
}, nil }, nil
} }
@ -466,10 +459,12 @@ func (vm *FVM) ApplyMessage(ctx context.Context, cmsg types.ChainMsg) (*ApplyRet
} }
duration := time.Since(start) duration := time.Since(start)
receipt := types.MessageReceipt{
Return: ret.Return, var receipt types.MessageReceipt
ExitCode: exitcode.ExitCode(ret.ExitCode), if vm.nv >= network.Version18 {
GasUsed: ret.GasUsed, 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 var aerr aerrors.ActorError
@ -530,10 +525,12 @@ func (vm *FVM) ApplyImplicitMessage(ctx context.Context, cmsg *types.Message) (*
} }
duration := time.Since(start) duration := time.Since(start)
receipt := types.MessageReceipt{
Return: ret.Return, var receipt types.MessageReceipt
ExitCode: exitcode.ExitCode(ret.ExitCode), if vm.nv >= network.Version18 {
GasUsed: ret.GasUsed, 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 var aerr aerrors.ActorError

View File

@ -111,6 +111,7 @@ var Prices = map[abi.ChainEpoch]Pricelist{
verifySignature: map[crypto.SigType]int64{ verifySignature: map[crypto.SigType]int64{
crypto.SigTypeBLS: 16598605, crypto.SigTypeBLS: 16598605,
crypto.SigTypeSecp256k1: 1637292, crypto.SigTypeSecp256k1: 1637292,
crypto.SigTypeDelegated: 1637292,
}, },
hashingBase: 31355, hashingBase: 31355,

View File

@ -284,16 +284,16 @@ func DecodeParams(b []byte, out interface{}) error {
} }
func DumpActorState(i *ActorRegistry, act *types.Actor, b []byte) (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] actInfo, ok := i.actors[act.Code]
if !ok { if !ok {
return nil, xerrors.Errorf("state type for actor %s not found", act.Code) return nil, xerrors.Errorf("state type for actor %s not found", act.Code)
} }
um := actInfo.vmActor.State() 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 { if err := um.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
return nil, xerrors.Errorf("unmarshaling actor state: %w", err) return nil, xerrors.Errorf("unmarshaling actor state: %w", err)
} }

View File

@ -249,7 +249,7 @@ func (rt *Runtime) GetRandomnessFromBeacon(personalization crypto.DomainSeparati
func (rt *Runtime) NewActorAddress() address.Address { func (rt *Runtime) NewActorAddress() address.Address {
var b bytes.Buffer 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? 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)) panic(aerrors.Fatalf("writing caller address into a buffer: %v", err))
} }

View File

@ -255,7 +255,7 @@ func (ss *syscallShim) workerKeyAtLookback(height abi.ChainEpoch) (address.Addre
return address.Undef, err 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 { func (ss *syscallShim) VerifyPoSt(info proof7.WindowPoStVerifyInfo) error {
@ -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 { func (ss *syscallShim) VerifySignature(sig crypto.Signature, addr address.Address, input []byte) error {
// TODO: in genesis setup, we are currently faking signatures // 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 { if err != nil {
return err return err
} }

View File

@ -45,9 +45,11 @@ var (
gasOnActorExec = newGasCharge("OnActorExec", 0, 0) gasOnActorExec = newGasCharge("OnActorExec", 0, 0)
) )
// ResolveToKeyAddr returns the public key type of address (`BLS`/`SECP256K1`) of an account actor identified by `addr`. // ResolveToDeterministicAddr returns the public key type of address
func ResolveToKeyAddr(state types.StateTree, cst cbor.IpldStore, addr address.Address) (address.Address, error) { // (`BLS`/`SECP256K1`) of an actor identified by `addr`, or its
if addr.Protocol() == address.BLS || addr.Protocol() == address.SECP256K1 { // 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 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) 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) aast, err := account.Load(adt.WrapStore(context.TODO(), cst), act)
if err != nil { if err != nil {
return address.Undef, xerrors.Errorf("failed to get account actor state for %s: %w", addr, err) return address.Undef, xerrors.Errorf("failed to get account actor state for %s: %w", addr, err)
} }
return aast.PubkeyAddress() return aast.PubkeyAddress()
} }
var ( var (
@ -216,6 +225,7 @@ type LegacyVM struct {
type VMOpts struct { type VMOpts struct {
StateBase cid.Cid StateBase cid.Cid
Epoch abi.ChainEpoch Epoch abi.ChainEpoch
Timestamp uint64
Rand Rand Rand Rand
Bstore blockstore.Blockstore Bstore blockstore.Blockstore
Actors *ActorRegistry Actors *ActorRegistry

View File

@ -7,6 +7,7 @@ import (
"github.com/filecoin-project/go-state-types/crypto" "github.com/filecoin-project/go-state-types/crypto"
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/types/ethtypes"
"github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/lib/sigs"
) )
@ -50,6 +51,22 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) {
if err != nil { if err != nil {
return nil, xerrors.Errorf("converting Secp256k1 to address: %w", err) 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: case types.KTBLS:
k.Address, err = address.NewBLSAddress(k.PublicKey) k.Address, err = address.NewBLSAddress(k.PublicKey)
if err != nil { if err != nil {
@ -58,6 +75,7 @@ func NewKey(keyinfo types.KeyInfo) (*Key, error) {
default: default:
return nil, xerrors.Errorf("unsupported key type: %s", k.Type) return nil, xerrors.Errorf("unsupported key type: %s", k.Type)
} }
return k, nil return k, nil
} }
@ -68,6 +86,8 @@ func ActSigType(typ types.KeyType) crypto.SigType {
return crypto.SigTypeBLS return crypto.SigTypeBLS
case types.KTSecp256k1: case types.KTSecp256k1:
return crypto.SigTypeSecp256k1 return crypto.SigTypeSecp256k1
case types.KTDelegated:
return crypto.SigTypeDelegated
default: default:
return crypto.SigTypeUnknown return crypto.SigTypeUnknown
} }

View File

@ -17,6 +17,7 @@ import (
"github.com/filecoin-project/lotus/chain/wallet/key" "github.com/filecoin-project/lotus/chain/wallet/key"
"github.com/filecoin-project/lotus/lib/sigs" "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/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/lib/sigs/secp" // enable secp signatures
) )

View File

@ -81,6 +81,7 @@ var Commands = []*cli.Command{
WithCategory("developer", LogCmd), WithCategory("developer", LogCmd),
WithCategory("developer", WaitApiCmd), WithCategory("developer", WaitApiCmd),
WithCategory("developer", FetchParamCmd), WithCategory("developer", FetchParamCmd),
WithCategory("developer", EvmCmd),
WithCategory("network", NetCmd), WithCategory("network", NetCmd),
WithCategory("network", SyncCmd), WithCategory("network", SyncCmd),
WithCategory("status", StatusCmd), WithCategory("status", StatusCmd),

503
cli/evm.go Normal file
View 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
}

View File

@ -776,6 +776,7 @@ var StateGetActorCmd = &cli.Command{
fmt.Printf("Nonce:\t\t%d\n", a.Nonce) fmt.Printf("Nonce:\t\t%d\n", a.Nonce)
fmt.Printf("Code:\t\t%s (%s)\n", a.Code, strtype) fmt.Printf("Code:\t\t%s (%s)\n", a.Code, strtype)
fmt.Printf("Head:\t\t%s\n", a.Head) fmt.Printf("Head:\t\t%s\n", a.Head)
fmt.Printf("Delegated address:\t\t%s\n", a.Address)
return nil return nil
}, },

View File

@ -41,6 +41,7 @@ import (
"github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/chain/vm"
lcli "github.com/filecoin-project/lotus/cli" lcli "github.com/filecoin-project/lotus/cli"
_ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "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/lib/sigs/secp"
"github.com/filecoin-project/lotus/node/repo" "github.com/filecoin-project/lotus/node/repo"
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper" "github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"

View File

@ -10,6 +10,7 @@ import (
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/chain/wallet"
_ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "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/lib/sigs/secp"
) )

View File

@ -23,6 +23,7 @@ import (
"github.com/filecoin-project/lotus/chain/wallet" "github.com/filecoin-project/lotus/chain/wallet"
"github.com/filecoin-project/lotus/chain/wallet/key" "github.com/filecoin-project/lotus/chain/wallet/key"
_ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "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/lib/sigs/secp"
"github.com/filecoin-project/lotus/node/modules" "github.com/filecoin-project/lotus/node/modules"
"github.com/filecoin-project/lotus/node/modules/lp2p" "github.com/filecoin-project/lotus/node/modules/lp2p"

View File

@ -4,10 +4,10 @@ import (
"context" "context"
"fmt" "fmt"
"io" "io"
"strconv"
"time" "time"
"github.com/ipfs/go-cid" "github.com/ipfs/go-cid"
logging "github.com/ipfs/go-log/v2"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
cbg "github.com/whyrusleeping/cbor-gen" cbg "github.com/whyrusleeping/cbor-gen"
"golang.org/x/xerrors" "golang.org/x/xerrors"
@ -25,6 +25,8 @@ import (
adt9 "github.com/filecoin-project/go-state-types/builtin/v9/util/adt" adt9 "github.com/filecoin-project/go-state-types/builtin/v9/util/adt"
verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg" verifreg9 "github.com/filecoin-project/go-state-types/builtin/v9/verifreg"
"github.com/filecoin-project/go-state-types/manifest" "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/specs-actors/v7/actors/migration/nv15"
"github.com/filecoin-project/lotus/blockstore" "github.com/filecoin-project/lotus/blockstore"
@ -47,9 +49,9 @@ import (
) )
var migrationsCmd = &cli.Command{ var migrationsCmd = &cli.Command{
Name: "migrate-nv17", Name: "migrate-state",
Description: "Run the nv17 migration", Description: "Run a network upgrade migration",
ArgsUsage: "[block to look back from]", ArgsUsage: "[new network version, block to look back from]",
Flags: []cli.Flag{ Flags: []cli.Flag{
&cli.StringFlag{ &cli.StringFlag{
Name: "repo", Name: "repo",
@ -65,16 +67,21 @@ var migrationsCmd = &cli.Command{
Action: func(cctx *cli.Context) error { Action: func(cctx *cli.Context) error {
ctx := context.TODO() 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 { if err != nil {
return err return err
} }
if cctx.NArg() != 1 { blkCid, err := cid.Decode(cctx.Args().Get(1))
return lcli.IncorrectNumArgs(cctx)
}
blkCid, err := cid.Decode(cctx.Args().First())
if err != nil { if err != nil {
return fmt.Errorf("failed to parse input: %w", err) return fmt.Errorf("failed to parse input: %w", err)
} }
@ -129,7 +136,7 @@ var migrationsCmd = &cli.Command{
startTime := time.Now() 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 { if err != nil {
return err return err
} }
@ -142,7 +149,7 @@ var migrationsCmd = &cli.Command{
fmt.Println("completed round actual (without cache), took ", uncachedMigrationTime) fmt.Println("completed round actual (without cache), took ", uncachedMigrationTime)
if !cctx.IsSet("skip-pre-migration") { if !cctx.IsSet("skip-pre-migration") {
cache := nv15.NewMemMigrationCache() cache := mutil.NewMemMigrationCache()
ts1, err := cs.GetTipsetByHeight(ctx, blk.Height-240, migrationTs, false) ts1, err := cs.GetTipsetByHeight(ctx, blk.Height-240, migrationTs, false)
if err != nil { if err != nil {
@ -151,7 +158,7 @@ var migrationsCmd = &cli.Command{
startTime = time.Now() 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 { if err != nil {
return err return err
} }
@ -165,7 +172,7 @@ var migrationsCmd = &cli.Command{
startTime = time.Now() 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 { if err != nil {
return err return err
} }
@ -174,7 +181,7 @@ var migrationsCmd = &cli.Command{
startTime = time.Now() 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 { if err != nil {
return err return err
} }
@ -191,7 +198,10 @@ var migrationsCmd = &cli.Command{
} }
if cctx.Bool("check-invariants") { 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 { if err != nil {
return err 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) actorStore := store.ActorStore(ctx, bs)
startTime := time.Now() startTime := time.Now()

View File

@ -74,14 +74,17 @@ func (sim *Simulation) makeTipSet(ctx context.Context, messages []*types.Message
Timestamp: uts, Timestamp: uts,
ElectionProof: &types.ElectionProof{WinCount: 1}, 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) newTipSet, err := types.NewTipSet(blks)
if err != nil { if err != nil {
return nil, xerrors.Errorf("failed to create new tipset: %w", err) 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() now := time.Now()
_, _, err = sim.StateManager.TipSetState(ctx, newTipSet) _, _, err = sim.StateManager.TipSetState(ctx, newTipSet)
if err != nil { if err != nil {

View File

@ -28,6 +28,7 @@ import (
"github.com/filecoin-project/lotus/chain/vm" "github.com/filecoin-project/lotus/chain/vm"
"github.com/filecoin-project/lotus/conformance/chaos" "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/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/lib/sigs/secp" // enable secp signatures
"github.com/filecoin-project/lotus/storage/sealer/ffiwrapper" "github.com/filecoin-project/lotus/storage/sealer/ffiwrapper"
) )

View File

@ -464,7 +464,9 @@ Inputs:
{ {
"SealProof": 8, "SealProof": 8,
"SectorNumber": 9, "SectorNumber": 9,
"SectorKey": null, "SectorKey": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"SealedCID": { "SealedCID": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
} }
@ -1279,8 +1281,12 @@ Response:
"ProposalCid": { "ProposalCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"AddFundsCid": null, "AddFundsCid": {
"PublishCid": null, "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PublishCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"Miner": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", "Miner": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
"Client": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", "Client": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
"State": 42, "State": 42,
@ -1295,7 +1301,9 @@ Response:
"Root": { "Root": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"PieceCid": null, "PieceCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PieceSize": 1024, "PieceSize": 1024,
"RawBlockSize": 42 "RawBlockSize": 42
}, },
@ -1457,8 +1465,12 @@ Response:
"ProposalCid": { "ProposalCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"AddFundsCid": null, "AddFundsCid": {
"PublishCid": null, "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PublishCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"Miner": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", "Miner": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
"Client": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", "Client": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
"State": 42, "State": 42,
@ -1473,7 +1485,9 @@ Response:
"Root": { "Root": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"PieceCid": null, "PieceCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PieceSize": 1024, "PieceSize": 1024,
"RawBlockSize": 42 "RawBlockSize": 42
}, },
@ -1509,7 +1523,9 @@ Response:
"Selector": { "Selector": {
"Raw": "Ynl0ZSBhcnJheQ==" "Raw": "Ynl0ZSBhcnJheQ=="
}, },
"PieceCID": null, "PieceCID": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PricePerByte": "0", "PricePerByte": "0",
"PaymentInterval": 42, "PaymentInterval": 42,
"PaymentIntervalIncrease": 42, "PaymentIntervalIncrease": 42,
@ -2908,7 +2924,9 @@ Inputs:
1024, 1024,
{}, {},
{ {
"PublishCid": null, "PublishCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"DealID": 5432, "DealID": 5432,
"DealProposal": { "DealProposal": {
"PieceCID": { "PieceCID": {
@ -2962,7 +2980,9 @@ Response:
"FailedSectors": { "FailedSectors": {
"123": "can't acquire read lock" "123": "can't acquire read lock"
}, },
"Msg": null, "Msg": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"Error": "string value" "Error": "string value"
} }
] ]
@ -3156,7 +3176,9 @@ Response:
123, 123,
124 124
], ],
"Msg": null, "Msg": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"Error": "string value" "Error": "string value"
} }
] ]
@ -3204,7 +3226,9 @@ Inputs:
} }
}, },
"DealInfo": { "DealInfo": {
"PublishCid": null, "PublishCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"DealID": 5432, "DealID": 5432,
"DealProposal": { "DealProposal": {
"PieceCID": { "PieceCID": {
@ -3232,8 +3256,12 @@ Inputs:
"TicketValue": "Bw==", "TicketValue": "Bw==",
"TicketEpoch": 10101, "TicketEpoch": 10101,
"PreCommit1Out": "Bw==", "PreCommit1Out": "Bw==",
"CommD": null, "CommD": {
"CommR": null, "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"CommR": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PreCommitInfo": { "PreCommitInfo": {
"SealProof": 8, "SealProof": 8,
"SectorNumber": 9, "SectorNumber": 9,
@ -3245,10 +3273,14 @@ Inputs:
5432 5432
], ],
"Expiration": 10101, "Expiration": 10101,
"UnsealedCid": null "UnsealedCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"PreCommitDeposit": "0", "PreCommitDeposit": "0",
"PreCommitMessage": null, "PreCommitMessage": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PreCommitTipSet": [ "PreCommitTipSet": [
{ {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
@ -3260,7 +3292,9 @@ Inputs:
"SeedValue": "Bw==", "SeedValue": "Bw==",
"SeedEpoch": 10101, "SeedEpoch": 10101,
"CommitProof": "Ynl0ZSBhcnJheQ==", "CommitProof": "Ynl0ZSBhcnJheQ==",
"CommitMessage": null, "CommitMessage": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"Log": [ "Log": [
{ {
"Kind": "string value", "Kind": "string value",
@ -3396,7 +3430,12 @@ Perms: admin
Inputs: `null` Inputs: `null`
Response: `null` Response:
```json
{
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
```
### SectorTerminatePending ### SectorTerminatePending
SectorTerminatePending returns a list of pending sector terminations to be sent in the next batch message SectorTerminatePending returns a list of pending sector terminations to be sent in the next batch message
@ -3497,8 +3536,12 @@ Response:
{ {
"SectorID": 9, "SectorID": 9,
"State": "Proving", "State": "Proving",
"CommD": null, "CommD": {
"CommR": null, "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"CommR": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"Proof": "Ynl0ZSBhcnJheQ==", "Proof": "Ynl0ZSBhcnJheQ==",
"Deals": [ "Deals": [
5432 5432
@ -3512,7 +3555,9 @@ Response:
} }
}, },
"DealInfo": { "DealInfo": {
"PublishCid": null, "PublishCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"DealID": 5432, "DealID": 5432,
"DealProposal": { "DealProposal": {
"PieceCID": { "PieceCID": {
@ -3545,11 +3590,17 @@ Response:
"Value": "Bw==", "Value": "Bw==",
"Epoch": 10101 "Epoch": 10101
}, },
"PreCommitMsg": null, "PreCommitMsg": {
"CommitMsg": null, "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"CommitMsg": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"Retries": 42, "Retries": 42,
"ToUpgrade": true, "ToUpgrade": true,
"ReplicaUpdateMessage": null, "ReplicaUpdateMessage": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"LastErr": "string value", "LastErr": "string value",
"Log": [ "Log": [
{ {
@ -3603,7 +3654,9 @@ Inputs:
1040384, 1040384,
1024, 1024,
"Bw==", "Bw==",
null {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
] ]
``` ```

View File

@ -754,7 +754,10 @@ Response:
{ {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
} }
] ]
``` ```
@ -1247,7 +1250,9 @@ Inputs:
{ {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
null {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
] ]
``` ```
@ -1259,7 +1264,9 @@ Response:
"Root": { "Root": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"Piece": null, "Piece": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"Size": 42, "Size": 42,
"MinPrice": "0", "MinPrice": "0",
"UnsealPrice": "0", "UnsealPrice": "0",
@ -1270,7 +1277,9 @@ Response:
"MinerPeer": { "MinerPeer": {
"Address": "f01234", "Address": "f01234",
"ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
"PieceCID": null "PieceCID": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
} }
} }
] ]
@ -1341,7 +1350,9 @@ Response:
"Root": { "Root": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"PieceCid": null, "PieceCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PieceSize": 1024, "PieceSize": 1024,
"RawBlockSize": 42 "RawBlockSize": 42
}, },
@ -1445,7 +1456,9 @@ Response:
"Root": { "Root": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"PieceCid": null, "PieceCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PieceSize": 1024, "PieceSize": 1024,
"RawBlockSize": 42 "RawBlockSize": 42
}, },
@ -1510,7 +1523,9 @@ Response:
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"ID": 5, "ID": 5,
"PieceCID": null, "PieceCID": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PricePerByte": "0", "PricePerByte": "0",
"UnsealPrice": "0", "UnsealPrice": "0",
"Status": 0, "Status": 0,
@ -1683,7 +1698,9 @@ Response:
"Root": { "Root": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"PieceCid": null, "PieceCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PieceSize": 1024, "PieceSize": 1024,
"RawBlockSize": 42 "RawBlockSize": 42
}, },
@ -1748,7 +1765,9 @@ Response:
{ {
"Key": 50, "Key": 50,
"Err": "string value", "Err": "string value",
"Root": null, "Root": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"Source": "string value", "Source": "string value",
"FilePath": "string value", "FilePath": "string value",
"CARPath": "string value" "CARPath": "string value"
@ -1773,7 +1792,9 @@ Response:
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"ID": 5, "ID": 5,
"PieceCID": null, "PieceCID": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PricePerByte": "0", "PricePerByte": "0",
"UnsealPrice": "0", "UnsealPrice": "0",
"Status": 0, "Status": 0,
@ -1834,7 +1855,9 @@ Inputs:
{ {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
null {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
] ]
``` ```
@ -1845,7 +1868,9 @@ Response:
"Root": { "Root": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"Piece": null, "Piece": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"Size": 42, "Size": 42,
"MinPrice": "0", "MinPrice": "0",
"UnsealPrice": "0", "UnsealPrice": "0",
@ -1856,7 +1881,9 @@ Response:
"MinerPeer": { "MinerPeer": {
"Address": "f01234", "Address": "f01234",
"ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
"PieceCID": null "PieceCID": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
} }
} }
``` ```
@ -1933,7 +1960,9 @@ Inputs:
"Root": { "Root": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"Piece": null, "Piece": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"DatamodelPathSelector": "Links/21/Hash/Links/42/Hash", "DatamodelPathSelector": "Links/21/Hash/Links/42/Hash",
"Size": 42, "Size": 42,
"FromLocalCAR": "string value", "FromLocalCAR": "string value",
@ -1946,7 +1975,9 @@ Inputs:
"MinerPeer": { "MinerPeer": {
"Address": "f01234", "Address": "f01234",
"ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
"PieceCID": null "PieceCID": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
} }
}, },
{ {
@ -1988,7 +2019,9 @@ Inputs:
"Root": { "Root": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"Piece": null, "Piece": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"DatamodelPathSelector": "Links/21/Hash/Links/42/Hash", "DatamodelPathSelector": "Links/21/Hash/Links/42/Hash",
"Size": 42, "Size": 42,
"FromLocalCAR": "string value", "FromLocalCAR": "string value",
@ -2001,7 +2034,9 @@ Inputs:
"MinerPeer": { "MinerPeer": {
"Address": "f01234", "Address": "f01234",
"ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf", "ID": "12D3KooWGzxzKZYveHXtpG6AsrUJBcWxHBFS2HsEoGTxrMLvKXtf",
"PieceCID": null "PieceCID": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
} }
}, },
{ {
@ -2037,7 +2072,9 @@ Inputs:
"Root": { "Root": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"PieceCid": null, "PieceCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PieceSize": 1024, "PieceSize": 1024,
"RawBlockSize": 42 "RawBlockSize": 42
}, },
@ -2053,7 +2090,12 @@ Inputs:
] ]
``` ```
Response: `null` Response:
```json
{
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
```
### ClientStatelessDeal ### ClientStatelessDeal
ClientStatelessDeal fire-and-forget-proposes an offline deal to a miner without subsequent tracking. ClientStatelessDeal fire-and-forget-proposes an offline deal to a miner without subsequent tracking.
@ -2070,7 +2112,9 @@ Inputs:
"Root": { "Root": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}, },
"PieceCid": null, "PieceCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"PieceSize": 1024, "PieceSize": 1024,
"RawBlockSize": 42 "RawBlockSize": 42
}, },
@ -2086,7 +2130,12 @@ Inputs:
] ]
``` ```
Response: `null` Response:
```json
{
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
```
## Create ## Create
@ -2613,7 +2662,9 @@ Response:
{ {
"SealProof": 8, "SealProof": 8,
"SectorNumber": 9, "SectorNumber": 9,
"SectorKey": null, "SectorKey": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"SealedCID": { "SealedCID": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4" "/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
} }
@ -4156,7 +4207,9 @@ Response:
"PendingAmt": "0", "PendingAmt": "0",
"NonReservedAmt": "0", "NonReservedAmt": "0",
"PendingAvailableAmt": "0", "PendingAvailableAmt": "0",
"PendingWaitSentinel": null, "PendingWaitSentinel": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"QueuedAmt": "0", "QueuedAmt": "0",
"VoucherReedeemedAmt": "0" "VoucherReedeemedAmt": "0"
} }
@ -4185,7 +4238,9 @@ Response:
"PendingAmt": "0", "PendingAmt": "0",
"NonReservedAmt": "0", "NonReservedAmt": "0",
"PendingAvailableAmt": "0", "PendingAvailableAmt": "0",
"PendingWaitSentinel": null, "PendingWaitSentinel": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"QueuedAmt": "0", "QueuedAmt": "0",
"VoucherReedeemedAmt": "0" "VoucherReedeemedAmt": "0"
} }
@ -4792,7 +4847,10 @@ Response:
"MsgRct": { "MsgRct": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"GasCost": { "GasCost": {
"Message": { "Message": {
@ -4825,7 +4883,10 @@ Response:
"MsgRct": { "MsgRct": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"Error": "string value", "Error": "string value",
"Duration": 60000000000, "Duration": 60000000000,
@ -4869,7 +4930,10 @@ Response:
"MsgRct": { "MsgRct": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"Error": "string value", "Error": "string value",
"Duration": 60000000000, "Duration": 60000000000,
@ -5059,7 +5123,10 @@ Response:
"MsgRct": { "MsgRct": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"GasCost": { "GasCost": {
"Message": { "Message": {
@ -5092,7 +5159,10 @@ Response:
"MsgRct": { "MsgRct": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"Error": "string value", "Error": "string value",
"Duration": 60000000000, "Duration": 60000000000,
@ -5136,7 +5206,10 @@ Response:
"MsgRct": { "MsgRct": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"Error": "string value", "Error": "string value",
"Duration": 60000000000, "Duration": 60000000000,
@ -5460,7 +5533,8 @@ Response:
"UpgradeChocolateHeight": 10101, "UpgradeChocolateHeight": 10101,
"UpgradeOhSnapHeight": 10101, "UpgradeOhSnapHeight": 10101,
"UpgradeSkyrHeight": 10101, "UpgradeSkyrHeight": 10101,
"UpgradeSharkHeight": 10101 "UpgradeSharkHeight": 10101,
"UpgradeHyggeHeight": 10101
} }
} }
``` ```
@ -5551,7 +5625,10 @@ Response:
{ {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
} }
``` ```
@ -5864,7 +5941,9 @@ Response:
"ExpectedStoragePledge": "0", "ExpectedStoragePledge": "0",
"ReplacedSectorAge": 10101, "ReplacedSectorAge": 10101,
"ReplacedDayReward": "0", "ReplacedDayReward": "0",
"SectorKeyCID": null, "SectorKeyCID": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"SimpleQAPower": true "SimpleQAPower": true
} }
] ]
@ -6032,7 +6111,9 @@ Inputs:
5432 5432
], ],
"Expiration": 10101, "Expiration": 10101,
"UnsealedCid": null "UnsealedCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
[ [
{ {
@ -6154,7 +6235,9 @@ Inputs:
5432 5432
], ],
"Expiration": 10101, "Expiration": 10101,
"UnsealedCid": null "UnsealedCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
[ [
{ {
@ -6337,7 +6420,9 @@ Response:
"ExpectedStoragePledge": "0", "ExpectedStoragePledge": "0",
"ReplacedSectorAge": 10101, "ReplacedSectorAge": 10101,
"ReplacedDayReward": "0", "ReplacedDayReward": "0",
"SectorKeyCID": null, "SectorKeyCID": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"SimpleQAPower": true "SimpleQAPower": true
} }
] ]
@ -6470,7 +6555,10 @@ Response:
"MsgRct": { "MsgRct": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"GasCost": { "GasCost": {
"Message": { "Message": {
@ -6503,7 +6591,10 @@ Response:
"MsgRct": { "MsgRct": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"Error": "string value", "Error": "string value",
"Duration": 60000000000, "Duration": 60000000000,
@ -6547,7 +6638,10 @@ Response:
"MsgRct": { "MsgRct": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"Error": "string value", "Error": "string value",
"Duration": 60000000000, "Duration": 60000000000,
@ -6618,7 +6712,10 @@ Response:
"Receipt": { "Receipt": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"ReturnDec": {}, "ReturnDec": {},
"TipSet": [ "TipSet": [
@ -6672,7 +6769,10 @@ Response:
"Receipt": { "Receipt": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"ReturnDec": {}, "ReturnDec": {},
"TipSet": [ "TipSet": [
@ -6761,7 +6861,9 @@ Response:
"ExpectedStoragePledge": "0", "ExpectedStoragePledge": "0",
"ReplacedSectorAge": 10101, "ReplacedSectorAge": 10101,
"ReplacedDayReward": "0", "ReplacedDayReward": "0",
"SectorKeyCID": null, "SectorKeyCID": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
},
"SimpleQAPower": true "SimpleQAPower": true
} }
``` ```
@ -6832,7 +6934,9 @@ Response:
5432 5432
], ],
"Expiration": 10101, "Expiration": 10101,
"UnsealedCid": null "UnsealedCid": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"PreCommitDeposit": "0", "PreCommitDeposit": "0",
"PreCommitEpoch": 10101 "PreCommitEpoch": 10101
@ -6984,7 +7088,10 @@ Response:
"Receipt": { "Receipt": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"ReturnDec": {}, "ReturnDec": {},
"TipSet": [ "TipSet": [
@ -7041,7 +7148,10 @@ Response:
"Receipt": { "Receipt": {
"ExitCode": 0, "ExitCode": 0,
"Return": "Ynl0ZSBhcnJheQ==", "Return": "Ynl0ZSBhcnJheQ==",
"GasUsed": 9 "GasUsed": 9,
"EventsRoot": {
"/": "bafy2bzacea3wsdh6y3a36tb3skempjoxqpuyompjbmfeyf34fi3uy6uue42v4"
}
}, },
"ReturnDec": {}, "ReturnDec": {},
"TipSet": [ "TipSet": [

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,7 @@ COMMANDS:
log Manage logging log Manage logging
wait-api Wait for lotus api to come online wait-api Wait for lotus api to come online
fetch-params Fetch proving parameters fetch-params Fetch proving parameters
evm Commands related to the Filecoin EVM runtime
NETWORK: NETWORK:
net Manage P2P Network net Manage P2P Network
sync Inspect or interact with the chain syncer 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 ## lotus net
``` ```
NAME: NAME:

View File

@ -293,3 +293,53 @@
#Tracing = false #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

@ -1 +1 @@
Subproject commit 02ebb2d6169131cfe489e1063e896f14982c463d Subproject commit c4adeb4532719acf7b1c182cb98a3cca7b955a14

View File

@ -25,6 +25,7 @@ import (
"github.com/filecoin-project/lotus/chain/types" "github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/lotus/lib/sigs" "github.com/filecoin-project/lotus/lib/sigs"
_ "github.com/filecoin-project/lotus/lib/sigs/bls" _ "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/lib/sigs/secp"
"github.com/filecoin-project/lotus/metrics" "github.com/filecoin-project/lotus/metrics"
"github.com/filecoin-project/lotus/node/impl/full" "github.com/filecoin-project/lotus/node/impl/full"

View File

@ -29,12 +29,14 @@ func main() {
types.MsgMeta{}, types.MsgMeta{},
types.ActorV4{}, types.ActorV4{},
types.ActorV5{}, types.ActorV5{},
types.MessageReceipt{}, // types.MessageReceipt{}, // Custom serde to deal with versioning.
types.BlockMsg{}, types.BlockMsg{},
types.ExpTipSet{}, types.ExpTipSet{},
types.BeaconEntry{}, types.BeaconEntry{},
types.StateRoot{}, types.StateRoot{},
types.StateInfo0{}, types.StateInfo0{},
types.Event{},
types.EventEntry{},
) )
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)

11
go.mod
View File

@ -31,6 +31,7 @@ require (
github.com/filecoin-project/dagstore v0.5.2 github.com/filecoin-project/dagstore v0.5.2
github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200910194244-f640612a1a1f github.com/filecoin-project/filecoin-ffi v0.30.4-0.20200910194244-f640612a1a1f
github.com/filecoin-project/go-address v1.1.0 github.com/filecoin-project/go-address v1.1.0
github.com/filecoin-project/go-amt-ipld/v4 v4.0.0
github.com/filecoin-project/go-bitfield v0.2.4 github.com/filecoin-project/go-bitfield v0.2.4
github.com/filecoin-project/go-cbor-util v0.0.1 github.com/filecoin-project/go-cbor-util v0.0.1
github.com/filecoin-project/go-commp-utils v0.1.3 github.com/filecoin-project/go-commp-utils v0.1.3
@ -39,11 +40,11 @@ require (
github.com/filecoin-project/go-fil-commcid v0.1.0 github.com/filecoin-project/go-fil-commcid v0.1.0
github.com/filecoin-project/go-fil-commp-hashhash v0.1.0 github.com/filecoin-project/go-fil-commp-hashhash v0.1.0
github.com/filecoin-project/go-fil-markets v1.25.2 github.com/filecoin-project/go-fil-markets v1.25.2
github.com/filecoin-project/go-jsonrpc v0.1.8 github.com/filecoin-project/go-jsonrpc v0.1.9
github.com/filecoin-project/go-legs v0.4.4 github.com/filecoin-project/go-legs v0.4.4
github.com/filecoin-project/go-padreader v0.0.1 github.com/filecoin-project/go-padreader v0.0.1
github.com/filecoin-project/go-paramfetch v0.0.4 github.com/filecoin-project/go-paramfetch v0.0.4
github.com/filecoin-project/go-state-types v0.10.0-alpha-5 github.com/filecoin-project/go-state-types v0.10.0-alpha-9
github.com/filecoin-project/go-statemachine v1.0.2 github.com/filecoin-project/go-statemachine v1.0.2
github.com/filecoin-project/go-statestore v0.2.0 github.com/filecoin-project/go-statestore v0.2.0
github.com/filecoin-project/go-storedcounter v0.1.0 github.com/filecoin-project/go-storedcounter v0.1.0
@ -123,6 +124,7 @@ require (
github.com/libp2p/go-maddr-filter v0.1.0 github.com/libp2p/go-maddr-filter v0.1.0
github.com/libp2p/go-msgio v0.2.0 github.com/libp2p/go-msgio v0.2.0
github.com/mattn/go-isatty v0.0.16 github.com/mattn/go-isatty v0.0.16
github.com/mattn/go-sqlite3 v1.14.16
github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1 github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1
github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir v1.1.0
github.com/multiformats/go-base32 v0.1.0 github.com/multiformats/go-base32 v0.1.0
@ -140,7 +142,7 @@ require (
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
github.com/urfave/cli/v2 v2.16.3 github.com/urfave/cli/v2 v2.16.3
github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba github.com/whyrusleeping/bencher v0.0.0-20190829221104-bb6607aa8bba
github.com/whyrusleeping/cbor-gen v0.0.0-20220514204315-f29c37e9c44c github.com/whyrusleeping/cbor-gen v0.0.0-20221021053955-c138aae13722
github.com/whyrusleeping/ledger-filecoin-go v0.9.1-0.20201010031517-c3dcc1bddce4 github.com/whyrusleeping/ledger-filecoin-go v0.9.1-0.20201010031517-c3dcc1bddce4
github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7 github.com/whyrusleeping/multiaddr-filter v0.0.0-20160516205228-e903e4adabd7
github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542 github.com/xorcare/golden v0.6.1-0.20191112154924-b87f686d7542
@ -152,6 +154,7 @@ require (
go.uber.org/fx v1.15.0 go.uber.org/fx v1.15.0
go.uber.org/multierr v1.8.0 go.uber.org/multierr v1.8.0
go.uber.org/zap v1.23.0 go.uber.org/zap v1.23.0
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b
golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5 golang.org/x/net v0.0.0-20220920183852-bf014ff85ad5
golang.org/x/sync v0.0.0-20220907140024-f12130a52804 golang.org/x/sync v0.0.0-20220907140024-f12130a52804
@ -193,7 +196,6 @@ require (
github.com/etclabscore/go-jsonschema-walk v0.0.6 // indirect github.com/etclabscore/go-jsonschema-walk v0.0.6 // indirect
github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 // indirect github.com/filecoin-project/go-amt-ipld/v2 v2.1.0 // indirect
github.com/filecoin-project/go-amt-ipld/v3 v3.1.0 // indirect github.com/filecoin-project/go-amt-ipld/v3 v3.1.0 // indirect
github.com/filecoin-project/go-amt-ipld/v4 v4.0.0 // indirect
github.com/filecoin-project/go-commp-utils/nonffi v0.0.0-20220905160352-62059082a837 // indirect github.com/filecoin-project/go-commp-utils/nonffi v0.0.0-20220905160352-62059082a837 // indirect
github.com/filecoin-project/go-ds-versioning v0.1.2 // indirect github.com/filecoin-project/go-ds-versioning v0.1.2 // indirect
github.com/filecoin-project/go-hamt-ipld v0.1.5 // indirect github.com/filecoin-project/go-hamt-ipld v0.1.5 // indirect
@ -331,7 +333,6 @@ require (
go.uber.org/atomic v1.10.0 // indirect go.uber.org/atomic v1.10.0 // indirect
go.uber.org/dig v1.12.0 // indirect go.uber.org/dig v1.12.0 // indirect
go4.org v0.0.0-20200411211856-f5505b9728dd // indirect go4.org v0.0.0-20200411211856-f5505b9728dd // indirect
golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect

Some files were not shown because too many files have changed in this diff Show More