transfer builders and scripts to filecoin-project/test-vectors. (#242)
This commit is contained in:
parent
6164d16f19
commit
497bda21b2
@ -52,21 +52,6 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: "build tvx"
|
name: "build tvx"
|
||||||
command: pushd tvx && go build .
|
command: pushd tvx && go build .
|
||||||
- run:
|
|
||||||
name: "run messages test vector suite: msg_application"
|
|
||||||
command: pushd tvx/scripts/msg_application && go build . && ./msg_application | ../../tvx exec-lotus
|
|
||||||
- run:
|
|
||||||
name: "run messages test vector suite: nested send"
|
|
||||||
command: pushd tvx/scripts/nested && go build . && ./nested | ../../tvx exec-lotus
|
|
||||||
- run:
|
|
||||||
name: "run messages test vector suite: paych"
|
|
||||||
command: pushd tvx/scripts/paych && go build . && ./paych | ../../tvx exec-lotus
|
|
||||||
- run:
|
|
||||||
name: "run messages test vector suite: actor_creation"
|
|
||||||
command: pushd tvx/scripts/actor_creation && go build . && ./actor_creation | ../../tvx exec-lotus
|
|
||||||
- run:
|
|
||||||
name: "run messages test vector suite: transfer"
|
|
||||||
command: pushd tvx/scripts/transfer && go build . && ./transfer | ../../tvx exec-lotus
|
|
||||||
soup-build-linux:
|
soup-build-linux:
|
||||||
executor: linux
|
executor: linux
|
||||||
steps:
|
steps:
|
||||||
|
@ -1,261 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/account"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
|
||||||
)
|
|
||||||
|
|
||||||
type registeredActor struct {
|
|
||||||
handle AddressHandle
|
|
||||||
initial abi.TokenAmount
|
|
||||||
}
|
|
||||||
|
|
||||||
// Actors is an object that manages actors in the test vector.
|
|
||||||
type Actors struct {
|
|
||||||
// registered stores registered actors and their initial balances.
|
|
||||||
registered []registeredActor
|
|
||||||
|
|
||||||
b *Builder
|
|
||||||
}
|
|
||||||
|
|
||||||
func newActors(b *Builder) *Actors {
|
|
||||||
return &Actors{b: b}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Count returns the number of actors registered during preconditions.
|
|
||||||
func (a *Actors) Count() int {
|
|
||||||
return len(a.registered)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleFor gets the canonical handle for a registered address, which can
|
|
||||||
// appear at either ID or Robust position.
|
|
||||||
func (a *Actors) HandleFor(addr address.Address) AddressHandle {
|
|
||||||
for _, r := range a.registered {
|
|
||||||
if r.handle.ID == addr || r.handle.Robust == addr {
|
|
||||||
return r.handle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a.b.Assert.FailNowf("asked for handle of unknown actor", "actor: %s", addr)
|
|
||||||
return AddressHandle{} // will never reach here.
|
|
||||||
}
|
|
||||||
|
|
||||||
// InitialBalance returns the initial balance of an actor that was registered
|
|
||||||
// during preconditions. It matches against both the ID and Robust
|
|
||||||
// addresses. It records an assertion failure if the actor is unknown.
|
|
||||||
func (a *Actors) InitialBalance(addr address.Address) abi.TokenAmount {
|
|
||||||
for _, r := range a.registered {
|
|
||||||
if r.handle.ID == addr || r.handle.Robust == addr {
|
|
||||||
return r.initial
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a.b.Assert.FailNowf("asked for initial balance of unknown actor", "actor: %s", addr)
|
|
||||||
return big.Zero() // will never reach here.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handles returns the AddressHandles for all registered actors.
|
|
||||||
func (a *Actors) Handles() []AddressHandle {
|
|
||||||
ret := make([]AddressHandle, 0, len(a.registered))
|
|
||||||
for _, r := range a.registered {
|
|
||||||
ret = append(ret, r.handle)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// AccountN creates many account actors of the specified kind, with the
|
|
||||||
// specified balance, and places their addresses in the supplied AddressHandles.
|
|
||||||
func (a *Actors) AccountN(typ address.Protocol, balance abi.TokenAmount, handles ...*AddressHandle) {
|
|
||||||
for _, handle := range handles {
|
|
||||||
h := a.Account(typ, balance)
|
|
||||||
*handle = h
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Account creates a single account actor of the specified kind, with the
|
|
||||||
// specified balance, and returns its AddressHandle.
|
|
||||||
func (a *Actors) Account(typ address.Protocol, balance abi.TokenAmount) AddressHandle {
|
|
||||||
a.b.Assert.In(typ, address.SECP256K1, address.BLS)
|
|
||||||
|
|
||||||
var addr address.Address
|
|
||||||
switch typ {
|
|
||||||
case address.SECP256K1:
|
|
||||||
addr = a.b.Wallet.NewSECP256k1Account()
|
|
||||||
case address.BLS:
|
|
||||||
addr = a.b.Wallet.NewBLSAccount()
|
|
||||||
}
|
|
||||||
|
|
||||||
actorState := &account.State{Address: addr}
|
|
||||||
handle := a.CreateActor(builtin.AccountActorCodeID, addr, balance, actorState)
|
|
||||||
|
|
||||||
a.registered = append(a.registered, registeredActor{handle, balance})
|
|
||||||
return handle
|
|
||||||
}
|
|
||||||
|
|
||||||
type MinerActorCfg struct {
|
|
||||||
SealProofType abi.RegisteredSealProof
|
|
||||||
PeriodBoundary abi.ChainEpoch
|
|
||||||
OwnerBalance abi.TokenAmount
|
|
||||||
}
|
|
||||||
|
|
||||||
// Miner creates an owner account, a worker account, and a miner actor managed
|
|
||||||
// by those initial.
|
|
||||||
func (a *Actors) Miner(cfg MinerActorCfg) (minerActor, owner, worker AddressHandle) {
|
|
||||||
owner = a.Account(address.SECP256K1, cfg.OwnerBalance)
|
|
||||||
worker = a.Account(address.BLS, big.Zero())
|
|
||||||
// expectedMinerActorIDAddress := chain.MustNewIDAddr(chain.MustIDFromAddress(minerWorkerID) + 1)
|
|
||||||
// minerActorAddrs := computeInitActorExecReturn(minerWorkerPk, 0, 1, expectedMinerActorIDAddress)
|
|
||||||
|
|
||||||
ss, err := cfg.SealProofType.SectorSize()
|
|
||||||
a.b.Assert.NoError(err, "seal proof sector size")
|
|
||||||
|
|
||||||
ps, err := cfg.SealProofType.WindowPoStPartitionSectors()
|
|
||||||
a.b.Assert.NoError(err, "seal proof window PoSt partition sectors")
|
|
||||||
|
|
||||||
mi := &miner.MinerInfo{
|
|
||||||
Owner: owner.ID,
|
|
||||||
Worker: worker.ID,
|
|
||||||
PendingWorkerKey: nil,
|
|
||||||
PeerId: abi.PeerID("chain-validation"),
|
|
||||||
Multiaddrs: nil,
|
|
||||||
SealProofType: cfg.SealProofType,
|
|
||||||
SectorSize: ss,
|
|
||||||
WindowPoStPartitionSectors: ps,
|
|
||||||
}
|
|
||||||
infoCid, err := a.b.Stores.CBORStore.Put(context.Background(), mi)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the miner actor s.t. it exists in the init actors map
|
|
||||||
minerState, err := miner.ConstructState(infoCid,
|
|
||||||
cfg.PeriodBoundary,
|
|
||||||
EmptyBitfieldCid,
|
|
||||||
EmptyArrayCid,
|
|
||||||
EmptyMapCid,
|
|
||||||
EmptyDeadlinesCid,
|
|
||||||
EmptyVestingFundsCid,
|
|
||||||
)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
minerActorAddr := worker.NextActorAddress(0, 0)
|
|
||||||
handle := a.CreateActor(builtin.StorageMinerActorCodeID, minerActorAddr, big.Zero(), minerState)
|
|
||||||
|
|
||||||
// assert miner actor has been created, exists in the state tree, and has an entry in the init actor.
|
|
||||||
// next update the storage power actor to track the miner
|
|
||||||
|
|
||||||
var spa power.State
|
|
||||||
a.ActorState(builtin.StoragePowerActorAddr, &spa)
|
|
||||||
|
|
||||||
// set the miners claim
|
|
||||||
hm, err := adt.AsMap(adt.WrapStore(context.Background(), a.b.Stores.CBORStore), spa.Claims)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// add claim for the miner
|
|
||||||
err = hm.Put(adt.AddrKey(handle.ID), &power.Claim{
|
|
||||||
RawBytePower: abi.NewStoragePower(0),
|
|
||||||
QualityAdjPower: abi.NewTokenAmount(0),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// save the claim
|
|
||||||
spa.Claims, err = hm.Root()
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// update miner count
|
|
||||||
spa.MinerCount += 1
|
|
||||||
|
|
||||||
// update storage power actor's state in the tree
|
|
||||||
_, err = a.b.Stores.CBORStore.Put(context.Background(), &spa)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
a.registered = append(a.registered, registeredActor{handle, big.Zero()})
|
|
||||||
return handle, owner, worker
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateActor creates an actor in the state tree, of the specified kind, with
|
|
||||||
// the specified address and balance, and sets its state to the supplied state.
|
|
||||||
func (a *Actors) CreateActor(code cid.Cid, addr address.Address, balance abi.TokenAmount, state runtime.CBORMarshaler) AddressHandle {
|
|
||||||
var id address.Address
|
|
||||||
if addr.Protocol() != address.ID {
|
|
||||||
var err error
|
|
||||||
id, err = a.b.StateTree.RegisterNewAddress(addr)
|
|
||||||
if err != nil {
|
|
||||||
log.Panicf("register new address for actor: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the new state.
|
|
||||||
head, err := a.b.StateTree.Store.Put(context.Background(), state)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the actor's head to point to that state.
|
|
||||||
actr := &types.Actor{
|
|
||||||
Code: code,
|
|
||||||
Head: head,
|
|
||||||
Balance: balance,
|
|
||||||
}
|
|
||||||
if err := a.b.StateTree.SetActor(addr, actr); err != nil {
|
|
||||||
log.Panicf("setting new actor for actor: %v", err)
|
|
||||||
}
|
|
||||||
return AddressHandle{id, addr}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ActorState retrieves the state of the supplied actor, and sets it in the
|
|
||||||
// provided object. It also returns the actor's header from the state tree.
|
|
||||||
func (a *Actors) ActorState(addr address.Address, out cbg.CBORUnmarshaler) *types.Actor {
|
|
||||||
actor := a.Header(addr)
|
|
||||||
err := a.b.StateTree.Store.Get(context.Background(), actor.Head, out)
|
|
||||||
a.b.Assert.NoError(err, "failed to load state for actorr %s; head=%s", addr, actor.Head)
|
|
||||||
return actor
|
|
||||||
}
|
|
||||||
|
|
||||||
// Header returns the actor's header from the state tree.
|
|
||||||
func (a *Actors) Header(addr address.Address) *types.Actor {
|
|
||||||
actor, err := a.b.StateTree.GetActor(addr)
|
|
||||||
a.b.Assert.NoError(err, "failed to fetch actor %s from state", addr)
|
|
||||||
return actor
|
|
||||||
}
|
|
||||||
|
|
||||||
// Balance is a shortcut for Header(addr).Balance.
|
|
||||||
func (a *Actors) Balance(addr address.Address) abi.TokenAmount {
|
|
||||||
return a.Header(addr).Balance
|
|
||||||
}
|
|
||||||
|
|
||||||
// Head is a shortcut for Header(addr).Head.
|
|
||||||
func (a *Actors) Head(addr address.Address) cid.Cid {
|
|
||||||
return a.Header(addr).Head
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nonce is a shortcut for Header(addr).Nonce.
|
|
||||||
func (a *Actors) Nonce(addr address.Address) uint64 {
|
|
||||||
return a.Header(addr).Nonce
|
|
||||||
}
|
|
||||||
|
|
||||||
// Code is a shortcut for Header(addr).Code.
|
|
||||||
func (a *Actors) Code(addr address.Address) cid.Cid {
|
|
||||||
return a.Header(addr).Code
|
|
||||||
}
|
|
@ -1,102 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/binary"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/lotus/chain/actors/aerrors"
|
|
||||||
"github.com/multiformats/go-varint"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddressHandle encapsulates both the ID and Robust addresses of an actor.
|
|
||||||
type AddressHandle struct {
|
|
||||||
ID, Robust address.Address
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ah AddressHandle) IDAddr() address.Address {
|
|
||||||
return ah.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ah AddressHandle) RobustAddr() address.Address {
|
|
||||||
return ah.Robust
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ah AddressHandle) String() string {
|
|
||||||
return fmt.Sprintf("AddressHandle[ID: %s, Robust: %s]", ah.ID, ah.Robust)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NextActorAddress predicts the address of the next actor created by this address.
|
|
||||||
//
|
|
||||||
// Code is adapted from vm.Runtime#NewActorAddress()
|
|
||||||
func (ah *AddressHandle) NextActorAddress(nonce, numActorsCreated uint64) address.Address {
|
|
||||||
var b bytes.Buffer
|
|
||||||
if err := ah.Robust.MarshalCBOR(&b); err != nil {
|
|
||||||
panic(aerrors.Fatalf("writing caller address into assert buffer: %v", err))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := binary.Write(&b, binary.BigEndian, nonce); err != nil {
|
|
||||||
panic(aerrors.Fatalf("writing nonce address into assert buffer: %v", err))
|
|
||||||
}
|
|
||||||
if err := binary.Write(&b, binary.BigEndian, numActorsCreated); err != nil {
|
|
||||||
panic(aerrors.Fatalf("writing callSeqNum address into assert buffer: %v", err))
|
|
||||||
}
|
|
||||||
addr, err := address.NewActorAddress(b.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
panic(aerrors.Fatalf("create actor address: %v", err))
|
|
||||||
}
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustNewIDAddr returns an address.Address of kind ID.
|
|
||||||
func MustNewIDAddr(id uint64) address.Address {
|
|
||||||
addr, err := address.NewIDAddress(id)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustNewSECP256K1Addr returns an address.Address of kind secp256k1.
|
|
||||||
func MustNewSECP256K1Addr(pubkey string) address.Address {
|
|
||||||
// the pubkey of assert secp256k1 address is hashed for consistent length.
|
|
||||||
addr, err := address.NewSecp256k1Address([]byte(pubkey))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustNewBLSAddr returns an address.Address of kind bls.
|
|
||||||
func MustNewBLSAddr(seed int64) address.Address {
|
|
||||||
buf := make([]byte, address.BlsPublicKeyBytes)
|
|
||||||
binary.PutVarint(buf, seed)
|
|
||||||
|
|
||||||
addr, err := address.NewBLSAddress(buf)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustNewActorAddr returns an address.Address of kind actor.
|
|
||||||
func MustNewActorAddr(data string) address.Address {
|
|
||||||
addr, err := address.NewActorAddress([]byte(data))
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return addr
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustIDFromAddress returns the integer ID from an ID address.
|
|
||||||
func MustIDFromAddress(a address.Address) uint64 {
|
|
||||||
if a.Protocol() != address.ID {
|
|
||||||
panic("must be ID protocol address")
|
|
||||||
}
|
|
||||||
id, _, err := varint.FromUvarint(a.Payload())
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return id
|
|
||||||
}
|
|
@ -1,143 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Asserter offers useful assertions to verify outcomes at various stages of
|
|
||||||
// the test vector creation.
|
|
||||||
type Asserter struct {
|
|
||||||
*require.Assertions
|
|
||||||
|
|
||||||
b *Builder
|
|
||||||
stage Stage
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ require.TestingT = &Asserter{}
|
|
||||||
|
|
||||||
func newAsserter(b *Builder, stage Stage) *Asserter {
|
|
||||||
a := &Asserter{stage: stage, b: b}
|
|
||||||
a.Assertions = require.New(a)
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// In is assert fluid version of require.Contains. It inverts the argument order,
|
|
||||||
// such that the admissible set can be supplied through assert variadic argument.
|
|
||||||
func (a *Asserter) In(v interface{}, set ...interface{}) {
|
|
||||||
a.Contains(set, v, "set %v does not contain element %v", set, v)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BalanceEq verifies that the balance of the address equals the expected one.
|
|
||||||
func (a *Asserter) BalanceEq(addr address.Address, expected abi.TokenAmount) {
|
|
||||||
actor, err := a.b.StateTree.GetActor(addr)
|
|
||||||
a.NoError(err, "failed to fetch actor %s from state", addr)
|
|
||||||
a.Equal(expected, actor.Balance, "balances mismatch for address %s", addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NonceEq verifies that the nonce of the actor equals the expected one.
|
|
||||||
func (a *Asserter) NonceEq(addr address.Address, expected uint64) {
|
|
||||||
actor, err := a.b.StateTree.GetActor(addr)
|
|
||||||
a.NoError(err, "failed to fetch actor %s from state", addr)
|
|
||||||
a.Equal(expected, actor.Nonce, "expected actor %s nonce: %d, got: %d", addr, expected, actor.Nonce)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HeadEq verifies that the head of the actor equals the expected one.
|
|
||||||
func (a *Asserter) HeadEq(addr address.Address, expected cid.Cid) {
|
|
||||||
actor, err := a.b.StateTree.GetActor(addr)
|
|
||||||
a.NoError(err, "failed to fetch actor %s from state", addr)
|
|
||||||
a.Equal(expected, actor.Head, "expected actor %s head: %v, got: %v", addr, expected, actor.Head)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ActorExists verifies that the actor exists in the state tree.
|
|
||||||
func (a *Asserter) ActorExists(addr address.Address) {
|
|
||||||
_, err := a.b.StateTree.GetActor(addr)
|
|
||||||
a.NoError(err, "expected no error while looking up actor %s", addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ActorExists verifies that the actor is absent from the state tree.
|
|
||||||
func (a *Asserter) ActorMissing(addr address.Address) {
|
|
||||||
_, err := a.b.StateTree.GetActor(addr)
|
|
||||||
a.Error(err, "expected error while looking up actor %s", addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// EveryMessageResultSatisfies verifies that every message result satisfies the
|
|
||||||
// provided predicate.
|
|
||||||
func (a *Asserter) EveryMessageResultSatisfies(predicate ApplyRetPredicate, except ...*ApplicableMessage) {
|
|
||||||
exceptm := make(map[*ApplicableMessage]struct{}, len(except))
|
|
||||||
for _, am := range except {
|
|
||||||
exceptm[am] = struct{}{}
|
|
||||||
}
|
|
||||||
for i, m := range a.b.Messages.messages {
|
|
||||||
if _, ok := exceptm[m]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
err := predicate(m.Result)
|
|
||||||
a.NoError(err, "message result predicate failed on message %d: %s", i, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EveryMessageSenderSatisfies verifies that the sender actors of the supplied
|
|
||||||
// messages match a condition.
|
|
||||||
//
|
|
||||||
// This function groups ApplicableMessages by sender actor, and calls the
|
|
||||||
// predicate for each unique sender, passing in the initial state (when
|
|
||||||
// preconditions were committed), the final state (could be nil), and the
|
|
||||||
// ApplicableMessages themselves.
|
|
||||||
func (a *Asserter) MessageSendersSatisfy(predicate ActorPredicate, ams ...*ApplicableMessage) {
|
|
||||||
bysender := make(map[AddressHandle][]*ApplicableMessage, len(ams))
|
|
||||||
for _, am := range ams {
|
|
||||||
h := a.b.Actors.HandleFor(am.Message.From)
|
|
||||||
bysender[h] = append(bysender[h], am)
|
|
||||||
}
|
|
||||||
// we now have messages organized by unique senders.
|
|
||||||
for sender, amss := range bysender {
|
|
||||||
// get precondition state
|
|
||||||
pretree, err := state.LoadStateTree(a.b.Stores.CBORStore, a.b.PreRoot)
|
|
||||||
a.NoError(err)
|
|
||||||
prestate, err := pretree.GetActor(sender.Robust)
|
|
||||||
a.NoError(err)
|
|
||||||
|
|
||||||
// get postcondition state; if actor has been deleted, we store a nil.
|
|
||||||
poststate, _ := a.b.StateTree.GetActor(sender.Robust)
|
|
||||||
|
|
||||||
// invoke predicate.
|
|
||||||
err = predicate(sender, prestate, poststate, amss)
|
|
||||||
a.NoError(err, "'every sender actor' predicate failed for sender %s: %s", sender, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// EveryMessageSenderSatisfies is sugar for MessageSendersSatisfy(predicate, Messages.All()),
|
|
||||||
// but supports an exclusion set to restrict the messages that will actually be asserted.
|
|
||||||
func (a *Asserter) EveryMessageSenderSatisfies(predicate ActorPredicate, except ...*ApplicableMessage) {
|
|
||||||
ams := a.b.Messages.All()
|
|
||||||
if len(except) > 0 {
|
|
||||||
filtered := ams[:0]
|
|
||||||
for _, ex := range except {
|
|
||||||
for _, am := range ams {
|
|
||||||
if am == ex {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
filtered = append(filtered, am)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ams = filtered
|
|
||||||
}
|
|
||||||
a.MessageSendersSatisfy(predicate, ams...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Asserter) FailNow() {
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Asserter) Errorf(format string, args ...interface{}) {
|
|
||||||
id := a.b.vector.Meta.ID
|
|
||||||
stage := a.stage
|
|
||||||
fmt.Printf("❌ id: %s, stage: %s:"+format, append([]interface{}{id, stage}, args...)...)
|
|
||||||
}
|
|
@ -1,198 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/state"
|
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
format "github.com/ipfs/go-ipld-format"
|
|
||||||
"github.com/ipld/go-car"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/oni/tvx/lotus"
|
|
||||||
"github.com/filecoin-project/oni/tvx/schema"
|
|
||||||
ostate "github.com/filecoin-project/oni/tvx/state"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Stage string
|
|
||||||
|
|
||||||
const (
|
|
||||||
StagePreconditions = Stage("preconditions")
|
|
||||||
StageApplies = Stage("applies")
|
|
||||||
StageChecks = Stage("checks")
|
|
||||||
StageFinished = Stage("finished")
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
// disable logs, as we need a clean stdout output.
|
|
||||||
log.SetOutput(os.Stderr)
|
|
||||||
log.SetPrefix(">>> ")
|
|
||||||
|
|
||||||
_ = os.Setenv("LOTUS_DISABLE_VM_BUF", "iknowitsabadidea")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO use stage.Surgeon with non-proxying blockstore.
|
|
||||||
type Builder struct {
|
|
||||||
Actors *Actors
|
|
||||||
Assert *Asserter
|
|
||||||
Messages *Messages
|
|
||||||
Driver *lotus.Driver
|
|
||||||
PreRoot cid.Cid
|
|
||||||
PostRoot cid.Cid
|
|
||||||
CurrRoot cid.Cid
|
|
||||||
Wallet *Wallet
|
|
||||||
StateTree *state.StateTree
|
|
||||||
Stores *ostate.Stores
|
|
||||||
|
|
||||||
vector schema.TestVector
|
|
||||||
stage Stage
|
|
||||||
}
|
|
||||||
|
|
||||||
// MessageVector creates a builder for a message-class vector.
|
|
||||||
func MessageVector(metadata *schema.Metadata) *Builder {
|
|
||||||
stores := ostate.NewLocalStores(context.Background())
|
|
||||||
|
|
||||||
// Create a brand new state tree.
|
|
||||||
st, err := state.NewStateTree(stores.CBORStore)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
b := &Builder{
|
|
||||||
stage: StagePreconditions,
|
|
||||||
Stores: stores,
|
|
||||||
StateTree: st,
|
|
||||||
PreRoot: cid.Undef,
|
|
||||||
Driver: lotus.NewDriver(context.Background()),
|
|
||||||
}
|
|
||||||
|
|
||||||
b.Wallet = newWallet()
|
|
||||||
b.Assert = newAsserter(b, StagePreconditions)
|
|
||||||
b.Actors = newActors(b)
|
|
||||||
b.Messages = &Messages{b: b}
|
|
||||||
|
|
||||||
b.vector.Class = schema.ClassMessage
|
|
||||||
b.vector.Meta = metadata
|
|
||||||
b.vector.Pre = &schema.Preconditions{}
|
|
||||||
b.vector.Post = &schema.Postconditions{}
|
|
||||||
|
|
||||||
b.initializeZeroState()
|
|
||||||
|
|
||||||
return b
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) CommitPreconditions() {
|
|
||||||
if b.stage != StagePreconditions {
|
|
||||||
panic("called CommitPreconditions at the wrong time")
|
|
||||||
}
|
|
||||||
|
|
||||||
// capture the preroot after applying all preconditions.
|
|
||||||
preroot := b.FlushState()
|
|
||||||
|
|
||||||
b.vector.Pre.Epoch = 0
|
|
||||||
b.vector.Pre.StateTree = &schema.StateTree{RootCID: preroot}
|
|
||||||
|
|
||||||
b.CurrRoot, b.PreRoot = preroot, preroot
|
|
||||||
b.stage = StageApplies
|
|
||||||
b.Assert = newAsserter(b, StageApplies)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) CommitApplies() {
|
|
||||||
if b.stage != StageApplies {
|
|
||||||
panic("called CommitApplies at the wrong time")
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, am := range b.Messages.All() {
|
|
||||||
// apply all messages that are pending application.
|
|
||||||
if am.Result == nil {
|
|
||||||
b.applyMessage(am)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
b.PostRoot = b.CurrRoot
|
|
||||||
b.vector.Post.StateTree = &schema.StateTree{RootCID: b.CurrRoot}
|
|
||||||
b.stage = StageChecks
|
|
||||||
b.Assert = newAsserter(b, StageChecks)
|
|
||||||
}
|
|
||||||
|
|
||||||
// applyMessage executes the provided message via the driver, records the new
|
|
||||||
// root, refreshes the state tree, and updates the underlying vector with the
|
|
||||||
// message and its receipt.
|
|
||||||
func (b *Builder) applyMessage(am *ApplicableMessage) {
|
|
||||||
var err error
|
|
||||||
am.Result, b.CurrRoot, err = b.Driver.ExecuteMessage(am.Message, b.CurrRoot, b.Stores.Blockstore, am.Epoch)
|
|
||||||
b.Assert.NoError(err)
|
|
||||||
|
|
||||||
// replace the state tree.
|
|
||||||
b.StateTree, err = state.LoadStateTree(b.Stores.CBORStore, b.CurrRoot)
|
|
||||||
b.Assert.NoError(err)
|
|
||||||
|
|
||||||
b.vector.ApplyMessages = append(b.vector.ApplyMessages, schema.Message{
|
|
||||||
Bytes: MustSerialize(am.Message),
|
|
||||||
Epoch: &am.Epoch,
|
|
||||||
})
|
|
||||||
b.vector.Post.Receipts = append(b.vector.Post.Receipts, &schema.Receipt{
|
|
||||||
ExitCode: am.Result.ExitCode,
|
|
||||||
ReturnValue: am.Result.Return,
|
|
||||||
GasUsed: am.Result.GasUsed,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) Finish(w io.Writer) {
|
|
||||||
if b.stage != StageChecks {
|
|
||||||
panic("called Finish at the wrong time")
|
|
||||||
}
|
|
||||||
|
|
||||||
out := new(bytes.Buffer)
|
|
||||||
gw := gzip.NewWriter(out)
|
|
||||||
if err := b.WriteCAR(gw, b.vector.Pre.StateTree.RootCID, b.vector.Post.StateTree.RootCID); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if err := gw.Flush(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if err := gw.Close(); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
b.vector.CAR = out.Bytes()
|
|
||||||
|
|
||||||
b.stage = StageFinished
|
|
||||||
b.Assert = nil
|
|
||||||
|
|
||||||
encoder := json.NewEncoder(w)
|
|
||||||
if err := encoder.Encode(b.vector); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteCAR recursively writes the tree referenced by the root as assert CAR into the
|
|
||||||
// supplied io.Writer.
|
|
||||||
//
|
|
||||||
// TODO use state.Surgeon instead. (This is assert copy of Surgeon#WriteCAR).
|
|
||||||
func (b *Builder) WriteCAR(w io.Writer, roots ...cid.Cid) error {
|
|
||||||
carWalkFn := func(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
|
|
||||||
}
|
|
||||||
|
|
||||||
return car.WriteCarWithWalker(context.Background(), b.Stores.DAGService, roots, w, carWalkFn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *Builder) FlushState() cid.Cid {
|
|
||||||
preroot, err := b.StateTree.Flush(context.Background())
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return preroot
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/oni/tvx/lotus"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
overuseNum = 11
|
|
||||||
overuseDen = 10
|
|
||||||
)
|
|
||||||
|
|
||||||
// CalculateDeduction returns the balance that shall be deducted from the
|
|
||||||
// sender's account as a result of applying this message.
|
|
||||||
func CalculateDeduction(am *ApplicableMessage) big.Int {
|
|
||||||
if am.Result.GasUsed == 0 {
|
|
||||||
return big.Zero()
|
|
||||||
}
|
|
||||||
|
|
||||||
m := am.Message
|
|
||||||
minerReward := GetMinerReward(m.GasLimit, m.GasPremium) // goes to the miner
|
|
||||||
burn := CalculateBurn(m.GasLimit, am.Result.GasUsed) // vanishes
|
|
||||||
deducted := big.Add(minerReward, burn) // sum of gas accrued
|
|
||||||
|
|
||||||
if am.Result.ExitCode.IsSuccess() {
|
|
||||||
deducted = big.Add(deducted, m.Value) // message value
|
|
||||||
}
|
|
||||||
return deducted
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMinerReward returns the amount that the miner gets to keep, which is
|
|
||||||
func GetMinerReward(gasLimit int64, gasPremium abi.TokenAmount) abi.TokenAmount {
|
|
||||||
return big.Mul(big.NewInt(gasLimit), gasPremium)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetMinerPenalty(gasLimit int64) big.Int {
|
|
||||||
return big.Mul(lotus.BaseFee, big.NewInt(gasLimit))
|
|
||||||
}
|
|
||||||
|
|
||||||
// CalculateBurn calcualtes the amount that will be burnt, a function of the
|
|
||||||
// gas limit and the gas actually used.
|
|
||||||
func CalculateBurn(gasLimit int64, gasUsed int64) big.Int {
|
|
||||||
over := gasLimit - (overuseNum*gasUsed)/overuseDen
|
|
||||||
if over < 0 {
|
|
||||||
over = 0
|
|
||||||
}
|
|
||||||
if over > gasUsed {
|
|
||||||
over = gasUsed
|
|
||||||
}
|
|
||||||
|
|
||||||
overestimateGas := big.NewInt(gasLimit - gasUsed)
|
|
||||||
overestimateGas = big.Mul(overestimateGas, big.NewInt(over))
|
|
||||||
overestimateGas = big.Div(overestimateGas, big.NewInt(gasUsed))
|
|
||||||
|
|
||||||
totalBurnGas := big.Add(overestimateGas, big.NewInt(gasUsed))
|
|
||||||
return big.Mul(lotus.BaseFee, totalBurnGas)
|
|
||||||
}
|
|
@ -1,186 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/oni/tvx/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Generator is a batch generator and organizer of test vectors.
|
|
||||||
//
|
|
||||||
// Test vector scripts are simple programs (main function). Test vector scripts
|
|
||||||
// can delegate to the Generator to handle the execution, reporting and capture
|
|
||||||
// of emitted test vectors into files.
|
|
||||||
//
|
|
||||||
// Generator supports the following CLI flags:
|
|
||||||
//
|
|
||||||
// -o <directory>
|
|
||||||
// directory where test vector JSON files will be saved; if omitted,
|
|
||||||
// vectors will be written to stdout.
|
|
||||||
//
|
|
||||||
// -f <regex>
|
|
||||||
// regex filter to select a subset of vectors to execute; matched against
|
|
||||||
// the vector's ID.
|
|
||||||
//
|
|
||||||
// Scripts can bundle test vectors into "groups". The generator will execute
|
|
||||||
// each group in parallel, and will write each vector in a file:
|
|
||||||
// <output_dir>/<group>--<vector_id>.json
|
|
||||||
type Generator struct {
|
|
||||||
OutputPath string
|
|
||||||
Filter *regexp.Regexp
|
|
||||||
|
|
||||||
wg sync.WaitGroup
|
|
||||||
}
|
|
||||||
|
|
||||||
// genData is the generation data to stamp into vectors.
|
|
||||||
// TODO in the future this should contain the commit of this tool and
|
|
||||||
// the builder api.
|
|
||||||
var genData = schema.GenerationData{
|
|
||||||
Source: "script",
|
|
||||||
Version: "v0",
|
|
||||||
}
|
|
||||||
|
|
||||||
type MessageVectorGenItem struct {
|
|
||||||
Metadata *schema.Metadata
|
|
||||||
Func func(*Builder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewGenerator() *Generator {
|
|
||||||
// Consume CLI parameters.
|
|
||||||
var (
|
|
||||||
outputDir = flag.String("o", "", "directory where test vector JSON files will be saved; if omitted, vectors will be written to stdout")
|
|
||||||
filter = flag.String("f", "", "regex filter to select a subset of vectors to execute; matched against the vector's ID")
|
|
||||||
)
|
|
||||||
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
ret := new(Generator)
|
|
||||||
|
|
||||||
// If output directory is provided, we ensure it exists, or create it.
|
|
||||||
// Else, we'll output to stdout.
|
|
||||||
if dir := *outputDir; dir != "" {
|
|
||||||
err := ensureDirectory(dir)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal(err)
|
|
||||||
}
|
|
||||||
ret.OutputPath = dir
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a filter has been provided, compile it into a regex.
|
|
||||||
if *filter != "" {
|
|
||||||
exp, err := regexp.Compile(*filter)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("supplied regex %s is invalid: %s", *filter, err)
|
|
||||||
}
|
|
||||||
ret.Filter = exp
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Generator) Wait() {
|
|
||||||
g.wg.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Generator) MessageVectorGroup(group string, vectors ...*MessageVectorGenItem) {
|
|
||||||
g.wg.Add(1)
|
|
||||||
go func() {
|
|
||||||
defer g.wg.Done()
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
for _, item := range vectors {
|
|
||||||
if id := item.Metadata.ID; g.Filter != nil && !g.Filter.MatchString(id) {
|
|
||||||
log.Printf("skipping %s", id)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var w io.Writer
|
|
||||||
if g.OutputPath == "" {
|
|
||||||
w = os.Stdout
|
|
||||||
} else {
|
|
||||||
file := filepath.Join(g.OutputPath, fmt.Sprintf("%s--%s.json", group, item.Metadata.ID))
|
|
||||||
out, err := os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to write to file %s: %s", file, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
w = out
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Add(1)
|
|
||||||
go func(item *MessageVectorGenItem) {
|
|
||||||
g.generateOne(w, item, w != os.Stdout)
|
|
||||||
wg.Done()
|
|
||||||
}(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *Generator) generateOne(w io.Writer, b *MessageVectorGenItem, indent bool) {
|
|
||||||
log.Printf("generating test vector: %s", b.Metadata.ID)
|
|
||||||
|
|
||||||
// stamp with our generation data.
|
|
||||||
b.Metadata.Gen = genData
|
|
||||||
|
|
||||||
vector := MessageVector(b.Metadata)
|
|
||||||
|
|
||||||
// TODO: currently if an assertion fails, we call os.Exit(1), which
|
|
||||||
// aborts all ongoing vector generations. The Asserter should
|
|
||||||
// call runtime.Goexit() instead so only that goroutine is
|
|
||||||
// cancelled. The assertion error must bubble up somehow.
|
|
||||||
b.Func(vector)
|
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
vector.Finish(buf)
|
|
||||||
|
|
||||||
final := buf
|
|
||||||
if indent {
|
|
||||||
// reparse and reindent.
|
|
||||||
final = new(bytes.Buffer)
|
|
||||||
if err := json.Indent(final, buf.Bytes(), "", "\t"); err != nil {
|
|
||||||
log.Printf("failed to indent json: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n, err := w.Write(final.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to write to output: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("generated test vector: %s (size: %d bytes)", b.Metadata.ID, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensureDirectory checks if the provided path is a directory. If yes, it
|
|
||||||
// returns nil. If the path doesn't exist, it creates the directory and
|
|
||||||
// returns nil. If the path is not a directory, or another error occurs, an
|
|
||||||
// error is returned.
|
|
||||||
func ensureDirectory(path string) error {
|
|
||||||
switch stat, err := os.Stat(path); {
|
|
||||||
case os.IsNotExist(err):
|
|
||||||
// create directory.
|
|
||||||
log.Printf("creating directory %s", path)
|
|
||||||
err := os.MkdirAll(path, 0700)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create directory %s: %s", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
case err == nil && !stat.IsDir():
|
|
||||||
return fmt.Errorf("path %s exists, but it's not a directory", path)
|
|
||||||
|
|
||||||
case err != nil:
|
|
||||||
return fmt.Errorf("failed to stat directory %s: %w", path, err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,168 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TypedCall represents a call to a known built-in actor kind.
|
|
||||||
type TypedCall func() (method abi.MethodNum, params []byte)
|
|
||||||
|
|
||||||
// Messages accumulates the messages to be executed within the test vector.
|
|
||||||
type Messages struct {
|
|
||||||
b *Builder
|
|
||||||
defaults msgOpts
|
|
||||||
|
|
||||||
messages []*ApplicableMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDefaults sets default options for all messages.
|
|
||||||
func (m *Messages) SetDefaults(opts ...MsgOpt) *Messages {
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&m.defaults)
|
|
||||||
}
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplicableMessage represents a message to be applied on the test vector.
|
|
||||||
type ApplicableMessage struct {
|
|
||||||
Epoch abi.ChainEpoch
|
|
||||||
Message *types.Message
|
|
||||||
Result *vm.ApplyRet
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Messages) Sugar() *sugarMsg {
|
|
||||||
return &sugarMsg{m}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All returns all ApplicableMessages that have been accumulated, in the same
|
|
||||||
// order they were added.
|
|
||||||
func (m *Messages) All() []*ApplicableMessage {
|
|
||||||
cpy := make([]*ApplicableMessage, len(m.messages))
|
|
||||||
copy(cpy, m.messages)
|
|
||||||
return cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Typed adds a typed call to this message accumulator.
|
|
||||||
func (m *Messages) Typed(from, to address.Address, typedm TypedCall, opts ...MsgOpt) *ApplicableMessage {
|
|
||||||
method, params := typedm()
|
|
||||||
return m.Raw(from, to, method, params, opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Raw adds a raw message to this message accumulator.
|
|
||||||
func (m *Messages) Raw(from, to address.Address, method abi.MethodNum, params []byte, opts ...MsgOpt) *ApplicableMessage {
|
|
||||||
options := m.defaults
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(&options)
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := &types.Message{
|
|
||||||
To: to,
|
|
||||||
From: from,
|
|
||||||
Nonce: options.nonce,
|
|
||||||
Value: options.value,
|
|
||||||
Method: method,
|
|
||||||
Params: params,
|
|
||||||
GasLimit: options.gasLimit,
|
|
||||||
GasFeeCap: options.gasFeeCap,
|
|
||||||
GasPremium: options.gasPremium,
|
|
||||||
}
|
|
||||||
|
|
||||||
am := &ApplicableMessage{
|
|
||||||
Epoch: options.epoch,
|
|
||||||
Message: msg,
|
|
||||||
}
|
|
||||||
|
|
||||||
m.messages = append(m.messages, am)
|
|
||||||
return am
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyOne applies the provided message. The following constraints are checked:
|
|
||||||
// - all previous messages have been applied.
|
|
||||||
// - we know about this message (i.e. it has been added through Typed, Raw or Sugar).
|
|
||||||
func (m *Messages) ApplyOne(am *ApplicableMessage) {
|
|
||||||
var found bool
|
|
||||||
for i, other := range m.messages {
|
|
||||||
if other.Result != nil {
|
|
||||||
// message has been applied, continue.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if am == other {
|
|
||||||
// we have scanned all preceding messages, and verified they had been applied.
|
|
||||||
// we are ready to perform the application.
|
|
||||||
found = true
|
|
||||||
break
|
|
||||||
}
|
|
||||||
// verify that preceding messages have been applied.
|
|
||||||
// this will abort if unsatisfied.
|
|
||||||
m.b.Assert.Nil(other.Result, "preceding messages must have been applied when calling Apply*; index of first unapplied: %d", i)
|
|
||||||
}
|
|
||||||
m.b.Assert.True(found, "ApplicableMessage not found")
|
|
||||||
m.b.applyMessage(am)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ApplyN calls ApplyOne for the supplied messages, in the order they are passed.
|
|
||||||
// The constraints described in ApplyOne apply.
|
|
||||||
func (m *Messages) ApplyN(ams ...*ApplicableMessage) {
|
|
||||||
for _, am := range ams {
|
|
||||||
m.ApplyOne(am)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type msgOpts struct {
|
|
||||||
nonce uint64
|
|
||||||
value big.Int
|
|
||||||
gasLimit int64
|
|
||||||
gasFeeCap abi.TokenAmount
|
|
||||||
gasPremium abi.TokenAmount
|
|
||||||
epoch abi.ChainEpoch
|
|
||||||
}
|
|
||||||
|
|
||||||
// MsgOpt is an option configuring message value, gas parameters, execution
|
|
||||||
// epoch, and other elements.
|
|
||||||
type MsgOpt func(*msgOpts)
|
|
||||||
|
|
||||||
// Value sets a value on a message.
|
|
||||||
func Value(value big.Int) MsgOpt {
|
|
||||||
return func(opts *msgOpts) {
|
|
||||||
opts.value = value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Nonce sets the nonce of a message.
|
|
||||||
func Nonce(n uint64) MsgOpt {
|
|
||||||
return func(opts *msgOpts) {
|
|
||||||
opts.nonce = n
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GasLimit sets the gas limit of a message.
|
|
||||||
func GasLimit(limit int64) MsgOpt {
|
|
||||||
return func(opts *msgOpts) {
|
|
||||||
opts.gasLimit = limit
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GasFeeCap sets the gas fee cap of a message.
|
|
||||||
func GasFeeCap(feeCap int64) MsgOpt {
|
|
||||||
return func(opts *msgOpts) {
|
|
||||||
opts.gasFeeCap = big.NewInt(feeCap)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// GasPremium sets the gas premium of a message.
|
|
||||||
func GasPremium(premium int64) MsgOpt {
|
|
||||||
return func(opts *msgOpts) {
|
|
||||||
opts.gasPremium = big.NewInt(premium)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Epoch sets the epoch in which a message is to be executed.
|
|
||||||
func Epoch(epoch abi.ChainEpoch) MsgOpt {
|
|
||||||
return func(opts *msgOpts) {
|
|
||||||
opts.epoch = epoch
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
|
||||||
|
|
||||||
"github.com/libp2p/go-libp2p-core/peer"
|
|
||||||
)
|
|
||||||
|
|
||||||
type sugarMsg struct{ m *Messages }
|
|
||||||
|
|
||||||
// Transfer enlists a value transfer message.
|
|
||||||
func (s *sugarMsg) Transfer(from, to address.Address, opts ...MsgOpt) *ApplicableMessage {
|
|
||||||
return s.m.Typed(from, to, Transfer(), opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *sugarMsg) CreatePaychActor(from, to address.Address, opts ...MsgOpt) *ApplicableMessage {
|
|
||||||
ctorparams := &paych.ConstructorParams{
|
|
||||||
From: from,
|
|
||||||
To: to,
|
|
||||||
}
|
|
||||||
return s.m.Typed(from, builtin.InitActorAddr, InitExec(&init_.ExecParams{
|
|
||||||
CodeCID: builtin.PaymentChannelActorCodeID,
|
|
||||||
ConstructorParams: MustSerialize(ctorparams),
|
|
||||||
}), opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *sugarMsg) CreateMultisigActor(from address.Address, params *multisig.ConstructorParams, opts ...MsgOpt) *ApplicableMessage {
|
|
||||||
return s.m.Typed(from, builtin.InitActorAddr, InitExec(&init_.ExecParams{
|
|
||||||
CodeCID: builtin.MultisigActorCodeID,
|
|
||||||
ConstructorParams: MustSerialize(params),
|
|
||||||
}), opts...)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *sugarMsg) CreateMinerActor(owner, worker address.Address, sealProofType abi.RegisteredSealProof, pid peer.ID, maddrs []abi.Multiaddrs, opts ...MsgOpt) *ApplicableMessage {
|
|
||||||
params := &power.CreateMinerParams{
|
|
||||||
Worker: worker,
|
|
||||||
Owner: owner,
|
|
||||||
SealProofType: sealProofType,
|
|
||||||
Peer: abi.PeerID(pid),
|
|
||||||
Multiaddrs: maddrs,
|
|
||||||
}
|
|
||||||
return s.m.Typed(owner, builtin.StoragePowerActorAddr, PowerCreateMiner(params), opts...)
|
|
||||||
}
|
|
@ -1,379 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/puppet"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/cron"
|
|
||||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/market"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/miner"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/power"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Transfer() TypedCall {
|
|
||||||
return func() (method abi.MethodNum, params []byte) {
|
|
||||||
return builtin.MethodSend, []byte{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// | ACCOUNT
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func AccountConstructor(params *address.Address) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsAccount.Constructor, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func AccountPubkeyAddress(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsAccount.PubkeyAddress, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// | MARKET
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func MarketConstructor(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMarket.Constructor, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MarketAddBalance(params *address.Address) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMarket.AddBalance, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MarketWithdrawBalance(params *market.WithdrawBalanceParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMarket.WithdrawBalance, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MarketPublishStorageDeals(params *market.PublishStorageDealsParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMarket.PublishStorageDeals, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MarketVerifyDealsForActivation(params *market.VerifyDealsForActivationParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMarket.VerifyDealsForActivation, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MarketActivateDeals(params *market.ActivateDealsParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMarket.ActivateDeals, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MarketOnMinerSectorsTerminate(params *market.OnMinerSectorsTerminateParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMarket.OnMinerSectorsTerminate, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MarketComputeDataCommitment(params *market.ComputeDataCommitmentParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMarket.ComputeDataCommitment, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MarketCronTick(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMarket.CronTick, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// | MINER
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func MinerConstructor(params *power.MinerConstructorParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.Constructor, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerControlAddresses(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.ControlAddresses, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerChangeWorkerAddress(params *miner.ChangeWorkerAddressParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.ChangeWorkerAddress, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerChangePeerID(params *miner.ChangePeerIDParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.ChangePeerID, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerSubmitWindowedPoSt(params *miner.SubmitWindowedPoStParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.SubmitWindowedPoSt, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerPreCommitSector(params *miner.SectorPreCommitInfo) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.PreCommitSector, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerProveCommitSector(params *miner.ProveCommitSectorParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.ProveCommitSector, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerExtendSectorExpiration(params *miner.ExtendSectorExpirationParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.ExtendSectorExpiration, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerTerminateSectors(params *miner.TerminateSectorsParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.TerminateSectors, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerDeclareFaults(params *miner.DeclareFaultsParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.DeclareFaults, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerDeclareFaultsRecovered(params *miner.DeclareFaultsRecoveredParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.DeclareFaultsRecovered, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerOnDeferredCronEvent(params *miner.CronEventPayload) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.OnDeferredCronEvent, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerCheckSectorProven(params *miner.CheckSectorProvenParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.CheckSectorProven, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerAddLockedFund(params *big.Int) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.AddLockedFund, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerReportConsensusFault(params *miner.ReportConsensusFaultParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.ReportConsensusFault, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerWithdrawBalance(params *miner.WithdrawBalanceParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.WithdrawBalance, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerConfirmSectorProofsValid(params *builtin.ConfirmSectorProofsParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.ConfirmSectorProofsValid, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MinerChangeMultiaddrs(params *miner.ChangeMultiaddrsParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMiner.ChangeMultiaddrs, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// | MULTISIG
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func MultisigConstructor(params *multisig.ConstructorParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMultisig.Constructor, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MultisigPropose(params *multisig.ProposeParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMultisig.Propose, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MultisigApprove(params *multisig.TxnIDParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMultisig.Approve, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MultisigCancel(params *multisig.TxnIDParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMultisig.Cancel, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MultisigAddSigner(params *multisig.AddSignerParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMultisig.AddSigner, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MultisigRemoveSigner(params *multisig.RemoveSignerParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMultisig.RemoveSigner, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MultisigSwapSigner(params *multisig.SwapSignerParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMultisig.SwapSigner, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func MultisigChangeNumApprovalsThreshold(params *multisig.ChangeNumApprovalsThresholdParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsMultisig.ChangeNumApprovalsThreshold, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// | POWER
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func PowerConstructor(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPower.Constructor, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func PowerCreateMiner(params *power.CreateMinerParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPower.CreateMiner, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func PowerUpdateClaimedPower(params *power.UpdateClaimedPowerParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPower.UpdateClaimedPower, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func PowerEnrollCronEvent(params *power.EnrollCronEventParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPower.EnrollCronEvent, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func PowerOnEpochTickEnd(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPower.OnEpochTickEnd, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func PowerUpdatePledgeTotal(params *big.Int) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPower.UpdatePledgeTotal, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func PowerOnConsensusFault(params *big.Int) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPower.OnConsensusFault, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func PowerSubmitPoRepForBulkVerify(params *abi.SealVerifyInfo) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPower.SubmitPoRepForBulkVerify, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func PowerCurrentTotalPower(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPower.CurrentTotalPower, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// | REWARD
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func RewardConstructor(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsReward.Constructor, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func RewardAwardBlockReward(params *reward.AwardBlockRewardParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsReward.AwardBlockReward, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func RewardThisEpochReward(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsReward.ThisEpochReward, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func RewardUpdateNetworkKPI(params *big.Int) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsReward.UpdateNetworkKPI, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// | PAYCH
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func PaychConstructor(params *paych.ConstructorParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPaych.Constructor, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func PaychUpdateChannelState(params *paych.UpdateChannelStateParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPaych.UpdateChannelState, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func PaychSettle(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPaych.Settle, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func PaychCollect(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsPaych.Collect, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// | CRON
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func CronConstructor(params *cron.ConstructorParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsCron.Constructor, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func CronEpochTick(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsCron.EpochTick, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// | INIT
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func InitConstructor(params *init_.ConstructorParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsInit.Constructor, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func InitExec(params *init_.ExecParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return builtin.MethodsInit.Exec, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// | PUPPET
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
func PuppetConstructor(params *adt.EmptyValue) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return puppet.MethodsPuppet.Constructor, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func PuppetSend(params *puppet.SendParams) TypedCall {
|
|
||||||
return func() (abi.MethodNum, []byte) {
|
|
||||||
return puppet.MethodsPuppet.Send, MustSerialize(params)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
"github.com/filecoin-project/lotus/chain/vm"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ApplyRetPredicate evaluates a given condition against the result of a
|
|
||||||
// message application.
|
|
||||||
type ApplyRetPredicate func(ret *vm.ApplyRet) error
|
|
||||||
|
|
||||||
// OptionalActor is a marker type to warn that the value can be nil.
|
|
||||||
type OptionalActor = types.Actor
|
|
||||||
|
|
||||||
// ActorPredicate evaluates whether the actor that participates in the provided
|
|
||||||
// messages satisfies a given condition. The initial state (after preconditions)
|
|
||||||
// and final state (after applies) are supplied.
|
|
||||||
type ActorPredicate func(handle AddressHandle, initial *OptionalActor, final *OptionalActor, amss []*ApplicableMessage) error
|
|
||||||
|
|
||||||
// ExitCode returns an ApplyRetPredicate that passes if the exit code of the
|
|
||||||
// message execution matches the argument.
|
|
||||||
func ExitCode(expect exitcode.ExitCode) ApplyRetPredicate {
|
|
||||||
return func(ret *vm.ApplyRet) error {
|
|
||||||
if ret.ExitCode == expect {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return fmt.Errorf("message exit code was %d; expected %d", ret.ExitCode, expect)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// BalanceUpdated returns a ActorPredicate that checks whether the balance
|
|
||||||
// of the actor has been deducted the gas cost and the outgoing value transfers,
|
|
||||||
// and has been increased by the offset (or decreased, if the argument is negative).
|
|
||||||
func BalanceUpdated(offset abi.TokenAmount) ActorPredicate {
|
|
||||||
return func(handle AddressHandle, initial *types.Actor, final *OptionalActor, amss []*ApplicableMessage) error {
|
|
||||||
if initial == nil || final == nil {
|
|
||||||
return fmt.Errorf("BalanceUpdated predicate expected non-nil state")
|
|
||||||
}
|
|
||||||
|
|
||||||
// accumulate all balance deductions: ∑(burnt + premium + transferred value)
|
|
||||||
deducted := big.Zero()
|
|
||||||
for _, am := range amss {
|
|
||||||
d := CalculateDeduction(am)
|
|
||||||
deducted = big.Add(deducted, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := big.Sub(initial.Balance, deducted)
|
|
||||||
expected = big.Add(expected, offset)
|
|
||||||
if !final.Balance.Equals(expected) {
|
|
||||||
return fmt.Errorf("expected balance %s, was: %s", expected, final.Balance)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NonceUpdated returns a ActorPredicate that checks whether the nonce
|
|
||||||
// of the actor has been updated to the nonce of the last message + 1.
|
|
||||||
func NonceUpdated() ActorPredicate {
|
|
||||||
return func(handle AddressHandle, initial *types.Actor, final *OptionalActor, amss []*ApplicableMessage) error {
|
|
||||||
if initial == nil || final == nil {
|
|
||||||
return fmt.Errorf("BalanceUpdated predicate expected non-nil state")
|
|
||||||
}
|
|
||||||
|
|
||||||
// the nonce should be equal to the nonce of the last message + 1.
|
|
||||||
last := amss[len(amss)-1]
|
|
||||||
if expected, actual := last.Message.Nonce+1, final.Nonce; expected != actual {
|
|
||||||
return fmt.Errorf("for actor: %s: expected nonce %d, got %d", handle, expected, actual)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
cbg "github.com/whyrusleeping/cbor-gen"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MustSerialize(i cbg.CBORMarshaler) []byte {
|
|
||||||
out, err := Serialize(i)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func Serialize(i cbg.CBORMarshaler) ([]byte, error) {
|
|
||||||
buf := new(bytes.Buffer)
|
|
||||||
if err := i.MarshalCBOR(buf); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func MustDeserialize(b []byte, out interface{}) {
|
|
||||||
if err := Deserialize(b, out); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Deserialize(b []byte, out interface{}) error {
|
|
||||||
um, ok := out.(cbg.CBORUnmarshaler)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("type %T does not implement UnmarshalCBOR", out)
|
|
||||||
}
|
|
||||||
return um.UnmarshalCBOR(bytes.NewReader(b))
|
|
||||||
}
|
|
@ -1,172 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/go-bitfield"
|
|
||||||
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"
|
|
||||||
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"
|
|
||||||
runtime_spec "github.com/filecoin-project/specs-actors/actors/runtime"
|
|
||||||
adt_spec "github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
||||||
"github.com/ipfs/go-cid"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
totalFilecoin = 2_000_000_000
|
|
||||||
filecoinPrecision = 1_000_000_000_000_000_000
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
TotalNetworkBalance = big_spec.Mul(big_spec.NewInt(totalFilecoin), big_spec.NewInt(filecoinPrecision))
|
|
||||||
EmptyReturnValue = []byte{}
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
// initialized by calling initializeStoreWithAdtRoots
|
|
||||||
EmptyArrayCid cid.Cid
|
|
||||||
EmptyDeadlinesCid cid.Cid
|
|
||||||
EmptyMapCid cid.Cid
|
|
||||||
EmptyMultiMapCid cid.Cid
|
|
||||||
EmptyBitfieldCid cid.Cid
|
|
||||||
EmptyVestingFundsCid cid.Cid
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
TestSealProofType = abi_spec.RegisteredSealProof_StackedDrg2KiBV1
|
|
||||||
)
|
|
||||||
|
|
||||||
func (b *Builder) initializeZeroState() {
|
|
||||||
if err := insertEmptyStructures(b.Stores.ADTStore); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ActorState struct {
|
|
||||||
Addr address.Address
|
|
||||||
Balance abi_spec.TokenAmount
|
|
||||||
Code cid.Cid
|
|
||||||
State runtime_spec.CBORMarshaler
|
|
||||||
}
|
|
||||||
|
|
||||||
var actors []ActorState
|
|
||||||
|
|
||||||
actors = append(actors, ActorState{
|
|
||||||
Addr: builtin_spec.InitActorAddr,
|
|
||||||
Balance: big_spec.Zero(),
|
|
||||||
Code: builtin_spec.InitActorCodeID,
|
|
||||||
State: init_spec.ConstructState(EmptyMapCid, "chain-validation"),
|
|
||||||
})
|
|
||||||
|
|
||||||
zeroRewardState := reward_spec.ConstructState(big_spec.Zero())
|
|
||||||
zeroRewardState.ThisEpochReward = big_spec.NewInt(1e17)
|
|
||||||
|
|
||||||
actors = append(actors, ActorState{
|
|
||||||
Addr: builtin_spec.RewardActorAddr,
|
|
||||||
Balance: TotalNetworkBalance,
|
|
||||||
Code: builtin_spec.RewardActorCodeID,
|
|
||||||
State: zeroRewardState,
|
|
||||||
})
|
|
||||||
|
|
||||||
actors = append(actors, ActorState{
|
|
||||||
Addr: builtin_spec.BurntFundsActorAddr,
|
|
||||||
Balance: big_spec.Zero(),
|
|
||||||
Code: builtin_spec.AccountActorCodeID,
|
|
||||||
State: &account_spec.State{Address: builtin_spec.BurntFundsActorAddr},
|
|
||||||
})
|
|
||||||
|
|
||||||
actors = append(actors, ActorState{
|
|
||||||
Addr: builtin_spec.StoragePowerActorAddr,
|
|
||||||
Balance: big_spec.Zero(),
|
|
||||||
Code: builtin_spec.StoragePowerActorCodeID,
|
|
||||||
State: power_spec.ConstructState(EmptyMapCid, EmptyMultiMapCid),
|
|
||||||
})
|
|
||||||
|
|
||||||
actors = append(actors, 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,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
actors = append(actors, ActorState{
|
|
||||||
Addr: builtin_spec.SystemActorAddr,
|
|
||||||
Balance: big_spec.Zero(),
|
|
||||||
Code: builtin_spec.SystemActorCodeID,
|
|
||||||
State: &system.State{},
|
|
||||||
})
|
|
||||||
|
|
||||||
actors = append(actors, 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,
|
|
||||||
},
|
|
||||||
}},
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, act := range actors {
|
|
||||||
_ = b.Actors.CreateActor(act.Code, act.Addr, act.Balance, act.State)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func insertEmptyStructures(store adt_spec.Store) error {
|
|
||||||
var err error
|
|
||||||
_, err = store.Put(context.TODO(), []struct{}{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
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.ConstructDeadline(EmptyArrayCid))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
emptyBitfield := bitfield.NewFromSet(nil)
|
|
||||||
EmptyBitfieldCid, err = store.Put(context.TODO(), emptyBitfield)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
EmptyVestingFundsCid, err = store.Put(context.Background(), miner.ConstructVestingFunds())
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
package builders
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"math/rand"
|
|
||||||
|
|
||||||
"github.com/minio/blake2b-simd"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/go-crypto"
|
|
||||||
acrypto "github.com/filecoin-project/specs-actors/actors/crypto"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/wallet"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/lotus/chain/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Wallet struct {
|
|
||||||
// Private keys by address
|
|
||||||
keys map[address.Address]*wallet.Key
|
|
||||||
|
|
||||||
// Seed for deterministic secp key generation.
|
|
||||||
secpSeed int64
|
|
||||||
// Seed for deterministic bls key generation.
|
|
||||||
blsSeed int64 // nolint: structcheck
|
|
||||||
}
|
|
||||||
|
|
||||||
func newWallet() *Wallet {
|
|
||||||
return &Wallet{
|
|
||||||
keys: make(map[address.Address]*wallet.Key),
|
|
||||||
secpSeed: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Wallet) NewSECP256k1Account() address.Address {
|
|
||||||
secpKey := w.newSecp256k1Key()
|
|
||||||
w.keys[secpKey.Address] = secpKey
|
|
||||||
return secpKey.Address
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Wallet) NewBLSAccount() address.Address {
|
|
||||||
blsKey := w.newBLSKey()
|
|
||||||
w.keys[blsKey.Address] = blsKey
|
|
||||||
return blsKey.Address
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Wallet) Sign(addr address.Address, data []byte) (acrypto.Signature, error) {
|
|
||||||
ki, ok := w.keys[addr]
|
|
||||||
if !ok {
|
|
||||||
return acrypto.Signature{}, fmt.Errorf("unknown address %v", addr)
|
|
||||||
}
|
|
||||||
var sigType acrypto.SigType
|
|
||||||
if ki.Type == wallet.KTSecp256k1 {
|
|
||||||
sigType = acrypto.SigTypeBLS
|
|
||||||
hashed := blake2b.Sum256(data)
|
|
||||||
sig, err := crypto.Sign(ki.PrivateKey, hashed[:])
|
|
||||||
if err != nil {
|
|
||||||
return acrypto.Signature{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return acrypto.Signature{
|
|
||||||
Type: sigType,
|
|
||||||
Data: sig,
|
|
||||||
}, nil
|
|
||||||
} else if ki.Type == wallet.KTBLS {
|
|
||||||
panic("lotus validator cannot sign BLS messages")
|
|
||||||
} else {
|
|
||||||
panic("unknown signature type")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Wallet) newSecp256k1Key() *wallet.Key {
|
|
||||||
randSrc := rand.New(rand.NewSource(w.secpSeed))
|
|
||||||
prv, err := crypto.GenerateKeyFromSeed(randSrc)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
w.secpSeed++
|
|
||||||
key, err := wallet.NewKey(types.KeyInfo{
|
|
||||||
Type: wallet.KTSecp256k1,
|
|
||||||
PrivateKey: prv,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return key
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Wallet) newBLSKey() *wallet.Key {
|
|
||||||
// FIXME: bls needs deterministic key generation
|
|
||||||
//sk := ffi.PrivateKeyGenerate(s.blsSeed)
|
|
||||||
// s.blsSeed++
|
|
||||||
sk := [32]byte{}
|
|
||||||
sk[0] = uint8(w.blsSeed) // hack to keep gas values determinist
|
|
||||||
w.blsSeed++
|
|
||||||
key, err := wallet.NewKey(types.KeyInfo{
|
|
||||||
Type: wallet.KTBLS,
|
|
||||||
PrivateKey: sk[:],
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return key
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
)
|
|
||||||
|
|
||||||
func sequentialAddresses(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
initial := big.NewInt(1_000_000_000_000_000)
|
|
||||||
|
|
||||||
// Set up sender and receiver accounts.
|
|
||||||
var sender, receiver AddressHandle
|
|
||||||
v.Actors.AccountN(address.SECP256K1, initial, &sender, &receiver)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// Create 10 payment channels.
|
|
||||||
for i := uint64(0); i < 10; i++ {
|
|
||||||
v.Messages.Sugar().CreatePaychActor(sender.Robust, receiver.Robust, Value(big.NewInt(1000)), Nonce(i))
|
|
||||||
}
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
for i, am := range v.Messages.All() {
|
|
||||||
expectedActorAddr := AddressHandle{
|
|
||||||
ID: MustNewIDAddr(MustIDFromAddress(receiver.ID) + uint64(i) + 1),
|
|
||||||
Robust: sender.NextActorAddress(am.Message.Nonce, 0),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify that the return contains the expected addresses.
|
|
||||||
var ret init_.ExecReturn
|
|
||||||
MustDeserialize(am.Result.Return, &ret)
|
|
||||||
v.Assert.Equal(expectedActorAddr.Robust, ret.RobustAddress)
|
|
||||||
v.Assert.Equal(expectedActorAddr.ID, ret.IDAddress)
|
|
||||||
}
|
|
||||||
|
|
||||||
v.Assert.EveryMessageSenderSatisfies(BalanceUpdated(big.Zero()))
|
|
||||||
v.Assert.EveryMessageSenderSatisfies(NonceUpdated())
|
|
||||||
}
|
|
@ -1,82 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
"github.com/filecoin-project/oni/tvx/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
g := NewGenerator()
|
|
||||||
|
|
||||||
g.MessageVectorGroup("addresses",
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "sequential-10",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "actor addresses are sequential",
|
|
||||||
},
|
|
||||||
Func: sequentialAddresses,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
g.MessageVectorGroup("on_transfer",
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok-create-secp256k1",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
Func: actorCreationOnTransfer(actorCreationOnTransferParams{
|
|
||||||
senderType: address.SECP256K1,
|
|
||||||
senderBal: abi.NewTokenAmount(1_000_000_000_000_000),
|
|
||||||
receiverAddr: MustNewSECP256K1Addr("publickeyfoo"),
|
|
||||||
amount: abi.NewTokenAmount(10_000),
|
|
||||||
exitCode: exitcode.Ok,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok-create-bls",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
Func: actorCreationOnTransfer(actorCreationOnTransferParams{
|
|
||||||
senderType: address.SECP256K1,
|
|
||||||
senderBal: abi.NewTokenAmount(1_000_000_000_000_000),
|
|
||||||
receiverAddr: MustNewBLSAddr(1),
|
|
||||||
amount: abi.NewTokenAmount(10_000),
|
|
||||||
exitCode: exitcode.Ok,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-secp256k1-insufficient-balance",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
Func: actorCreationOnTransfer(actorCreationOnTransferParams{
|
|
||||||
senderType: address.SECP256K1,
|
|
||||||
senderBal: abi.NewTokenAmount(9_999),
|
|
||||||
receiverAddr: MustNewSECP256K1Addr("publickeyfoo"),
|
|
||||||
amount: abi.NewTokenAmount(10_000),
|
|
||||||
exitCode: exitcode.SysErrSenderStateInvalid,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-bls-insufficient-balance",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
Func: actorCreationOnTransfer(actorCreationOnTransferParams{
|
|
||||||
senderType: address.SECP256K1,
|
|
||||||
senderBal: abi.NewTokenAmount(9_999),
|
|
||||||
receiverAddr: MustNewBLSAddr(1),
|
|
||||||
amount: abi.NewTokenAmount(10_000),
|
|
||||||
exitCode: exitcode.SysErrSenderStateInvalid,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
g.Wait()
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
)
|
|
||||||
|
|
||||||
type actorCreationOnTransferParams struct {
|
|
||||||
senderType address.Protocol
|
|
||||||
senderBal abi.TokenAmount
|
|
||||||
receiverAddr address.Address
|
|
||||||
amount abi.TokenAmount
|
|
||||||
exitCode exitcode.ExitCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func actorCreationOnTransfer(params actorCreationOnTransferParams) func(v *Builder) {
|
|
||||||
return func(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
// Set up sender account.
|
|
||||||
sender := v.Actors.Account(params.senderType, params.senderBal)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// Perform the transfer.
|
|
||||||
v.Messages.Sugar().Transfer(sender.ID, params.receiverAddr, Value(params.amount), Nonce(0))
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(params.exitCode))
|
|
||||||
v.Assert.EveryMessageSenderSatisfies(BalanceUpdated(big.Zero()))
|
|
||||||
|
|
||||||
if params.exitCode.IsSuccess() {
|
|
||||||
v.Assert.EveryMessageSenderSatisfies(NonceUpdated())
|
|
||||||
v.Assert.BalanceEq(params.receiverAddr, params.amount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
)
|
|
||||||
|
|
||||||
func failActorExecutionAborted(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
// Set up sender and receiver accounts.
|
|
||||||
var sender, receiver AddressHandle
|
|
||||||
var paychAddr AddressHandle
|
|
||||||
|
|
||||||
v.Actors.AccountN(address.SECP256K1, balance1T, &sender, &receiver)
|
|
||||||
paychAddr = AddressHandle{
|
|
||||||
ID: MustNewIDAddr(MustIDFromAddress(receiver.ID) + 1),
|
|
||||||
Robust: sender.NextActorAddress(0, 0),
|
|
||||||
}
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// Construct the payment channel.
|
|
||||||
createMsg := v.Messages.Sugar().CreatePaychActor(sender.Robust, receiver.Robust, Value(abi.NewTokenAmount(10_000)))
|
|
||||||
|
|
||||||
// Update the payment channel.
|
|
||||||
updateMsg := v.Messages.Typed(sender.Robust, paychAddr.Robust, PaychUpdateChannelState(&paych.UpdateChannelStateParams{
|
|
||||||
Sv: paych.SignedVoucher{
|
|
||||||
ChannelAddr: paychAddr.Robust,
|
|
||||||
TimeLockMin: abi.ChainEpoch(10),
|
|
||||||
Lane: 123,
|
|
||||||
Nonce: 1,
|
|
||||||
Amount: big.NewInt(10),
|
|
||||||
Signature: &crypto.Signature{
|
|
||||||
Type: crypto.SigTypeBLS,
|
|
||||||
Data: []byte("Grrr im an invalid signature, I cause panics in the payment channel actor"),
|
|
||||||
},
|
|
||||||
}}), Nonce(1), Value(big.Zero()))
|
|
||||||
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.Equal(exitcode.Ok, createMsg.Result.ExitCode)
|
|
||||||
v.Assert.Equal(exitcode.ErrIllegalArgument, updateMsg.Result.ExitCode)
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
)
|
|
||||||
|
|
||||||
func failCoverReceiptGasCost(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
v.Messages.Sugar().Transfer(alice.ID, alice.ID, Value(transferAmnt), Nonce(0), GasPremium(1), GasLimit(8))
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrOutOfGas))
|
|
||||||
}
|
|
||||||
|
|
||||||
func failCoverOnChainSizeGasCost(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
v.Messages.Sugar().Transfer(alice.ID, alice.ID, Value(transferAmnt), Nonce(0), GasPremium(10), GasLimit(1))
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrOutOfGas))
|
|
||||||
}
|
|
||||||
|
|
||||||
func failCoverTransferAccountCreationGasStepwise(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
var alice, bob, charlie AddressHandle
|
|
||||||
alice = v.Actors.Account(address.SECP256K1, balance1T)
|
|
||||||
bob.Robust, charlie.Robust = MustNewSECP256K1Addr("1"), MustNewSECP256K1Addr("2")
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
var nonce uint64
|
|
||||||
ref := v.Messages.Sugar().Transfer(alice.Robust, bob.Robust, Value(transferAmnt), Nonce(nonce))
|
|
||||||
nonce++
|
|
||||||
v.Messages.ApplyOne(ref)
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.Ok))
|
|
||||||
|
|
||||||
// decrease the gas cost by `gasStep` for each apply and ensure `SysErrOutOfGas` is always returned.
|
|
||||||
trueGas := ref.Result.GasUsed
|
|
||||||
gasStep := trueGas / 100
|
|
||||||
for tryGas := trueGas - gasStep; tryGas > 0; tryGas -= gasStep {
|
|
||||||
v.Messages.Sugar().Transfer(alice.Robust, charlie.Robust, Value(transferAmnt), Nonce(nonce), GasPremium(1), GasLimit(tryGas))
|
|
||||||
nonce++
|
|
||||||
}
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrOutOfGas), ref)
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
)
|
|
||||||
|
|
||||||
func failInvalidActorNonce(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// invalid nonce from known account.
|
|
||||||
msg1 := v.Messages.Sugar().Transfer(alice.ID, alice.ID, Value(transferAmnt), Nonce(1))
|
|
||||||
|
|
||||||
// invalid nonce from an unknown account.
|
|
||||||
msg2 := v.Messages.Sugar().Transfer(unknown, alice.ID, Value(transferAmnt), Nonce(1))
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.Equal(msg1.Result.ExitCode, exitcode.SysErrSenderStateInvalid)
|
|
||||||
v.Assert.Equal(msg2.Result.ExitCode, exitcode.SysErrSenderInvalid)
|
|
||||||
}
|
|
||||||
|
|
||||||
func failInvalidReceiverMethod(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
v.Messages.Typed(alice.ID, alice.ID, MarketComputeDataCommitment(nil), Nonce(0), Value(big.Zero()))
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrInvalidMethod))
|
|
||||||
}
|
|
@ -1,98 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
"github.com/filecoin-project/oni/tvx/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
unknown = MustNewIDAddr(10000000)
|
|
||||||
balance1T = abi.NewTokenAmount(1_000_000_000_000)
|
|
||||||
transferAmnt = abi.NewTokenAmount(10)
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
g := NewGenerator()
|
|
||||||
|
|
||||||
g.MessageVectorGroup("gas_cost",
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "msg-apply-fail-receipt-gas",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "fail to cover gas cost for message receipt on chain",
|
|
||||||
},
|
|
||||||
Func: failCoverReceiptGasCost,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "msg-apply-fail-onchainsize-gas",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "not enough gas to pay message on-chain-size cost",
|
|
||||||
},
|
|
||||||
Func: failCoverOnChainSizeGasCost,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "msg-apply-fail-transfer-accountcreation-gas",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "fail not enough gas to cover account actor creation on transfer",
|
|
||||||
},
|
|
||||||
Func: failCoverTransferAccountCreationGasStepwise,
|
|
||||||
})
|
|
||||||
|
|
||||||
g.MessageVectorGroup("invalid_msgs",
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "msg-apply-fail-invalid-nonce",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "invalid actor nonce",
|
|
||||||
},
|
|
||||||
Func: failInvalidActorNonce,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "msg-apply-fail-invalid-receiver-method",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "invalid receiver method",
|
|
||||||
},
|
|
||||||
Func: failInvalidReceiverMethod,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
g.MessageVectorGroup("unknown_actors",
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "msg-apply-fail-unknown-sender",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "fail due to lack of gas when sender is unknown",
|
|
||||||
},
|
|
||||||
Func: failUnknownSender,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "msg-apply-fail-unknown-receiver",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "inexistent receiver",
|
|
||||||
Comment: `Note that this test is not a valid message, since it is using
|
|
||||||
an unknown actor. However in the event that an invalid message isn't filtered by
|
|
||||||
block validation we need to ensure behaviour is consistent across VM implementations.`,
|
|
||||||
},
|
|
||||||
Func: failUnknownReceiver,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
g.MessageVectorGroup("actor_exec",
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "msg-apply-fail-actor-execution-illegal-arg",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "abort during actor execution due to illegal argument",
|
|
||||||
},
|
|
||||||
Func: failActorExecutionAborted,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
g.Wait()
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
)
|
|
||||||
|
|
||||||
func failUnknownSender(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
v.Messages.Sugar().Transfer(unknown, alice.ID, Value(transferAmnt), Nonce(0))
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrSenderInvalid))
|
|
||||||
}
|
|
||||||
|
|
||||||
func failUnknownReceiver(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
alice := v.Actors.Account(address.SECP256K1, balance1T)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// Sending a message to non-existent ID address must produce an error.
|
|
||||||
unknownID := MustNewIDAddr(10000000)
|
|
||||||
v.Messages.Sugar().Transfer(alice.ID, unknownID, Value(transferAmnt), Nonce(0))
|
|
||||||
|
|
||||||
unknownActor := MustNewActorAddr("1234")
|
|
||||||
v.Messages.Sugar().Transfer(alice.ID, unknownActor, Value(transferAmnt), Nonce(1))
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrInvalidReceiver))
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
"github.com/filecoin-project/oni/tvx/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
gasLimit = 1_000_000_000
|
|
||||||
gasFeeCap = 200
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
g := NewGenerator()
|
|
||||||
defer g.Wait()
|
|
||||||
|
|
||||||
g.MessageVectorGroup("basic",
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok-create",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "multisig actor constructor ok",
|
|
||||||
},
|
|
||||||
Func: constructor,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok-propose-and-cancel",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "multisig actor propose and cancel ok",
|
|
||||||
},
|
|
||||||
Func: proposeAndCancelOk,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok-propose-and-approve",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "multisig actor propose, unauthorized proposals+approval, and approval ok",
|
|
||||||
},
|
|
||||||
Func: proposeAndApprove,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok-add-signer",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "multisig actor accepts only AddSigner messages that go through a reflexive flow",
|
|
||||||
},
|
|
||||||
Func: addSigner,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,305 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/minio/blake2b-simd"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
)
|
|
||||||
|
|
||||||
func constructor(v *Builder) {
|
|
||||||
var balance = abi.NewTokenAmount(1_000_000_000_000)
|
|
||||||
var amount = abi.NewTokenAmount(10)
|
|
||||||
|
|
||||||
v.Messages.SetDefaults(GasLimit(gasLimit), GasPremium(1), GasFeeCap(gasFeeCap))
|
|
||||||
|
|
||||||
// Set up one account.
|
|
||||||
alice := v.Actors.Account(address.SECP256K1, balance)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
createMultisig(v, alice, []address.Address{alice.ID}, 1, Value(amount), Nonce(0))
|
|
||||||
v.CommitApplies()
|
|
||||||
}
|
|
||||||
|
|
||||||
func proposeAndCancelOk(v *Builder) {
|
|
||||||
var (
|
|
||||||
initial = abi.NewTokenAmount(1_000_000_000_000)
|
|
||||||
amount = abi.NewTokenAmount(10)
|
|
||||||
unlockDuration = abi.ChainEpoch(10)
|
|
||||||
)
|
|
||||||
|
|
||||||
v.Messages.SetDefaults(Value(big.Zero()), Epoch(1), GasLimit(gasLimit), GasPremium(1), GasFeeCap(gasFeeCap))
|
|
||||||
|
|
||||||
// Set up three accounts: alice and bob (signers), and charlie (outsider).
|
|
||||||
var alice, bob, charlie AddressHandle
|
|
||||||
v.Actors.AccountN(address.SECP256K1, initial, &alice, &bob, &charlie)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// create the multisig actor; created by alice.
|
|
||||||
multisigAddr := createMultisig(v, alice, []address.Address{alice.ID, bob.ID}, 2, Value(amount), Nonce(0))
|
|
||||||
|
|
||||||
// alice proposes that charlie should receive 'amount' FIL.
|
|
||||||
hash := proposeOk(v, proposeOpts{
|
|
||||||
multisigAddr: multisigAddr,
|
|
||||||
sender: alice.ID,
|
|
||||||
recipient: charlie.ID,
|
|
||||||
amount: amount,
|
|
||||||
}, Nonce(1))
|
|
||||||
|
|
||||||
// bob cancels alice's transaction. This fails as bob did not create alice's transaction.
|
|
||||||
bobCancelMsg := v.Messages.Typed(bob.ID, multisigAddr, MultisigCancel(&multisig.TxnIDParams{
|
|
||||||
ID: multisig.TxnID(0),
|
|
||||||
ProposalHash: hash,
|
|
||||||
}), Nonce(0))
|
|
||||||
v.Messages.ApplyOne(bobCancelMsg)
|
|
||||||
v.Assert.Equal(bobCancelMsg.Result.ExitCode, exitcode.ErrForbidden)
|
|
||||||
|
|
||||||
// alice cancels their transaction; charlie doesn't receive any FIL,
|
|
||||||
// the multisig actor's balance is empty, and the transaction is canceled.
|
|
||||||
aliceCancelMsg := v.Messages.Typed(alice.ID, multisigAddr, MultisigCancel(&multisig.TxnIDParams{
|
|
||||||
ID: multisig.TxnID(0),
|
|
||||||
ProposalHash: hash,
|
|
||||||
}), Nonce(2))
|
|
||||||
v.Messages.ApplyOne(aliceCancelMsg)
|
|
||||||
v.Assert.Equal(exitcode.Ok, aliceCancelMsg.Result.ExitCode)
|
|
||||||
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
// verify balance is untouched.
|
|
||||||
v.Assert.BalanceEq(multisigAddr, amount)
|
|
||||||
|
|
||||||
// reload the multisig state and verify
|
|
||||||
var multisigState multisig.State
|
|
||||||
v.Actors.ActorState(multisigAddr, &multisigState)
|
|
||||||
v.Assert.Equal(&multisig.State{
|
|
||||||
Signers: []address.Address{alice.ID, bob.ID},
|
|
||||||
NumApprovalsThreshold: 2,
|
|
||||||
NextTxnID: 1,
|
|
||||||
InitialBalance: amount,
|
|
||||||
StartEpoch: 1,
|
|
||||||
UnlockDuration: unlockDuration,
|
|
||||||
PendingTxns: EmptyMapCid,
|
|
||||||
}, &multisigState)
|
|
||||||
}
|
|
||||||
|
|
||||||
func proposeAndApprove(v *Builder) {
|
|
||||||
var (
|
|
||||||
initial = abi.NewTokenAmount(1_000_000_000_000)
|
|
||||||
amount = abi.NewTokenAmount(10)
|
|
||||||
unlockDuration = abi.ChainEpoch(10)
|
|
||||||
)
|
|
||||||
|
|
||||||
v.Messages.SetDefaults(Value(big.Zero()), Epoch(1), GasLimit(gasLimit), GasPremium(1), GasFeeCap(gasFeeCap))
|
|
||||||
|
|
||||||
// Set up three accounts: alice and bob (signers), and charlie (outsider).
|
|
||||||
var alice, bob, charlie AddressHandle
|
|
||||||
v.Actors.AccountN(address.SECP256K1, initial, &alice, &bob, &charlie)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// create the multisig actor; created by alice.
|
|
||||||
multisigAddr := createMultisig(v, alice, []address.Address{alice.ID, bob.ID}, 2, Value(amount), Nonce(0))
|
|
||||||
|
|
||||||
// alice proposes that charlie should receive 'amount' FIL.
|
|
||||||
hash := proposeOk(v, proposeOpts{
|
|
||||||
multisigAddr: multisigAddr,
|
|
||||||
sender: alice.ID,
|
|
||||||
recipient: charlie.ID,
|
|
||||||
amount: amount,
|
|
||||||
}, Nonce(1))
|
|
||||||
|
|
||||||
// charlie proposes himself -> fails.
|
|
||||||
charliePropose := v.Messages.Typed(charlie.ID, multisigAddr,
|
|
||||||
MultisigPropose(&multisig.ProposeParams{
|
|
||||||
To: charlie.ID,
|
|
||||||
Value: amount,
|
|
||||||
Method: builtin.MethodSend,
|
|
||||||
Params: nil,
|
|
||||||
}), Nonce(0))
|
|
||||||
v.Messages.ApplyOne(charliePropose)
|
|
||||||
v.Assert.Equal(exitcode.ErrForbidden, charliePropose.Result.ExitCode)
|
|
||||||
|
|
||||||
// charlie attempts to accept the pending transaction -> fails.
|
|
||||||
charlieApprove := v.Messages.Typed(charlie.ID, multisigAddr,
|
|
||||||
MultisigApprove(&multisig.TxnIDParams{
|
|
||||||
ID: multisig.TxnID(0),
|
|
||||||
ProposalHash: hash,
|
|
||||||
}), Nonce(1))
|
|
||||||
v.Messages.ApplyOne(charlieApprove)
|
|
||||||
v.Assert.Equal(exitcode.ErrForbidden, charlieApprove.Result.ExitCode)
|
|
||||||
|
|
||||||
// bob approves transfer of 'amount' FIL to charlie.
|
|
||||||
// epoch is unlockDuration + 1
|
|
||||||
bobApprove := v.Messages.Typed(bob.ID, multisigAddr,
|
|
||||||
MultisigApprove(&multisig.TxnIDParams{
|
|
||||||
ID: multisig.TxnID(0),
|
|
||||||
ProposalHash: hash,
|
|
||||||
}), Nonce(0), Epoch(unlockDuration+1))
|
|
||||||
v.Messages.ApplyOne(bobApprove)
|
|
||||||
v.Assert.Equal(exitcode.Ok, bobApprove.Result.ExitCode)
|
|
||||||
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
var approveRet multisig.ApproveReturn
|
|
||||||
MustDeserialize(bobApprove.Result.Return, &approveRet)
|
|
||||||
v.Assert.Equal(multisig.ApproveReturn{
|
|
||||||
Applied: true,
|
|
||||||
Code: 0,
|
|
||||||
Ret: nil,
|
|
||||||
}, approveRet)
|
|
||||||
|
|
||||||
// assert that the multisig balance has been drained, and charlie's incremented.
|
|
||||||
v.Assert.BalanceEq(multisigAddr, big.Zero())
|
|
||||||
v.Assert.MessageSendersSatisfy(BalanceUpdated(amount), charliePropose, charlieApprove)
|
|
||||||
|
|
||||||
// reload the multisig state and verify
|
|
||||||
var multisigState multisig.State
|
|
||||||
v.Actors.ActorState(multisigAddr, &multisigState)
|
|
||||||
v.Assert.Equal(&multisig.State{
|
|
||||||
Signers: []address.Address{alice.ID, bob.ID},
|
|
||||||
NumApprovalsThreshold: 2,
|
|
||||||
NextTxnID: 1,
|
|
||||||
InitialBalance: amount,
|
|
||||||
StartEpoch: 1,
|
|
||||||
UnlockDuration: unlockDuration,
|
|
||||||
PendingTxns: EmptyMapCid,
|
|
||||||
}, &multisigState)
|
|
||||||
}
|
|
||||||
|
|
||||||
func addSigner(v *Builder) {
|
|
||||||
var (
|
|
||||||
initial = abi.NewTokenAmount(1_000_000_000_000)
|
|
||||||
amount = abi.NewTokenAmount(10)
|
|
||||||
)
|
|
||||||
|
|
||||||
v.Messages.SetDefaults(Value(big.Zero()), Epoch(1), GasLimit(gasLimit), GasPremium(1), GasFeeCap(gasFeeCap))
|
|
||||||
|
|
||||||
// Set up three accounts: alice and bob (signers), and charlie (outsider).
|
|
||||||
var alice, bob, charlie AddressHandle
|
|
||||||
v.Actors.AccountN(address.SECP256K1, initial, &alice, &bob, &charlie)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// create the multisig actor; created by alice.
|
|
||||||
multisigAddr := createMultisig(v, alice, []address.Address{alice.ID}, 1, Value(amount), Nonce(0))
|
|
||||||
|
|
||||||
addParams := &multisig.AddSignerParams{
|
|
||||||
Signer: bob.ID,
|
|
||||||
Increase: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
// attempt to add bob as a signer; this fails because the addition needs to go through
|
|
||||||
// the multisig flow, as it is subject to the same approval policy.
|
|
||||||
v.Messages.Typed(alice.ID, multisigAddr, MultisigAddSigner(addParams), Nonce(1))
|
|
||||||
|
|
||||||
// go through the multisig wallet.
|
|
||||||
// since approvals = 1, this auto-approves the transaction.
|
|
||||||
v.Messages.Typed(alice.ID, multisigAddr, MultisigPropose(&multisig.ProposeParams{
|
|
||||||
To: multisigAddr,
|
|
||||||
Value: big.Zero(),
|
|
||||||
Method: builtin.MethodsMultisig.AddSigner,
|
|
||||||
Params: MustSerialize(addParams),
|
|
||||||
}), Nonce(2))
|
|
||||||
|
|
||||||
// TODO also exercise the approvals = 2 case with explicit approval.
|
|
||||||
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
// reload the multisig state and verify that bob is now a signer.
|
|
||||||
var multisigState multisig.State
|
|
||||||
v.Actors.ActorState(multisigAddr, &multisigState)
|
|
||||||
v.Assert.Equal(&multisig.State{
|
|
||||||
Signers: []address.Address{alice.ID, bob.ID},
|
|
||||||
NumApprovalsThreshold: 1,
|
|
||||||
NextTxnID: 1,
|
|
||||||
InitialBalance: amount,
|
|
||||||
StartEpoch: 1,
|
|
||||||
UnlockDuration: 10,
|
|
||||||
PendingTxns: EmptyMapCid,
|
|
||||||
}, &multisigState)
|
|
||||||
}
|
|
||||||
|
|
||||||
type proposeOpts struct {
|
|
||||||
multisigAddr address.Address
|
|
||||||
sender address.Address
|
|
||||||
recipient address.Address
|
|
||||||
amount abi.TokenAmount
|
|
||||||
}
|
|
||||||
|
|
||||||
func proposeOk(v *Builder, proposeOpts proposeOpts, opts ...MsgOpt) []byte {
|
|
||||||
propose := &multisig.ProposeParams{
|
|
||||||
To: proposeOpts.recipient,
|
|
||||||
Value: proposeOpts.amount,
|
|
||||||
Method: builtin.MethodSend,
|
|
||||||
Params: nil,
|
|
||||||
}
|
|
||||||
proposeMsg := v.Messages.Typed(proposeOpts.sender, proposeOpts.multisigAddr, MultisigPropose(propose), opts...)
|
|
||||||
|
|
||||||
v.Messages.ApplyOne(proposeMsg)
|
|
||||||
|
|
||||||
// verify that the multisig state contains the outstanding TX.
|
|
||||||
var multisigState multisig.State
|
|
||||||
v.Actors.ActorState(proposeOpts.multisigAddr, &multisigState)
|
|
||||||
|
|
||||||
id := multisig.TxnID(0)
|
|
||||||
actualTxn := loadMultisigTxn(v, multisigState, id)
|
|
||||||
v.Assert.Equal(&multisig.Transaction{
|
|
||||||
To: propose.To,
|
|
||||||
Value: propose.Value,
|
|
||||||
Method: propose.Method,
|
|
||||||
Params: propose.Params,
|
|
||||||
Approved: []address.Address{proposeOpts.sender},
|
|
||||||
}, actualTxn)
|
|
||||||
|
|
||||||
return makeProposalHash(v, actualTxn)
|
|
||||||
}
|
|
||||||
|
|
||||||
func createMultisig(v *Builder, creator AddressHandle, approvers []address.Address, threshold uint64, opts ...MsgOpt) address.Address {
|
|
||||||
const unlockDuration = abi.ChainEpoch(10)
|
|
||||||
// create the multisig actor.
|
|
||||||
params := &multisig.ConstructorParams{
|
|
||||||
Signers: approvers,
|
|
||||||
NumApprovalsThreshold: threshold,
|
|
||||||
UnlockDuration: unlockDuration,
|
|
||||||
}
|
|
||||||
msg := v.Messages.Sugar().CreateMultisigActor(creator.ID, params, opts...)
|
|
||||||
v.Messages.ApplyOne(msg)
|
|
||||||
|
|
||||||
// verify ok
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.Ok))
|
|
||||||
|
|
||||||
// verify the assigned addess is as expected.
|
|
||||||
var ret init_.ExecReturn
|
|
||||||
MustDeserialize(msg.Result.Return, &ret)
|
|
||||||
v.Assert.Equal(creator.NextActorAddress(msg.Message.Nonce, 0), ret.RobustAddress)
|
|
||||||
handles := v.Actors.Handles()
|
|
||||||
v.Assert.Equal(MustNewIDAddr(MustIDFromAddress(handles[len(handles)-1].ID)+1), ret.IDAddress)
|
|
||||||
|
|
||||||
// the multisig address's balance is incremented by the value sent to it.
|
|
||||||
v.Assert.BalanceEq(ret.IDAddress, msg.Message.Value)
|
|
||||||
|
|
||||||
return ret.IDAddress
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadMultisigTxn(v *Builder, state multisig.State, id multisig.TxnID) *multisig.Transaction {
|
|
||||||
pending, err := adt.AsMap(v.Stores.ADTStore, state.PendingTxns)
|
|
||||||
v.Assert.NoError(err)
|
|
||||||
|
|
||||||
var actualTxn multisig.Transaction
|
|
||||||
found, err := pending.Get(id, &actualTxn)
|
|
||||||
v.Assert.True(found)
|
|
||||||
v.Assert.NoError(err)
|
|
||||||
return &actualTxn
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeProposalHash(v *Builder, txn *multisig.Transaction) []byte {
|
|
||||||
ret, err := multisig.ComputeProposalHash(txn, blake2b.Sum256)
|
|
||||||
v.Assert.NoError(err)
|
|
||||||
return ret
|
|
||||||
}
|
|
@ -1,127 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
"github.com/filecoin-project/oni/tvx/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
g := NewGenerator()
|
|
||||||
|
|
||||||
g.MessageVectorGroup("nested_sends",
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok-basic",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_OkBasic,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok-to-new-actor",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_OkToNewActor,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok-to-new-actor-with-invoke",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_OkToNewActorWithInvoke,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok-recursive",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_OkRecursive,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok-non-cbor-params-with-transfer",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_OKNonCBORParamsWithTransfer,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-non-existent-id-address",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_FailNonexistentIDAddress,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-non-existent-actor-address",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_FailNonexistentActorAddress,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-invalid-method-num-new-actor",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_FailInvalidMethodNumNewActor,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-invalid-method-num-for-actor",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_FailInvalidMethodNumForActor,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-missing-params",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_FailMissingParams,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-mismatch-params",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_FailMismatchParams,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-inner-abort",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_FailInnerAbort,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-aborted-exec",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_FailAbortedExec,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-insufficient-funds-for-transfer-in-inner-send",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: nestedSends_FailInsufficientFundsForTransferInInnerSend,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
g.Wait()
|
|
||||||
}
|
|
@ -1,358 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin"
|
|
||||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/multisig"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/reward"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/puppet"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
||||||
typegen "github.com/whyrusleeping/cbor-gen"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
acctDefaultBalance = abi.NewTokenAmount(1_000_000_000_000)
|
|
||||||
multisigBalance = abi.NewTokenAmount(1_000_000_000)
|
|
||||||
nonce = uint64(1)
|
|
||||||
PuppetAddress address.Address
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
var err error
|
|
||||||
// the address before the burnt funds address
|
|
||||||
PuppetAddress, err = address.NewIDAddress(builtin.FirstNonSingletonActorId - 2)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_OkBasic(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
balanceBefore := v.Actors.Balance(stage.creator)
|
|
||||||
|
|
||||||
// Multisig sends back to the creator.
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
result := stage.sendOk(stage.creator, amtSent, builtin.MethodSend, nil, nonce)
|
|
||||||
|
|
||||||
//td.AssertActor(stage.creator, big.Sub(big.Add(balanceBefore, amtSent), result.Result.Receipt.GasUsed.Big()), nonce+1)
|
|
||||||
v.Assert.NonceEq(stage.creator, nonce+1)
|
|
||||||
v.Assert.BalanceEq(stage.creator, big.Sub(big.Add(balanceBefore, amtSent), CalculateDeduction(result)))
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_OkToNewActor(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
balanceBefore := v.Actors.Balance(stage.creator)
|
|
||||||
|
|
||||||
// Multisig sends to new address.
|
|
||||||
newAddr := v.Wallet.NewSECP256k1Account()
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
result := stage.sendOk(newAddr, amtSent, builtin.MethodSend, nil, nonce)
|
|
||||||
|
|
||||||
v.Assert.BalanceEq(stage.msAddr, big.Sub(multisigBalance, amtSent))
|
|
||||||
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateDeduction(result)))
|
|
||||||
v.Assert.BalanceEq(newAddr, amtSent)
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_OkToNewActorWithInvoke(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
balanceBefore := v.Actors.Balance(stage.creator)
|
|
||||||
|
|
||||||
// Multisig sends to new address and invokes pubkey method at the same time.
|
|
||||||
newAddr := v.Wallet.NewSECP256k1Account()
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
result := stage.sendOk(newAddr, amtSent, builtin.MethodsAccount.PubkeyAddress, nil, nonce)
|
|
||||||
// TODO: use an explicit Approve() and check the return value is the correct pubkey address
|
|
||||||
// when the multisig Approve() method plumbs through the inner exit code and value.
|
|
||||||
// https://github.com/filecoin-project/specs-actors/issues/113
|
|
||||||
//expected := bytes.Buffer{}
|
|
||||||
//require.NoError(t, newAddr.MarshalCBOR(&expected))
|
|
||||||
//assert.Equal(t, expected.Bytes(), result.Result.Receipt.ReturnValue)
|
|
||||||
|
|
||||||
v.Assert.BalanceEq(stage.msAddr, big.Sub(multisigBalance, amtSent))
|
|
||||||
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateDeduction(result)))
|
|
||||||
v.Assert.BalanceEq(newAddr, amtSent)
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_OkRecursive(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
another := v.Actors.Account(address.SECP256K1, big.Zero())
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
balanceBefore := v.Actors.Balance(stage.creator)
|
|
||||||
|
|
||||||
// Multisig sends to itself.
|
|
||||||
params := multisig.AddSignerParams{
|
|
||||||
Signer: another.ID,
|
|
||||||
Increase: false,
|
|
||||||
}
|
|
||||||
result := stage.sendOk(stage.msAddr, big.Zero(), builtin.MethodsMultisig.AddSigner, ¶ms, nonce)
|
|
||||||
|
|
||||||
v.Assert.BalanceEq(stage.msAddr, multisigBalance)
|
|
||||||
v.Assert.Equal(big.Sub(balanceBefore, CalculateDeduction(result)), v.Actors.Balance(stage.creator))
|
|
||||||
|
|
||||||
var st multisig.State
|
|
||||||
v.Actors.ActorState(stage.msAddr, &st)
|
|
||||||
v.Assert.Equal([]address.Address{stage.creator, another.ID}, st.Signers)
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_OKNonCBORParamsWithTransfer(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
|
|
||||||
newAddr := v.Wallet.NewSECP256k1Account()
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
// So long as the parameters are not actually used by the method, a message can carry arbitrary bytes.
|
|
||||||
params := typegen.Deferred{Raw: []byte{1, 2, 3, 4}}
|
|
||||||
stage.sendOk(newAddr, amtSent, builtin.MethodSend, ¶ms, nonce)
|
|
||||||
|
|
||||||
v.Assert.BalanceEq(stage.msAddr, big.Sub(multisigBalance, amtSent))
|
|
||||||
v.Assert.BalanceEq(newAddr, amtSent)
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_FailNonexistentIDAddress(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
|
|
||||||
newAddr := MustNewIDAddr(1234)
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
stage.sendOk(newAddr, amtSent, builtin.MethodSend, nil, nonce)
|
|
||||||
|
|
||||||
v.Assert.BalanceEq(stage.msAddr, multisigBalance) // No change.
|
|
||||||
v.Assert.ActorMissing(newAddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_FailNonexistentActorAddress(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
|
|
||||||
newAddr := MustNewActorAddr("1234")
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
stage.sendOk(newAddr, amtSent, builtin.MethodSend, nil, nonce)
|
|
||||||
|
|
||||||
v.Assert.BalanceEq(stage.msAddr, multisigBalance) // No change.
|
|
||||||
v.Assert.ActorMissing(newAddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_FailInvalidMethodNumNewActor(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
|
|
||||||
newAddr := v.Wallet.NewSECP256k1Account()
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
stage.sendOk(newAddr, amtSent, abi.MethodNum(99), nil, nonce)
|
|
||||||
|
|
||||||
v.Assert.BalanceEq(stage.msAddr, multisigBalance) // No change.
|
|
||||||
v.Assert.ActorMissing(newAddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_FailInvalidMethodNumForActor(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
balanceBefore := v.Actors.Balance(stage.creator)
|
|
||||||
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
result := stage.sendOk(stage.creator, amtSent, abi.MethodNum(99), nil, nonce)
|
|
||||||
|
|
||||||
v.Assert.BalanceEq(stage.msAddr, multisigBalance) // No change.
|
|
||||||
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateDeduction(result))) // Pay gas, don't receive funds.
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_FailMissingParams(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
balanceBefore := v.Actors.Balance(stage.creator)
|
|
||||||
|
|
||||||
params := adt.Empty // Missing params required by AddSigner
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
result := stage.sendOk(stage.msAddr, amtSent, builtin.MethodsMultisig.AddSigner, params, nonce)
|
|
||||||
|
|
||||||
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateDeduction(result)))
|
|
||||||
v.Assert.BalanceEq(stage.msAddr, multisigBalance) // No change.
|
|
||||||
v.Assert.Equal(1, len(stage.state().Signers)) // No new signers
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_FailMismatchParams(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
balanceBefore := v.Actors.Balance(stage.creator)
|
|
||||||
|
|
||||||
// Wrong params for AddSigner
|
|
||||||
params := multisig.ProposeParams{
|
|
||||||
To: stage.creator,
|
|
||||||
Value: big.Zero(),
|
|
||||||
Method: builtin.MethodSend,
|
|
||||||
Params: nil,
|
|
||||||
}
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
result := stage.sendOk(stage.msAddr, amtSent, builtin.MethodsMultisig.AddSigner, ¶ms, nonce)
|
|
||||||
|
|
||||||
v.Assert.BalanceEq(stage.creator, big.Sub(balanceBefore, CalculateDeduction(result)))
|
|
||||||
v.Assert.BalanceEq(stage.msAddr, multisigBalance) // No change.
|
|
||||||
v.Assert.Equal(1, len(stage.state().Signers)) // No new signers
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_FailInnerAbort(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
prevHead := v.Actors.Head(builtin.RewardActorAddr)
|
|
||||||
|
|
||||||
// AwardBlockReward will abort unless invoked by the system actor
|
|
||||||
params := reward.AwardBlockRewardParams{
|
|
||||||
Miner: stage.creator,
|
|
||||||
Penalty: big.Zero(),
|
|
||||||
GasReward: big.Zero(),
|
|
||||||
}
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
stage.sendOk(builtin.RewardActorAddr, amtSent, builtin.MethodsReward.AwardBlockReward, ¶ms, nonce)
|
|
||||||
|
|
||||||
v.Assert.BalanceEq(stage.msAddr, multisigBalance) // No change.
|
|
||||||
v.Assert.HeadEq(builtin.RewardActorAddr, prevHead)
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_FailAbortedExec(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
stage := prepareStage(v, acctDefaultBalance, multisigBalance)
|
|
||||||
prevHead := v.Actors.Head(builtin.InitActorAddr)
|
|
||||||
|
|
||||||
// Illegal paych constructor params (addresses are not accounts)
|
|
||||||
ctorParams := paych.ConstructorParams{
|
|
||||||
From: builtin.SystemActorAddr,
|
|
||||||
To: builtin.SystemActorAddr,
|
|
||||||
}
|
|
||||||
execParams := init_.ExecParams{
|
|
||||||
CodeCID: builtin.PaymentChannelActorCodeID,
|
|
||||||
ConstructorParams: MustSerialize(&ctorParams),
|
|
||||||
}
|
|
||||||
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
stage.sendOk(builtin.InitActorAddr, amtSent, builtin.MethodsInit.Exec, &execParams, nonce)
|
|
||||||
|
|
||||||
v.Assert.BalanceEq(stage.msAddr, multisigBalance) // No change.
|
|
||||||
v.Assert.HeadEq(builtin.InitActorAddr, prevHead) // Init state unchanged.
|
|
||||||
}
|
|
||||||
|
|
||||||
func nestedSends_FailInsufficientFundsForTransferInInnerSend(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
// puppet actor has zero funds
|
|
||||||
puppetBalance := big.Zero()
|
|
||||||
_ = v.Actors.CreateActor(puppet.PuppetActorCodeID, PuppetAddress, puppetBalance, &puppet.State{})
|
|
||||||
|
|
||||||
alice := v.Actors.Account(address.SECP256K1, acctDefaultBalance)
|
|
||||||
bob := v.Actors.Account(address.SECP256K1, big.Zero())
|
|
||||||
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// alice tells the puppet actor to send funds to bob, the puppet actor has 0 balance so the inner send will fail,
|
|
||||||
// and alice will pay the gas cost.
|
|
||||||
amtSent := abi.NewTokenAmount(1)
|
|
||||||
msg := v.Messages.Typed(alice.ID, PuppetAddress, PuppetSend(&puppet.SendParams{
|
|
||||||
To: bob.ID,
|
|
||||||
Value: amtSent,
|
|
||||||
Method: builtin.MethodSend,
|
|
||||||
Params: nil,
|
|
||||||
}), Nonce(0), Value(big.Zero()))
|
|
||||||
|
|
||||||
v.Messages.ApplyOne(msg)
|
|
||||||
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
// the outer message should be applied successfully
|
|
||||||
v.Assert.Equal(exitcode.Ok, msg.Result.ExitCode)
|
|
||||||
|
|
||||||
var puppetRet puppet.SendReturn
|
|
||||||
MustDeserialize(msg.Result.MessageReceipt.Return, &puppetRet)
|
|
||||||
|
|
||||||
// the inner message should fail
|
|
||||||
v.Assert.Equal(exitcode.SysErrInsufficientFunds, puppetRet.Code)
|
|
||||||
|
|
||||||
// alice should be charged for the gas cost and bob should have not received any funds.
|
|
||||||
v.Assert.MessageSendersSatisfy(BalanceUpdated(big.Zero()), msg)
|
|
||||||
v.Assert.BalanceEq(bob.ID, big.Zero())
|
|
||||||
}
|
|
||||||
|
|
||||||
type msStage struct {
|
|
||||||
v *Builder
|
|
||||||
creator address.Address // Address of the creator and sole signer of the multisig.
|
|
||||||
msAddr address.Address // Address of the multisig actor from which nested messages are sent.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a multisig actor with its creator as sole approver.
|
|
||||||
func prepareStage(v *Builder, creatorBalance, msBalance abi.TokenAmount) *msStage {
|
|
||||||
// Set up sender and receiver accounts.
|
|
||||||
creator := v.Actors.Account(address.SECP256K1, creatorBalance)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
msg := v.Messages.Sugar().CreateMultisigActor(creator.ID, &multisig.ConstructorParams{
|
|
||||||
Signers: []address.Address{creator.ID},
|
|
||||||
NumApprovalsThreshold: 1,
|
|
||||||
UnlockDuration: 0,
|
|
||||||
}, Value(msBalance), Nonce(0))
|
|
||||||
v.Messages.ApplyOne(msg)
|
|
||||||
|
|
||||||
v.Assert.Equal(msg.Result.ExitCode, exitcode.Ok)
|
|
||||||
|
|
||||||
// Verify init actor return.
|
|
||||||
var ret init_.ExecReturn
|
|
||||||
MustDeserialize(msg.Result.Return, &ret)
|
|
||||||
|
|
||||||
return &msStage{
|
|
||||||
v: v,
|
|
||||||
creator: creator.ID,
|
|
||||||
msAddr: ret.IDAddress,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *msStage) sendOk(to address.Address, value abi.TokenAmount, method abi.MethodNum, params runtime.CBORMarshaler, approverNonce uint64) *ApplicableMessage {
|
|
||||||
buf := bytes.Buffer{}
|
|
||||||
if params != nil {
|
|
||||||
err := params.MarshalCBOR(&buf)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pparams := multisig.ProposeParams{
|
|
||||||
To: to,
|
|
||||||
Value: value,
|
|
||||||
Method: method,
|
|
||||||
Params: buf.Bytes(),
|
|
||||||
}
|
|
||||||
msg := s.v.Messages.Typed(s.creator, s.msAddr, MultisigPropose(&pparams), Nonce(approverNonce), Value(big.NewInt(0)))
|
|
||||||
s.v.CommitApplies()
|
|
||||||
|
|
||||||
// all messages succeeded.
|
|
||||||
s.v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.Ok))
|
|
||||||
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *msStage) state() *multisig.State {
|
|
||||||
var msState multisig.State
|
|
||||||
s.v.Actors.ActorState(s.msAddr, &msState)
|
|
||||||
return &msState
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
"github.com/filecoin-project/oni/tvx/schema"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
initialBal = abi.NewTokenAmount(1_000_000_000_000)
|
|
||||||
toSend = abi.NewTokenAmount(10_000)
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
g := NewGenerator()
|
|
||||||
|
|
||||||
g.MessageVectorGroup("paych",
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "create-ok",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: happyPathCreate,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "update-ok",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: happyPathUpdate,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "collect-ok",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "",
|
|
||||||
},
|
|
||||||
Func: happyPathCollect,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
g.Wait()
|
|
||||||
}
|
|
@ -1,167 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
init_ "github.com/filecoin-project/specs-actors/actors/builtin/init"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/builtin/paych"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/crypto"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/util/adt"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
)
|
|
||||||
|
|
||||||
func happyPathCreate(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
// Set up sender and receiver accounts.
|
|
||||||
var sender, receiver AddressHandle
|
|
||||||
v.Actors.AccountN(address.SECP256K1, initialBal, &sender, &receiver)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// Add the constructor message.
|
|
||||||
createMsg := v.Messages.Sugar().CreatePaychActor(sender.Robust, receiver.Robust, Value(toSend))
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
expectedActorAddr := AddressHandle{
|
|
||||||
ID: MustNewIDAddr(MustIDFromAddress(receiver.ID) + 1),
|
|
||||||
Robust: sender.NextActorAddress(0, 0),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify init actor return.
|
|
||||||
var ret init_.ExecReturn
|
|
||||||
MustDeserialize(createMsg.Result.Return, &ret)
|
|
||||||
v.Assert.Equal(expectedActorAddr.Robust, ret.RobustAddress)
|
|
||||||
v.Assert.Equal(expectedActorAddr.ID, ret.IDAddress)
|
|
||||||
|
|
||||||
// Verify the paych state.
|
|
||||||
var state paych.State
|
|
||||||
actor := v.Actors.ActorState(ret.IDAddress, &state)
|
|
||||||
v.Assert.Equal(sender.ID, state.From)
|
|
||||||
v.Assert.Equal(receiver.ID, state.To)
|
|
||||||
v.Assert.Equal(toSend, actor.Balance)
|
|
||||||
|
|
||||||
v.Assert.EveryMessageSenderSatisfies(NonceUpdated())
|
|
||||||
}
|
|
||||||
|
|
||||||
func happyPathUpdate(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
var (
|
|
||||||
timelock = abi.ChainEpoch(0)
|
|
||||||
lane = uint64(123)
|
|
||||||
nonce = uint64(1)
|
|
||||||
amount = big.NewInt(10)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Set up sender and receiver accounts.
|
|
||||||
var sender, receiver AddressHandle
|
|
||||||
var paychAddr AddressHandle
|
|
||||||
|
|
||||||
v.Actors.AccountN(address.SECP256K1, initialBal, &sender, &receiver)
|
|
||||||
paychAddr = AddressHandle{
|
|
||||||
ID: MustNewIDAddr(MustIDFromAddress(receiver.ID) + 1),
|
|
||||||
Robust: sender.NextActorAddress(0, 0),
|
|
||||||
}
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// Construct the payment channel.
|
|
||||||
createMsg := v.Messages.Sugar().CreatePaychActor(sender.Robust, receiver.Robust, Value(toSend))
|
|
||||||
|
|
||||||
// Update the payment channel.
|
|
||||||
v.Messages.Typed(sender.Robust, paychAddr.Robust, PaychUpdateChannelState(&paych.UpdateChannelStateParams{
|
|
||||||
Sv: paych.SignedVoucher{
|
|
||||||
ChannelAddr: paychAddr.Robust,
|
|
||||||
TimeLockMin: timelock,
|
|
||||||
TimeLockMax: 0, // TimeLockMax set to 0 means no timeout
|
|
||||||
Lane: lane,
|
|
||||||
Nonce: nonce,
|
|
||||||
Amount: amount,
|
|
||||||
MinSettleHeight: 0,
|
|
||||||
Signature: &crypto.Signature{
|
|
||||||
Type: crypto.SigTypeBLS,
|
|
||||||
Data: []byte("signature goes here"), // TODO may need to generate an actual signature
|
|
||||||
},
|
|
||||||
}}), Nonce(1), Value(big.Zero()))
|
|
||||||
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
// all messages succeeded.
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.Ok))
|
|
||||||
|
|
||||||
// Verify init actor return.
|
|
||||||
var ret init_.ExecReturn
|
|
||||||
MustDeserialize(createMsg.Result.Return, &ret)
|
|
||||||
|
|
||||||
// Verify the paych state.
|
|
||||||
var state paych.State
|
|
||||||
v.Actors.ActorState(ret.RobustAddress, &state)
|
|
||||||
|
|
||||||
arr, err := adt.AsArray(v.Stores.ADTStore, state.LaneStates)
|
|
||||||
v.Assert.NoError(err)
|
|
||||||
v.Assert.EqualValues(1, arr.Length())
|
|
||||||
|
|
||||||
var ls paych.LaneState
|
|
||||||
found, err := arr.Get(lane, &ls)
|
|
||||||
v.Assert.NoError(err)
|
|
||||||
v.Assert.True(found)
|
|
||||||
|
|
||||||
v.Assert.Equal(amount, ls.Redeemed)
|
|
||||||
v.Assert.Equal(nonce, ls.Nonce)
|
|
||||||
|
|
||||||
v.Assert.EveryMessageSenderSatisfies(NonceUpdated())
|
|
||||||
}
|
|
||||||
|
|
||||||
func happyPathCollect(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
// Set up sender and receiver accounts.
|
|
||||||
var sender, receiver AddressHandle
|
|
||||||
var paychAddr AddressHandle
|
|
||||||
v.Actors.AccountN(address.SECP256K1, initialBal, &sender, &receiver)
|
|
||||||
paychAddr = AddressHandle{
|
|
||||||
ID: MustNewIDAddr(MustIDFromAddress(receiver.ID) + 1),
|
|
||||||
Robust: sender.NextActorAddress(0, 0),
|
|
||||||
}
|
|
||||||
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// Construct the payment channel.
|
|
||||||
createMsg := v.Messages.Sugar().CreatePaychActor(sender.Robust, receiver.Robust, Value(toSend))
|
|
||||||
|
|
||||||
// Update the payment channel.
|
|
||||||
updateMsg := v.Messages.Typed(sender.Robust, paychAddr.Robust, PaychUpdateChannelState(&paych.UpdateChannelStateParams{
|
|
||||||
Sv: paych.SignedVoucher{
|
|
||||||
ChannelAddr: paychAddr.Robust,
|
|
||||||
TimeLockMin: 0,
|
|
||||||
TimeLockMax: 0, // TimeLockMax set to 0 means no timeout
|
|
||||||
Lane: 1,
|
|
||||||
Nonce: 1,
|
|
||||||
Amount: toSend,
|
|
||||||
MinSettleHeight: 0,
|
|
||||||
Signature: &crypto.Signature{
|
|
||||||
Type: crypto.SigTypeBLS,
|
|
||||||
Data: []byte("signature goes here"), // TODO may need to generate an actual signature
|
|
||||||
},
|
|
||||||
}}), Nonce(1), Value(big.Zero()))
|
|
||||||
|
|
||||||
settleMsg := v.Messages.Typed(receiver.Robust, paychAddr.Robust, PaychSettle(nil), Value(big.Zero()), Nonce(0))
|
|
||||||
|
|
||||||
// advance the epoch so the funds may be redeemed.
|
|
||||||
collectMsg := v.Messages.Typed(receiver.Robust, paychAddr.Robust, PaychCollect(nil), Value(big.Zero()), Nonce(1), Epoch(paych.SettleDelay))
|
|
||||||
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
// all messages succeeded.
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.Ok))
|
|
||||||
|
|
||||||
v.Assert.MessageSendersSatisfy(BalanceUpdated(big.Zero()), createMsg, updateMsg)
|
|
||||||
v.Assert.MessageSendersSatisfy(BalanceUpdated(toSend), settleMsg, collectMsg)
|
|
||||||
v.Assert.EveryMessageSenderSatisfies(NonceUpdated())
|
|
||||||
|
|
||||||
// the paych actor should have been deleted after the collect
|
|
||||||
v.Assert.ActorMissing(paychAddr.Robust)
|
|
||||||
v.Assert.ActorMissing(paychAddr.ID)
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
)
|
|
||||||
|
|
||||||
type basicTransferParams struct {
|
|
||||||
senderType address.Protocol
|
|
||||||
senderBal abi.TokenAmount
|
|
||||||
receiverType address.Protocol
|
|
||||||
amount abi.TokenAmount
|
|
||||||
exitCode exitcode.ExitCode
|
|
||||||
}
|
|
||||||
|
|
||||||
func basicTransfer(params basicTransferParams) func(v *Builder) {
|
|
||||||
return func(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(gasLimit), GasPremium(1), GasFeeCap(gasFeeCap))
|
|
||||||
|
|
||||||
// Set up sender and receiver accounts.
|
|
||||||
var sender, receiver AddressHandle
|
|
||||||
sender = v.Actors.Account(params.senderType, params.senderBal)
|
|
||||||
receiver = v.Actors.Account(params.receiverType, big.Zero())
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// Perform the transfer.
|
|
||||||
v.Messages.Sugar().Transfer(sender.ID, receiver.ID, Value(params.amount), Nonce(0))
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(params.exitCode))
|
|
||||||
v.Assert.EveryMessageSenderSatisfies(BalanceUpdated(big.Zero()))
|
|
||||||
|
|
||||||
if params.exitCode.IsSuccess() {
|
|
||||||
v.Assert.EveryMessageSenderSatisfies(NonceUpdated())
|
|
||||||
v.Assert.BalanceEq(receiver.ID, params.amount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,165 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
"github.com/filecoin-project/oni/tvx/schema"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
gasLimit = 1_000_000_000
|
|
||||||
gasFeeCap = 200
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
g := NewGenerator()
|
|
||||||
defer g.Wait()
|
|
||||||
|
|
||||||
g.MessageVectorGroup("basic",
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "successfully transfer funds from sender to receiver",
|
|
||||||
},
|
|
||||||
Func: basicTransfer(basicTransferParams{
|
|
||||||
senderType: address.SECP256K1,
|
|
||||||
senderBal: abi.NewTokenAmount(10 * gasLimit * gasFeeCap),
|
|
||||||
receiverType: address.SECP256K1,
|
|
||||||
amount: abi.NewTokenAmount(50),
|
|
||||||
exitCode: exitcode.Ok,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "ok-zero",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "successfully transfer zero funds from sender to receiver",
|
|
||||||
},
|
|
||||||
Func: basicTransfer(basicTransferParams{
|
|
||||||
senderType: address.SECP256K1,
|
|
||||||
senderBal: abi.NewTokenAmount(10 * gasFeeCap * gasLimit),
|
|
||||||
receiverType: address.SECP256K1,
|
|
||||||
amount: abi.NewTokenAmount(0),
|
|
||||||
exitCode: exitcode.Ok,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-exceed-balance",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "fail to transfer more funds than sender balance > 0",
|
|
||||||
},
|
|
||||||
Func: basicTransfer(basicTransferParams{
|
|
||||||
senderType: address.SECP256K1,
|
|
||||||
senderBal: abi.NewTokenAmount(10 * gasFeeCap * gasLimit),
|
|
||||||
receiverType: address.SECP256K1,
|
|
||||||
amount: abi.NewTokenAmount(10*gasFeeCap*gasLimit - gasFeeCap*gasLimit + 1),
|
|
||||||
exitCode: exitcode.SysErrInsufficientFunds,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-balance-equal-gas",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "fail to transfer more funds than sender has when sender balance matches gas limit",
|
|
||||||
},
|
|
||||||
Func: basicTransfer(basicTransferParams{
|
|
||||||
senderType: address.SECP256K1,
|
|
||||||
senderBal: abi.NewTokenAmount(gasFeeCap * gasLimit),
|
|
||||||
receiverType: address.SECP256K1,
|
|
||||||
amount: abi.NewTokenAmount(1),
|
|
||||||
exitCode: exitcode.SysErrInsufficientFunds,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-balance-under-gaslimit",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "fail to transfer when sender balance under gas limit",
|
|
||||||
},
|
|
||||||
Func: basicTransfer(basicTransferParams{
|
|
||||||
senderType: address.SECP256K1,
|
|
||||||
senderBal: abi.NewTokenAmount(gasFeeCap*gasLimit - 1),
|
|
||||||
receiverType: address.SECP256K1,
|
|
||||||
amount: abi.NewTokenAmount(0),
|
|
||||||
exitCode: exitcode.SysErrSenderStateInvalid,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
g.MessageVectorGroup("self_transfer",
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "secp-to-secp-addresses",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
Func: selfTransfer(AddressHandle.RobustAddr, AddressHandle.RobustAddr),
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "secp-to-id-addresses",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
Func: selfTransfer(AddressHandle.RobustAddr, AddressHandle.IDAddr),
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "id-to-secp-addresses",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
Func: selfTransfer(AddressHandle.IDAddr, AddressHandle.RobustAddr),
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "id-to-id-addresses",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
Func: selfTransfer(AddressHandle.IDAddr, AddressHandle.IDAddr),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
g.MessageVectorGroup("unknown_accounts",
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-unknown-sender-known-receiver",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "fail to transfer from unknown account to known address",
|
|
||||||
},
|
|
||||||
Func: failTransferUnknownSenderKnownReceiver,
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "fail-unknown-sender-unknown-receiver",
|
|
||||||
Version: "v1",
|
|
||||||
Desc: "fail to transfer from unknown address to unknown address",
|
|
||||||
},
|
|
||||||
Func: failTransferUnknownSenderUnknownReceiver,
|
|
||||||
},
|
|
||||||
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "secp-to-id-addresses",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
Func: selfTransfer(AddressHandle.RobustAddr, AddressHandle.IDAddr),
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "id-to-secp-addresses",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
Func: selfTransfer(AddressHandle.IDAddr, AddressHandle.RobustAddr),
|
|
||||||
},
|
|
||||||
&MessageVectorGenItem{
|
|
||||||
Metadata: &schema.Metadata{
|
|
||||||
ID: "id-to-id-addresses",
|
|
||||||
Version: "v1",
|
|
||||||
},
|
|
||||||
Func: selfTransfer(AddressHandle.IDAddr, AddressHandle.IDAddr),
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
)
|
|
||||||
|
|
||||||
func selfTransfer(from, to func(h AddressHandle) address.Address) func(v *Builder) {
|
|
||||||
return func(v *Builder) {
|
|
||||||
initial := abi.NewTokenAmount(1_000_000_000_000)
|
|
||||||
transfer := abi.NewTokenAmount(10)
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
// Set up sender account.
|
|
||||||
account := v.Actors.Account(address.SECP256K1, initial)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// Perform the transfer.
|
|
||||||
msg := v.Messages.Sugar().Transfer(from(account), to(account), Value(transfer), Nonce(0))
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.Equal(exitcode.Ok, msg.Result.ExitCode)
|
|
||||||
|
|
||||||
// the transfer balance comes back to us.
|
|
||||||
v.Assert.EveryMessageSenderSatisfies(BalanceUpdated(transfer))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/filecoin-project/go-address"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
||||||
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
||||||
|
|
||||||
. "github.com/filecoin-project/oni/tvx/builders"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
initial = abi.NewTokenAmount(1_000_000_000_000)
|
|
||||||
transfer = Value(abi.NewTokenAmount(10))
|
|
||||||
)
|
|
||||||
|
|
||||||
func failTransferUnknownSenderKnownReceiver(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
// Set up receiver account.
|
|
||||||
receiver := v.Actors.Account(address.SECP256K1, initial)
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// create a new random sender.
|
|
||||||
sender := v.Wallet.NewSECP256k1Account()
|
|
||||||
|
|
||||||
// perform the transfer.
|
|
||||||
v.Messages.Sugar().Transfer(sender, receiver.Robust, transfer, Nonce(0))
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrSenderInvalid))
|
|
||||||
v.Assert.ActorMissing(sender)
|
|
||||||
v.Assert.ActorExists(receiver.Robust)
|
|
||||||
v.Assert.BalanceEq(receiver.Robust, initial)
|
|
||||||
}
|
|
||||||
|
|
||||||
func failTransferUnknownSenderUnknownReceiver(v *Builder) {
|
|
||||||
v.Messages.SetDefaults(GasLimit(1_000_000_000), GasPremium(1), GasFeeCap(200))
|
|
||||||
|
|
||||||
// no accounts in the system.
|
|
||||||
v.CommitPreconditions()
|
|
||||||
|
|
||||||
// create new random senders and resceivers.
|
|
||||||
sender, receiver := v.Wallet.NewSECP256k1Account(), v.Wallet.NewSECP256k1Account()
|
|
||||||
|
|
||||||
// perform the transfer.
|
|
||||||
v.Messages.Sugar().Transfer(sender, receiver, transfer, Nonce(0))
|
|
||||||
v.CommitApplies()
|
|
||||||
|
|
||||||
v.Assert.EveryMessageResultSatisfies(ExitCode(exitcode.SysErrSenderInvalid))
|
|
||||||
v.Assert.ActorMissing(sender)
|
|
||||||
v.Assert.ActorMissing(receiver)
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user