lotus/tvx/drivers/tipset_message_producer.go
Anton Evangelatov 5353210814
generate test-vectors based on tests from chain-validation project (#181)
* Read a subset of filecoin state over the full node API

* wip

* import export wip

* extract actors from message

* generate car for any state

* library for providing a pruned statetree

* test vector schema draft + example 'message' class test vector.

* message => messages test vector class.

* fixup

* wip

* use lb.NewBlockstore with ID

* fixup lotus-soup, and generate

* fix deals

* magic params

* work on schema / export of test vector

* fixup

* wip deserialise state tree

* pass at building a test case from a message

* progress loading / serializing

* recreation of ipld nodes

* generation of vector creates json

* kick off tvx tool.

* wip

* wip

* retain init actor state.

* initial test with printed out state

* remove testing.T, but keep require and assert libraries

* wip refactor state tree plucking.

* simplified

* removed factories

* remove builder.Build ; remove interface - use concrete iface

* comment out validateState

* remove Validator

* remove TestDriverBuilder

* remove client

* remove box

* remove gen

* remove factories

* remove KeyManager interfafce

* moved stuff around

* remove ValidationConfig

* extract randomness

* extract config and key_manager

* extract statewrapper

* extract applier

* rename factories to various

* flatten chain-validation package

* initial marshal of test vector

* do not require schema package

* fixup

* run all messages tests

* better names

* run all messages tests

* remove Indent setting from JSON encoder for now

* refactor, and actually running successfully ;-)

* remove irrelevant files; rename extract-msg command.

* remove root CID from state_tree object in schema.

* add tvx/lotus package; adjust .gitignore.

* tidy up command flag management.

* add comment.

* remove validateState and trackState

* remove xerrors

* remove NewVM

* remove commented out RootCID sets

* enable more tests

* add all `message_application` tests

* delete all.json

* update Message struct

* fix message serialization

* support multiple messages

* gofmt

* remove custom Message and SignedMessage types

* update tests with gzip and adhere to new schema for compressed CAR

* improved iface for Marshal

* update Validation

* remove test-suites and utils

* better names for chain. methods

* go mod tidy

* remove top-level dummyT

Co-authored-by: Will Scott <will@cypherpunk.email>
Co-authored-by: Raúl Kripalani <raul@protocol.ai>
2020-08-05 19:40:09 +02:00

202 lines
5.3 KiB
Go

