2020-08-14 12:51:43 +00:00
|
|
|
package builders
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
|
2020-08-15 23:03:58 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/types"
|
2020-08-14 12:51:43 +00:00
|
|
|
"github.com/filecoin-project/lotus/chain/vm"
|
2020-08-15 23:03:58 +00:00
|
|
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
|
|
|
"github.com/filecoin-project/specs-actors/actors/abi/big"
|
2020-08-14 12:51:43 +00:00
|
|
|
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
|
|
|
)
|
|
|
|
|
2020-08-15 23:03:58 +00:00
|
|
|
// ApplyRetPredicate evaluates a given condition against the result of a
|
|
|
|
// message application.
|
2020-08-14 12:51:43 +00:00
|
|
|
type ApplyRetPredicate func(ret *vm.ApplyRet) error
|
|
|
|
|
2020-08-15 23:03:58 +00:00
|
|
|
// 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.
|
2020-08-14 12:51:43 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
2020-08-15 23:03:58 +00:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
}
|