lotus/tvx/messages_message_application.go

359 lines
10 KiB
Go

package main
import (
"encoding/json"
"os"
abi_spec "github.com/filecoin-project/specs-actors/actors/abi"
big_spec "github.com/filecoin-project/specs-actors/actors/abi/big"
paych_spec "github.com/filecoin-project/specs-actors/actors/builtin/paych"
crypto_spec "github.com/filecoin-project/specs-actors/actors/crypto"
exitcode_spec "github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
"github.com/filecoin-project/oni/tvx/chain"
"github.com/filecoin-project/oni/tvx/drivers"
)
func MessageTest_MessageApplicationEdgecases() error {
var aliceBal = abi_spec.NewTokenAmount(1_000_000_000_000)
var transferAmnt = abi_spec.NewTokenAmount(10)
err := func(testname string) error {
td := drivers.NewTestDriver()
v := newEmptyMessageVector()
alice, _ := td.NewAccountActor(drivers.SECP, aliceBal)
preroot := td.GetStateRoot()
msg := td.MessageProducer.Transfer(alice, alice, chain.Value(transferAmnt), chain.Nonce(0), chain.GasPrice(1), chain.GasLimit(8))
v.ApplyMessages = append(v.ApplyMessages, chain.MustSerialize(msg))
td.ApplyFailure(
msg,
exitcode_spec.SysErrOutOfGas)
postroot := td.GetStateRoot()
v.CAR = td.MustMarshalGzippedCAR(preroot, postroot)
v.Pre.StateTree.RootCID = preroot
v.Post.StateTree.RootCID = postroot
// encode and output
enc := json.NewEncoder(os.Stdout)
if err := enc.Encode(&v); err != nil {
return err
}
return nil
}("fail to cover gas cost for message receipt on chain")
if err != nil {
return err
}
err = func(testname string) error {
//TODO: this test is broken, fix later
return nil
td := drivers.NewTestDriver()
v := newEmptyMessageVector()
alice, _ := td.NewAccountActor(drivers.SECP, aliceBal)
preroot := td.GetStateRoot()
msg := td.MessageProducer.Transfer(alice, alice, chain.Value(transferAmnt), chain.Nonce(0), chain.GasPrice(10), chain.GasLimit(1))
// Expect Message application to fail due to lack of gas
td.ApplyFailure(
msg,
exitcode_spec.SysErrOutOfGas)
// Expect Message application to fail due to lack of gas when sender is unknown
unknown := chain.MustNewIDAddr(10000000)
msg = td.MessageProducer.Transfer(unknown, alice, chain.Value(transferAmnt), chain.Nonce(0), chain.GasPrice(10), chain.GasLimit(1))
v.ApplyMessages = append(v.ApplyMessages, chain.MustSerialize(msg))
td.ApplyFailure(
msg,
exitcode_spec.SysErrOutOfGas)
postroot := td.GetStateRoot()
v.CAR = td.MustMarshalGzippedCAR(preroot, postroot)
v.Pre.StateTree.RootCID = preroot
v.Post.StateTree.RootCID = postroot
// encode and output
enc := json.NewEncoder(os.Stdout)
if err := enc.Encode(&v); err != nil {
return err
}
return nil
}("not enough gas to pay message on-chain-size cost")
if err != nil {
return err
}
err = func(testname string) error {
td := drivers.NewTestDriver()
v := newEmptyMessageVector()
alice, _ := td.NewAccountActor(drivers.SECP, aliceBal)
preroot := td.GetStateRoot()
aliceNonce := uint64(0)
aliceNonceF := func() uint64 {
defer func() { aliceNonce++ }()
return aliceNonce
}
newAccountA := chain.MustNewSECP256K1Addr("1")
msg := td.MessageProducer.Transfer(alice, newAccountA, chain.Value(transferAmnt), chain.Nonce(aliceNonceF()))
v.ApplyMessages = append(v.ApplyMessages, chain.MustSerialize(msg))
// get the "true" gas cost of applying the message
result := td.ApplyOk(msg)
// decrease the gas cost by `gasStep` for each apply and ensure `SysErrOutOfGas` is always returned.
trueGas := int64(result.GasUsed())
gasStep := int64(trueGas / 100)
newAccountB := chain.MustNewSECP256K1Addr("2")
for tryGas := trueGas - gasStep; tryGas > 0; tryGas -= gasStep {
msg := td.MessageProducer.Transfer(alice, newAccountB, chain.Value(transferAmnt), chain.Nonce(aliceNonceF()), chain.GasPrice(1), chain.GasLimit(tryGas))
v.ApplyMessages = append(v.ApplyMessages, chain.MustSerialize(msg))
td.ApplyFailure(
msg,
exitcode_spec.SysErrOutOfGas,
)
}
postroot := td.GetStateRoot()
v.CAR = td.MustMarshalGzippedCAR(preroot, postroot)
v.Pre.StateTree.RootCID = preroot
v.Post.StateTree.RootCID = postroot
// encode and output
enc := json.NewEncoder(os.Stdout)
if err := enc.Encode(&v); err != nil {
return err
}
return nil
}("fail not enough gas to cover account actor creation")
if err != nil {
return err
}
err = func(testname string) error {
//TODO: this test is broken, fix me
return nil
td := drivers.NewTestDriver()
v := newEmptyMessageVector()
alice, _ := td.NewAccountActor(drivers.SECP, aliceBal)
preroot := td.GetStateRoot()
msg := td.MessageProducer.Transfer(alice, alice, chain.Value(transferAmnt), chain.Nonce(1))
v.ApplyMessages = append(v.ApplyMessages, chain.MustSerialize(msg))
// Expect Message application to fail due to callseqnum being invalid: 1 instead of 0
td.ApplyFailure(
msg,
exitcode_spec.SysErrSenderStateInvalid)
unknown := chain.MustNewIDAddr(10000000)
msg = td.MessageProducer.Transfer(unknown, alice, chain.Value(transferAmnt), chain.Nonce(1))
v.ApplyMessages = append(v.ApplyMessages, chain.MustSerialize(msg))
// Expect message application to fail due to unknow actor when call seq num is also incorrect
td.ApplyFailure(
msg,
exitcode_spec.SysErrSenderInvalid)
postroot := td.GetStateRoot()
v.CAR = td.MustMarshalGzippedCAR(preroot, postroot)
v.Pre.StateTree.RootCID = preroot
v.Post.StateTree.RootCID = postroot
// encode and output
enc := json.NewEncoder(os.Stdout)
if err := enc.Encode(&v); err != nil {
return err
}
return nil
}("invalid actor nonce")
if err != nil {
return err
}
err = func(testname string) error {
td := drivers.NewTestDriver()
v := newEmptyMessageVector()
const pcTimeLock = abi_spec.ChainEpoch(10)
const pcLane = uint64(123)
const pcNonce = uint64(1)
var pcAmount = big_spec.NewInt(10)
var initialBal = abi_spec.NewTokenAmount(200_000_000_000)
var toSend = abi_spec.NewTokenAmount(10_000)
var pcSig = &crypto_spec.Signature{
Type: crypto_spec.SigTypeBLS,
Data: []byte("Grrr im an invalid signature, I cause panics in the payment channel actor"),
}
// will create and send on payment channel
sender, _ := td.NewAccountActor(drivers.SECP, initialBal)
// will be receiver on paych
receiver, receiverID := td.NewAccountActor(drivers.SECP, initialBal)
// the _expected_ address of the payment channel
paychAddr := chain.MustNewIDAddr(chain.MustIdFromAddress(receiverID) + 1)
createRet := td.ComputeInitActorExecReturn(sender, 0, 0, paychAddr)
preroot := td.GetStateRoot()
msg := td.MessageProducer.CreatePaymentChannelActor(sender, receiver, chain.Value(toSend), chain.Nonce(0))
v.ApplyMessages = append(v.ApplyMessages, chain.MustSerialize(msg))
td.ApplyExpect(
msg,
chain.MustSerialize(&createRet))
msg = td.MessageProducer.PaychUpdateChannelState(sender, paychAddr, &paych_spec.UpdateChannelStateParams{
Sv: paych_spec.SignedVoucher{
ChannelAddr: paychAddr,
TimeLockMin: pcTimeLock,
TimeLockMax: pcTimeLock,
SecretPreimage: nil,
Extra: nil,
Lane: pcLane,
Nonce: pcNonce,
Amount: pcAmount,
MinSettleHeight: 0,
Merges: nil,
Signature: pcSig, // construct with invalid signature
},
}, chain.Nonce(1), chain.Value(big_spec.Zero()))
v.ApplyMessages = append(v.ApplyMessages, chain.MustSerialize(msg))
// message application fails due to invalid argument (signature).
td.ApplyFailure(
msg,
exitcode_spec.ErrIllegalArgument)
postroot := td.GetStateRoot()
v.CAR = td.MustMarshalGzippedCAR(preroot, postroot)
v.Pre.StateTree.RootCID = preroot
v.Post.StateTree.RootCID = postroot
// encode and output
enc := json.NewEncoder(os.Stdout)
if err := enc.Encode(&v); err != nil {
return err
}
return nil
}("abort during actor execution")
if err != nil {
return err
}
err = func(testname string) error {
td := drivers.NewTestDriver()
v := newEmptyMessageVector()
alice, _ := td.NewAccountActor(drivers.SECP, aliceBal)
preroot := td.GetStateRoot()
msg := td.MessageProducer.MarketComputeDataCommitment(alice, alice, nil, chain.Nonce(0))
v.ApplyMessages = append(v.ApplyMessages, chain.MustSerialize(msg))
// message application fails because ComputeDataCommitment isn't defined
// on the recipient actor
td.ApplyFailure(
msg,
exitcode_spec.SysErrInvalidMethod)
postroot := td.GetStateRoot()
v.CAR = td.MustMarshalGzippedCAR(preroot, postroot)
v.Pre.StateTree.RootCID = preroot
v.Post.StateTree.RootCID = postroot
// encode and output
enc := json.NewEncoder(os.Stdout)
if err := enc.Encode(&v); err != nil {
return err
}
return nil
}("invalid method for receiver")
if err != nil {
return err
}
err = func(testname string) error {
td := drivers.NewTestDriver()
v := newEmptyMessageVector()
alice, _ := td.NewAccountActor(drivers.SECP, aliceBal)
preroot := td.GetStateRoot()
// Sending a message to non-existent ID address must produce an error.
unknownA := chain.MustNewIDAddr(10000000)
msg := td.MessageProducer.Transfer(alice, unknownA, chain.Value(transferAmnt), chain.Nonce(0))
v.ApplyMessages = append(v.ApplyMessages, chain.MustSerialize(msg))
td.ApplyFailure(
msg,
exitcode_spec.SysErrInvalidReceiver)
// Sending a message to non-existing actor address must produce an error.
unknownB := chain.MustNewActorAddr("1234")
msg = td.MessageProducer.Transfer(alice, unknownB, chain.Value(transferAmnt), chain.Nonce(1))
v.ApplyMessages = append(v.ApplyMessages, chain.MustSerialize(msg))
td.ApplyFailure(
msg,
exitcode_spec.SysErrInvalidReceiver)
postroot := td.GetStateRoot()
v.CAR = td.MustMarshalGzippedCAR(preroot, postroot)
v.Pre.StateTree.RootCID = preroot
v.Post.StateTree.RootCID = postroot
// encode and output
enc := json.NewEncoder(os.Stdout)
if err := enc.Encode(&v); err != nil {
return err
}
return nil
}("receiver ID/Actor address does not exist")
if err != nil {
return err
}
return nil
// TODO more tests:
// - missing/mismatched params for receiver
// - various out-of-gas cases
}