5353210814
* Read a subset of filecoin state over the full node API * wip * import export wip * extract actors from message * generate car for any state * library for providing a pruned statetree * test vector schema draft + example 'message' class test vector. * message => messages test vector class. * fixup * wip * use lb.NewBlockstore with ID * fixup lotus-soup, and generate * fix deals * magic params * work on schema / export of test vector * fixup * wip deserialise state tree * pass at building a test case from a message * progress loading / serializing * recreation of ipld nodes * generation of vector creates json * kick off tvx tool. * wip * wip * retain init actor state. * initial test with printed out state * remove testing.T, but keep require and assert libraries * wip refactor state tree plucking. * simplified * removed factories * remove builder.Build ; remove interface - use concrete iface * comment out validateState * remove Validator * remove TestDriverBuilder * remove client * remove box * remove gen * remove factories * remove KeyManager interfafce * moved stuff around * remove ValidationConfig * extract randomness * extract config and key_manager * extract statewrapper * extract applier * rename factories to various * flatten chain-validation package * initial marshal of test vector * do not require schema package * fixup * run all messages tests * better names * run all messages tests * remove Indent setting from JSON encoder for now * refactor, and actually running successfully ;-) * remove irrelevant files; rename extract-msg command. * remove root CID from state_tree object in schema. * add tvx/lotus package; adjust .gitignore. * tidy up command flag management. * add comment. * remove validateState and trackState * remove xerrors * remove NewVM * remove commented out RootCID sets * enable more tests * add all `message_application` tests * delete all.json * update Message struct * fix message serialization * support multiple messages * gofmt * remove custom Message and SignedMessage types * update tests with gzip and adhere to new schema for compressed CAR * improved iface for Marshal * update Validation * remove test-suites and utils * better names for chain. methods * go mod tidy * remove top-level dummyT Co-authored-by: Will Scott <will@cypherpunk.email> Co-authored-by: Raúl Kripalani <raul@protocol.ai>
568 lines
18 KiB
Go
568 lines
18 KiB
Go
package drivers
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/gzip"
|
|
"context"
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
|
|
"github.com/filecoin-project/go-bitfield"
|
|
"github.com/filecoin-project/lotus/chain/state"
|
|
|
|
"github.com/filecoin-project/go-address"
|
|
abi_spec "github.com/filecoin-project/specs-actors/actors/abi"
|
|
big_spec "github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
builtin_spec "github.com/filecoin-project/specs-actors/actors/builtin"
|
|
account_spec "github.com/filecoin-project/specs-actors/actors/builtin/account"
|
|
cron_spec "github.com/filecoin-project/specs-actors/actors/builtin/cron"
|
|
init_spec "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
|
market_spec "github.com/filecoin-project/specs-actors/actors/builtin/market"
|
|
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
|
multisig_spec "github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
|
power_spec "github.com/filecoin-project/specs-actors/actors/builtin/power"
|
|
reward_spec "github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
|
"github.com/filecoin-project/specs-actors/actors/builtin/system"
|
|
"github.com/filecoin-project/specs-actors/actors/runtime"
|
|
runtime_spec "github.com/filecoin-project/specs-actors/actors/runtime"
|
|
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
adt_spec "github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
"github.com/ipfs/go-blockservice"
|
|
cid "github.com/ipfs/go-cid"
|
|
datastore "github.com/ipfs/go-datastore"
|
|
blockstore "github.com/ipfs/go-ipfs-blockstore"
|
|
offline "github.com/ipfs/go-ipfs-exchange-offline"
|
|
cbor "github.com/ipfs/go-ipld-cbor"
|
|
format "github.com/ipfs/go-ipld-format"
|
|
"github.com/ipfs/go-merkledag"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/ipld/go-car"
|
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
|
"github.com/filecoin-project/oni/tvx/chain"
|
|
vtypes "github.com/filecoin-project/oni/tvx/chain/types"
|
|
)
|
|
|
|
var (
|
|
|
|
// initialized by calling initializeStoreWithAdtRoots
|
|
EmptyArrayCid cid.Cid
|
|
EmptyDeadlinesCid cid.Cid
|
|
EmptyMapCid cid.Cid
|
|
EmptyMultiMapCid cid.Cid
|
|
EmptyBitfieldCid cid.Cid
|
|
)
|
|
|
|
var (
|
|
DefaultInitActorState ActorState
|
|
DefaultRewardActorState ActorState
|
|
DefaultBurntFundsActorState ActorState
|
|
DefaultStoragePowerActorState ActorState
|
|
DefaultStorageMarketActorState ActorState
|
|
DefaultSystemActorState ActorState
|
|
DefaultCronActorState ActorState
|
|
DefaultBuiltinActorsState []ActorState
|
|
)
|
|
|
|
const (
|
|
TestSealProofType = abi_spec.RegisteredSealProof_StackedDrg2KiBV1
|
|
)
|
|
|
|
func init() {
|
|
ms := newMockStore()
|
|
if err := initializeStoreWithAdtRoots(ms); err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
DefaultInitActorState = ActorState{
|
|
Addr: builtin_spec.InitActorAddr,
|
|
Balance: big_spec.Zero(),
|
|
Code: builtin_spec.InitActorCodeID,
|
|
State: init_spec.ConstructState(EmptyMapCid, "chain-validation"),
|
|
}
|
|
|
|
firstRewardState := reward_spec.ConstructState(big_spec.Zero())
|
|
firstRewardState.ThisEpochReward = big_spec.NewInt(1e17)
|
|
|
|
DefaultRewardActorState = ActorState{
|
|
Addr: builtin_spec.RewardActorAddr,
|
|
Balance: TotalNetworkBalance,
|
|
Code: builtin_spec.RewardActorCodeID,
|
|
State: firstRewardState,
|
|
}
|
|
|
|
DefaultBurntFundsActorState = ActorState{
|
|
Addr: builtin_spec.BurntFundsActorAddr,
|
|
Balance: big_spec.Zero(),
|
|
Code: builtin_spec.AccountActorCodeID,
|
|
State: &account_spec.State{Address: builtin_spec.BurntFundsActorAddr},
|
|
}
|
|
|
|
DefaultStoragePowerActorState = ActorState{
|
|
Addr: builtin_spec.StoragePowerActorAddr,
|
|
Balance: big_spec.Zero(),
|
|
Code: builtin_spec.StoragePowerActorCodeID,
|
|
State: power_spec.ConstructState(EmptyMapCid, EmptyMultiMapCid),
|
|
}
|
|
|
|
DefaultStorageMarketActorState = ActorState{
|
|
Addr: builtin_spec.StorageMarketActorAddr,
|
|
Balance: big_spec.Zero(),
|
|
Code: builtin_spec.StorageMarketActorCodeID,
|
|
State: &market_spec.State{
|
|
Proposals: EmptyArrayCid,
|
|
States: EmptyArrayCid,
|
|
PendingProposals: EmptyMapCid,
|
|
EscrowTable: EmptyMapCid,
|
|
LockedTable: EmptyMapCid,
|
|
NextID: abi_spec.DealID(0),
|
|
DealOpsByEpoch: EmptyMultiMapCid,
|
|
LastCron: 0,
|
|
},
|
|
}
|
|
|
|
DefaultSystemActorState = ActorState{
|
|
Addr: builtin_spec.SystemActorAddr,
|
|
Balance: big_spec.Zero(),
|
|
Code: builtin_spec.SystemActorCodeID,
|
|
State: &system.State{},
|
|
}
|
|
|
|
DefaultCronActorState = ActorState{
|
|
Addr: builtin_spec.CronActorAddr,
|
|
Balance: big_spec.Zero(),
|
|
Code: builtin_spec.CronActorCodeID,
|
|
State: &cron_spec.State{Entries: []cron_spec.Entry{
|
|
{
|
|
Receiver: builtin_spec.StoragePowerActorAddr,
|
|
MethodNum: builtin_spec.MethodsPower.OnEpochTickEnd,
|
|
},
|
|
}},
|
|
}
|
|
|
|
DefaultBuiltinActorsState = []ActorState{
|
|
DefaultInitActorState,
|
|
DefaultRewardActorState,
|
|
DefaultBurntFundsActorState,
|
|
DefaultStoragePowerActorState,
|
|
DefaultStorageMarketActorState,
|
|
DefaultSystemActorState,
|
|
DefaultCronActorState,
|
|
}
|
|
}
|
|
|
|
func initializeStoreWithAdtRoots(store adt_spec.Store) error {
|
|
var err error
|
|
EmptyArrayCid, err = adt_spec.MakeEmptyArray(store).Root()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
EmptyMapCid, err = adt_spec.MakeEmptyMap(store).Root()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
EmptyMultiMapCid, err = adt_spec.MakeEmptyMultimap(store).Root()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
EmptyDeadlinesCid, err = store.Put(context.TODO(), &miner.Deadline{
|
|
Partitions: EmptyArrayCid,
|
|
ExpirationsEpochs: EmptyArrayCid,
|
|
PostSubmissions: abi_spec.NewBitField(),
|
|
EarlyTerminations: abi_spec.NewBitField(),
|
|
LiveSectors: 0,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
emptyBitfield := bitfield.NewFromSet(nil)
|
|
EmptyBitfieldCid, err = store.Put(context.TODO(), emptyBitfield)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
type mockStore struct {
|
|
ctx context.Context
|
|
cbor.IpldStore
|
|
}
|
|
|
|
func newMockStore() *mockStore {
|
|
bs := blockstore.NewBlockstore(datastore.NewMapDatastore())
|
|
cst := cbor.NewCborStore(bs)
|
|
return &mockStore{
|
|
ctx: context.Background(),
|
|
IpldStore: cst,
|
|
}
|
|
}
|
|
|
|
func (m mockStore) Context() context.Context {
|
|
return m.ctx
|
|
}
|
|
|
|
func NewTestDriver() *TestDriver {
|
|
syscalls := NewChainValidationSysCalls()
|
|
stateWrapper := NewStateWrapper()
|
|
applier := NewApplier(stateWrapper, func(ctx context.Context, cstate *state.StateTree, cst cbor.IpldStore) runtime.Syscalls {
|
|
return syscalls
|
|
})
|
|
|
|
sd := NewStateDriver(stateWrapper, newKeyManager())
|
|
|
|
err := initializeStoreWithAdtRoots(AsStore(sd.st))
|
|
require.NoError(t, err)
|
|
|
|
for _, acts := range DefaultBuiltinActorsState {
|
|
_, _, err := sd.State().CreateActor(acts.Code, acts.Addr, acts.Balance, acts.State)
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
minerActorIDAddr := sd.newMinerAccountActor(TestSealProofType, abi_spec.ChainEpoch(0))
|
|
|
|
exeCtx := vtypes.NewExecutionContext(1, minerActorIDAddr)
|
|
producer := chain.NewMessageProducer(1000000000, big_spec.NewInt(1)) // gas limit ; gas price
|
|
|
|
checkExit := true
|
|
checkRet := true
|
|
config := NewConfig(checkExit, checkRet)
|
|
|
|
return &TestDriver{
|
|
StateDriver: sd,
|
|
|
|
MessageProducer: producer,
|
|
ExeCtx: exeCtx,
|
|
Config: config,
|
|
SysCalls: syscalls,
|
|
|
|
applier: applier,
|
|
}
|
|
}
|
|
|
|
type ActorState struct {
|
|
Addr address.Address
|
|
Balance abi_spec.TokenAmount
|
|
Code cid.Cid
|
|
State runtime_spec.CBORMarshaler
|
|
}
|
|
|
|
type TestDriver struct {
|
|
*StateDriver
|
|
applier *Applier
|
|
|
|
MessageProducer *chain.MessageProducer
|
|
TipSetMessageBuilder *TipSetMessageBuilder
|
|
ExeCtx *vtypes.ExecutionContext
|
|
|
|
Config *Config
|
|
|
|
SysCalls *ChainValidationSysCalls
|
|
}
|
|
|
|
//
|
|
// Unsigned Message Appliers
|
|
//
|
|
|
|
func (td *TestDriver) ApplyMessage(msg *types.Message) vtypes.ApplyMessageResult {
|
|
result := td.applyMessage(msg)
|
|
return result
|
|
}
|
|
|
|
func (td *TestDriver) ApplyOk(msg *types.Message) vtypes.ApplyMessageResult {
|
|
return td.ApplyExpect(msg, EmptyReturnValue)
|
|
}
|
|
|
|
func (td *TestDriver) ApplyExpect(msg *types.Message, retval []byte) vtypes.ApplyMessageResult {
|
|
return td.applyMessageExpectCodeAndReturn(msg, exitcode.Ok, retval)
|
|
}
|
|
|
|
func (td *TestDriver) ApplyFailure(msg *types.Message, code exitcode.ExitCode) vtypes.ApplyMessageResult {
|
|
return td.applyMessageExpectCodeAndReturn(msg, code, EmptyReturnValue)
|
|
}
|
|
|
|
func (td *TestDriver) applyMessageExpectCodeAndReturn(msg *types.Message, code exitcode.ExitCode, retval []byte) vtypes.ApplyMessageResult {
|
|
result := td.applyMessage(msg)
|
|
td.validateResult(result, code, retval)
|
|
return result
|
|
}
|
|
|
|
func (td *TestDriver) applyMessage(msg *types.Message) (result vtypes.ApplyMessageResult) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
t.Fatalf("message application panicked: %v", r)
|
|
}
|
|
}()
|
|
|
|
result, err := td.applier.ApplyMessage(td.ExeCtx.Epoch, msg)
|
|
require.NoError(t, err)
|
|
|
|
return result
|
|
}
|
|
|
|
//
|
|
// Signed Message Appliers
|
|
//
|
|
|
|
func (td *TestDriver) ApplySigned(msg *types.Message) vtypes.ApplyMessageResult {
|
|
result := td.applyMessageSigned(msg)
|
|
return result
|
|
}
|
|
|
|
func (td *TestDriver) ApplySignedOk(msg *types.Message) vtypes.ApplyMessageResult {
|
|
return td.ApplySignedExpect(msg, EmptyReturnValue)
|
|
}
|
|
|
|
func (td *TestDriver) ApplySignedExpect(msg *types.Message, retval []byte) vtypes.ApplyMessageResult {
|
|
return td.applyMessageSignedExpectCodeAndReturn(msg, exitcode.Ok, retval)
|
|
}
|
|
|
|
func (td *TestDriver) ApplySignedFailure(msg *types.Message, code exitcode.ExitCode) vtypes.ApplyMessageResult {
|
|
return td.applyMessageExpectCodeAndReturn(msg, code, EmptyReturnValue)
|
|
}
|
|
|
|
func (td *TestDriver) applyMessageSignedExpectCodeAndReturn(msg *types.Message, code exitcode.ExitCode, retval []byte) vtypes.ApplyMessageResult {
|
|
result := td.applyMessageSigned(msg)
|
|
td.validateResult(result, code, retval)
|
|
return result
|
|
}
|
|
func (td *TestDriver) applyMessageSigned(msg *types.Message) (result vtypes.ApplyMessageResult) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
t.Fatalf("message application panicked: %v", r)
|
|
}
|
|
}()
|
|
serMsg, err := msg.Serialize()
|
|
require.NoError(t, err)
|
|
|
|
msgSig, err := td.Wallet().Sign(msg.From, serMsg)
|
|
require.NoError(t, err)
|
|
|
|
smsgs := &types.SignedMessage{
|
|
Message: *msg,
|
|
Signature: msgSig,
|
|
}
|
|
result, err = td.applier.ApplySignedMessage(td.ExeCtx.Epoch, smsgs)
|
|
require.NoError(t, err)
|
|
|
|
return result
|
|
}
|
|
|
|
func (td *TestDriver) validateResult(result vtypes.ApplyMessageResult, code exitcode.ExitCode, retval []byte) {
|
|
if td.Config.ValidateExitCode() {
|
|
assert.Equal(t, code, result.Receipt.ExitCode, "Expected ExitCode: %s Actual ExitCode: %s", code.Error(), result.Receipt.ExitCode.Error())
|
|
}
|
|
if td.Config.ValidateReturnValue() {
|
|
assert.Equal(t, retval, result.Receipt.ReturnValue, "Expected ReturnValue: %v Actual ReturnValue: %v", retval, result.Receipt.ReturnValue)
|
|
}
|
|
}
|
|
|
|
func (td *TestDriver) AssertNoActor(addr address.Address) {
|
|
_, err := td.State().Actor(addr)
|
|
assert.Error(t, err, "expected no such actor %s", addr)
|
|
}
|
|
|
|
func (td *TestDriver) GetBalance(addr address.Address) abi_spec.TokenAmount {
|
|
actr, err := td.State().Actor(addr)
|
|
require.NoError(t, err)
|
|
return actr.Balance()
|
|
}
|
|
|
|
func (td *TestDriver) GetHead(addr address.Address) cid.Cid {
|
|
actr, err := td.State().Actor(addr)
|
|
require.NoError(t, err)
|
|
return actr.Head()
|
|
}
|
|
|
|
// AssertBalance checks an actor has an expected balance.
|
|
func (td *TestDriver) AssertBalance(addr address.Address, expected abi_spec.TokenAmount) {
|
|
actr, err := td.State().Actor(addr)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, expected, actr.Balance(), fmt.Sprintf("expected actor %s balance: %s, actual balance: %s", addr, expected, actr.Balance()))
|
|
}
|
|
|
|
// Checks an actor's balance and callSeqNum.
|
|
func (td *TestDriver) AssertActor(addr address.Address, balance abi_spec.TokenAmount, callSeqNum uint64) {
|
|
actr, err := td.State().Actor(addr)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, balance, actr.Balance(), fmt.Sprintf("expected actor %s balance: %s, actual balance: %s", addr, balance, actr.Balance()))
|
|
assert.Equal(t, callSeqNum, actr.CallSeqNum(), fmt.Sprintf("expected actor %s callSeqNum: %d, actual : %d", addr, callSeqNum, actr.CallSeqNum()))
|
|
}
|
|
|
|
func (td *TestDriver) AssertHead(addr address.Address, expected cid.Cid) {
|
|
head := td.GetHead(addr)
|
|
assert.Equal(t, expected, head, "expected actor %s head %s, actual %s", addr, expected, head)
|
|
}
|
|
|
|
func (td *TestDriver) AssertBalanceCallback(addr address.Address, thing func(actorBalance abi_spec.TokenAmount) bool) {
|
|
actr, err := td.State().Actor(addr)
|
|
require.NoError(t, err)
|
|
assert.True(t, thing(actr.Balance()))
|
|
}
|
|
|
|
func (td *TestDriver) AssertMultisigTransaction(multisigAddr address.Address, txnID multisig_spec.TxnID, txn multisig_spec.Transaction) {
|
|
var msState multisig_spec.State
|
|
td.GetActorState(multisigAddr, &msState)
|
|
|
|
txnMap, err := adt_spec.AsMap(AsStore(td.State()), msState.PendingTxns)
|
|
require.NoError(t, err)
|
|
|
|
var actualTxn multisig_spec.Transaction
|
|
found, err := txnMap.Get(txnID, &actualTxn)
|
|
require.NoError(t, err)
|
|
require.True(t, found)
|
|
|
|
assert.Equal(t, txn, actualTxn)
|
|
}
|
|
|
|
func (td *TestDriver) AssertMultisigContainsTransaction(multisigAddr address.Address, txnID multisig_spec.TxnID, contains bool) {
|
|
var msState multisig_spec.State
|
|
td.GetActorState(multisigAddr, &msState)
|
|
|
|
txnMap, err := adt_spec.AsMap(AsStore(td.State()), msState.PendingTxns)
|
|
require.NoError(t, err)
|
|
|
|
var actualTxn multisig_spec.Transaction
|
|
found, err := txnMap.Get(txnID, &actualTxn)
|
|
require.NoError(t, err)
|
|
|
|
assert.Equal(t, contains, found)
|
|
|
|
}
|
|
|
|
func (td *TestDriver) AssertMultisigState(multisigAddr address.Address, expected multisig_spec.State) {
|
|
var msState multisig_spec.State
|
|
td.GetActorState(multisigAddr, &msState)
|
|
assert.NotNil(t, msState)
|
|
assert.Equal(t, expected.InitialBalance, msState.InitialBalance, fmt.Sprintf("expected InitialBalance: %v, actual InitialBalance: %v", expected.InitialBalance, msState.InitialBalance))
|
|
assert.Equal(t, expected.NextTxnID, msState.NextTxnID, fmt.Sprintf("expected NextTxnID: %v, actual NextTxnID: %v", expected.NextTxnID, msState.NextTxnID))
|
|
assert.Equal(t, expected.NumApprovalsThreshold, msState.NumApprovalsThreshold, fmt.Sprintf("expected NumApprovalsThreshold: %v, actual NumApprovalsThreshold: %v", expected.NumApprovalsThreshold, msState.NumApprovalsThreshold))
|
|
assert.Equal(t, expected.StartEpoch, msState.StartEpoch, fmt.Sprintf("expected StartEpoch: %v, actual StartEpoch: %v", expected.StartEpoch, msState.StartEpoch))
|
|
assert.Equal(t, expected.UnlockDuration, msState.UnlockDuration, fmt.Sprintf("expected UnlockDuration: %v, actual UnlockDuration: %v", expected.UnlockDuration, msState.UnlockDuration))
|
|
|
|
for _, e := range expected.Signers {
|
|
assert.Contains(t, msState.Signers, e, fmt.Sprintf("expected Signer: %v, actual Signer: %v", e, msState.Signers))
|
|
}
|
|
}
|
|
|
|
func (td *TestDriver) ComputeInitActorExecReturn(from address.Address, originatorCallSeq uint64, newActorAddressCount uint64, expectedNewAddr address.Address) init_spec.ExecReturn {
|
|
return computeInitActorExecReturn(from, originatorCallSeq, newActorAddressCount, expectedNewAddr)
|
|
}
|
|
|
|
func computeInitActorExecReturn(from address.Address, originatorCallSeq uint64, newActorAddressCount uint64, expectedNewAddr address.Address) init_spec.ExecReturn {
|
|
buf := new(bytes.Buffer)
|
|
if from.Protocol() == address.ID {
|
|
t.Fatal("cannot compute init actor address return from ID address", from)
|
|
}
|
|
|
|
require.NoError(t, from.MarshalCBOR(buf))
|
|
require.NoError(t, binary.Write(buf, binary.BigEndian, originatorCallSeq))
|
|
require.NoError(t, binary.Write(buf, binary.BigEndian, newActorAddressCount))
|
|
|
|
out, err := address.NewActorAddress(buf.Bytes())
|
|
require.NoError(t, err)
|
|
|
|
return init_spec.ExecReturn{
|
|
IDAddress: expectedNewAddr,
|
|
RobustAddress: out,
|
|
}
|
|
}
|
|
|
|
func (td *TestDriver) MustCreateAndVerifyMultisigActor(nonce uint64, value abi_spec.TokenAmount, multisigAddr address.Address, from address.Address, params *multisig_spec.ConstructorParams, code exitcode.ExitCode, retval []byte) {
|
|
/* Create the Multisig actor*/
|
|
td.applyMessageExpectCodeAndReturn(
|
|
td.MessageProducer.CreateMultisigActor(from, params.Signers, params.UnlockDuration, params.NumApprovalsThreshold, chain.Nonce(nonce), chain.Value(value)),
|
|
code, retval)
|
|
/* Assert the actor state was setup as expected */
|
|
pendingTxMapRoot, err := adt_spec.MakeEmptyMap(newMockStore()).Root()
|
|
require.NoError(t, err)
|
|
initialBalance := big_spec.Zero()
|
|
startEpoch := abi_spec.ChainEpoch(0)
|
|
if params.UnlockDuration > 0 {
|
|
initialBalance = value
|
|
startEpoch = td.ExeCtx.Epoch
|
|
}
|
|
td.AssertMultisigState(multisigAddr, multisig_spec.State{
|
|
NextTxnID: 0,
|
|
InitialBalance: initialBalance,
|
|
StartEpoch: startEpoch,
|
|
|
|
Signers: params.Signers,
|
|
UnlockDuration: params.UnlockDuration,
|
|
NumApprovalsThreshold: params.NumApprovalsThreshold,
|
|
|
|
PendingTxns: pendingTxMapRoot,
|
|
})
|
|
td.AssertBalance(multisigAddr, value)
|
|
}
|
|
|
|
type RewardSummary struct {
|
|
Treasury abi_spec.TokenAmount
|
|
SimpleSupply abi_spec.TokenAmount
|
|
BaselineSupply abi_spec.TokenAmount
|
|
NextPerEpochReward abi_spec.TokenAmount
|
|
NextPerBlockReward abi_spec.TokenAmount
|
|
}
|
|
|
|
func (td *TestDriver) GetRewardSummary() *RewardSummary {
|
|
var rst reward_spec.State
|
|
td.GetActorState(builtin_spec.RewardActorAddr, &rst)
|
|
|
|
return &RewardSummary{
|
|
Treasury: td.GetBalance(builtin_spec.RewardActorAddr),
|
|
NextPerEpochReward: rst.ThisEpochReward,
|
|
NextPerBlockReward: big_spec.Div(rst.ThisEpochReward, big_spec.NewInt(builtin_spec.ExpectedLeadersPerEpoch)),
|
|
}
|
|
}
|
|
|
|
func (td *TestDriver) GetStateRoot() cid.Cid {
|
|
return td.st.stateRoot
|
|
}
|
|
|
|
func (td *TestDriver) MustMarshalGzippedCAR(roots ...cid.Cid) []byte {
|
|
var b bytes.Buffer
|
|
gw := gzip.NewWriter(&b)
|
|
|
|
err := td.MarshalCAR(gw, roots...)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
gw.Close()
|
|
return b.Bytes()
|
|
}
|
|
|
|
func (td *TestDriver) MarshalCAR(w io.Writer, roots ...cid.Cid) error {
|
|
ctx := context.Background()
|
|
|
|
offl := offline.Exchange(td.st.bs)
|
|
blkserv := blockservice.New(td.st.bs, offl)
|
|
dserv := merkledag.NewDAGService(blkserv)
|
|
|
|
var cids []cid.Cid
|
|
cids = append(cids, roots...)
|
|
if err := car.WriteCarWithWalker(ctx, dserv, cids, w, walker); err != nil {
|
|
return fmt.Errorf("failed to write car file: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func walker(nd format.Node) (out []*format.Link, err error) {
|
|
for _, link := range nd.Links() {
|
|
if link.Cid.Prefix().Codec == cid.FilCommitmentSealed || link.Cid.Prefix().Codec == cid.FilCommitmentUnsealed {
|
|
continue
|
|
}
|
|
out = append(out, link)
|
|
}
|
|
|
|
return out, nil
|
|
}
|