package drivers
import (
"github.com/filecoin-project/go-address"
"github.com/filecoin-project/lotus/chain/types"
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
vtypes "github.com/filecoin-project/oni/tvx/chain/types"
)
type TipSetMessageBuilder struct {
driver *TestDriver
bbs []*BlockBuilder
}
func NewTipSetMessageBuilder(testDriver *TestDriver) *TipSetMessageBuilder {
return &TipSetMessageBuilder{
driver: testDriver,
bbs: nil,
}
}
func (t *TipSetMessageBuilder) WithBlockBuilder(bb *BlockBuilder) *TipSetMessageBuilder {
t.bbs = append(t.bbs, bb)
return t
}
func (t *TipSetMessageBuilder) Apply() vtypes.ApplyTipSetResult {
result := t.apply()
t.Clear()
return result
}
func (t *TipSetMessageBuilder) ApplyAndValidate() vtypes.ApplyTipSetResult {
result := t.apply()
t.validateResult(result)
t.Clear()
return result
}
func (tb *TipSetMessageBuilder) apply() vtypes.ApplyTipSetResult {
var blks []vtypes.BlockMessagesInfo
for _, b := range tb.bbs {
blks = append(blks, b.build())
}
result, err := tb.driver.applier.ApplyTipSetMessages(tb.driver.ExeCtx.Epoch, blks, tb.driver.Randomness())
require.NoError(t, err)
//t.driver.StateTracker.TrackResult(result)
return result
}
func (tb *TipSetMessageBuilder) validateResult(result vtypes.ApplyTipSetResult) {
expected := []ExpectedResult{}
for _, b := range tb.bbs {
expected = append(expected, b.expectedResults...)
}
if len(result.Receipts) > len(expected) {
t.Fatalf("ApplyTipSetMessages returned more result than expected. Expected: %d, Actual: %d", len(expected), len(result.Receipts))
return
}
for i := range result.Receipts {
if tb.driver.Config.ValidateExitCode() {
assert.Equal(t, expected[i].ExitCode, result.Receipts[i].ExitCode, "Message Number: %d Expected ExitCode: %s Actual ExitCode: %s", i, expected[i].ExitCode.Error(), result.Receipts[i].ExitCode.Error())
}
if tb.driver.Config.ValidateReturnValue() {
assert.Equal(t, expected[i].ReturnVal, result.Receipts[i].ReturnValue, "Message Number: %d Expected ReturnValue: %v Actual ReturnValue: %v", i, expected[i].ReturnVal, result.Receipts[i].ReturnValue)
}
}
}
func (t *TipSetMessageBuilder) Clear() {
t.bbs = nil
}
type BlockBuilder struct {
TD *TestDriver
miner address.Address
ticketCount int64
secpMsgs []*types.SignedMessage
blsMsgs []*types.Message
expectedResults []ExpectedResult
}
type ExpectedResult struct {
ExitCode exitcode.ExitCode
ReturnVal []byte
}
func NewBlockBuilder(td *TestDriver, miner address.Address) *BlockBuilder {
return &BlockBuilder{
TD: td,
miner: miner,
ticketCount: 1,
secpMsgs: nil,
blsMsgs: nil,
expectedResults: nil,
}
}
func (bb *BlockBuilder) addResult(code exitcode.ExitCode, retval []byte) {
bb.expectedResults = append(bb.expectedResults, ExpectedResult{
ExitCode: code,
ReturnVal: retval,
})
}
func (bb *BlockBuilder) WithBLSMessageOk(blsMsg *types.Message) *BlockBuilder {
bb.blsMsgs = append(bb.blsMsgs, blsMsg)
bb.addResult(exitcode.Ok, EmptyReturnValue)
return bb
}
func (bb *BlockBuilder) WithBLSMessageDropped(blsMsg *types.Message) *BlockBuilder {
bb.blsMsgs = append(bb.blsMsgs, blsMsg)
return bb
}
func (bb *BlockBuilder) WithBLSMessageAndCode(bm *types.Message, code exitcode.ExitCode) *BlockBuilder {
bb.blsMsgs = append(bb.blsMsgs, bm)
bb.addResult(code, EmptyReturnValue)
return bb
}
func (bb *BlockBuilder) WithBLSMessageAndRet(bm *types.Message, retval []byte) *BlockBuilder {
bb.blsMsgs = append(bb.blsMsgs, bm)
bb.addResult(exitcode.Ok, retval)
return bb
}
func (bb *BlockBuilder) WithSECPMessageAndCode(bm *types.Message, code exitcode.ExitCode) *BlockBuilder {
secpMsg := bb.toSignedMessage(bm)
bb.secpMsgs = append(bb.secpMsgs, secpMsg)
bb.addResult(code, EmptyReturnValue)
return bb
}
func (bb *BlockBuilder) WithSECPMessageAndRet(bm *types.Message, retval []byte) *BlockBuilder {
secpMsg := bb.toSignedMessage(bm)
bb.secpMsgs = append(bb.secpMsgs, secpMsg)
bb.addResult(exitcode.Ok, retval)
return bb
}
func (bb *BlockBuilder) WithSECPMessageOk(bm *types.Message) *BlockBuilder {
secpMsg := bb.toSignedMessage(bm)
bb.secpMsgs = append(bb.secpMsgs, secpMsg)
bb.addResult(exitcode.Ok, EmptyReturnValue)
return bb
}
func (bb *BlockBuilder) WithSECPMessageDropped(bm *types.Message) *BlockBuilder {
secpMsg := bb.toSignedMessage(bm)
bb.secpMsgs = append(bb.secpMsgs, secpMsg)
return bb
}
func (bb *BlockBuilder) WithTicketCount(count int64) *BlockBuilder {
bb.ticketCount = count
return bb
}
func (bb *BlockBuilder) toSignedMessage(m *types.Message) *types.SignedMessage {
from := m.From
if from.Protocol() == address.ID {
from = bb.TD.ActorPubKey(from)
}
if from.Protocol() != address.SECP256K1 {
t.Fatalf("Invalid address for SECP signature, address protocol: %v", from.Protocol())
}
raw, err := m.Serialize()
require.NoError(t, err)
sig, err := bb.TD.Wallet().Sign(from, raw)
require.NoError(t, err)
return &types.SignedMessage{
Message: *m,
Signature: sig,
}
}
func (bb *BlockBuilder) build() vtypes.BlockMessagesInfo {
return vtypes.BlockMessagesInfo{
BLSMessages: bb.blsMsgs,
SECPMessages: bb.secpMsgs,
Miner: bb.miner,
TicketCount: bb.ticketCount,
}
}