2020-08-07 12:47:16 +00:00
|
|
|
package schema
|
2020-08-05 12:20:13 +00:00
|
|
|
|
|
|
|
import (
|
2020-08-14 17:05:29 +00:00
|
|
|
"encoding/base64"
|
2020-08-05 12:20:13 +00:00
|
|
|
"encoding/json"
|
2020-08-06 16:20:17 +00:00
|
|
|
"fmt"
|
2020-08-05 12:20:13 +00:00
|
|
|
|
|
|
|
"github.com/filecoin-project/specs-actors/actors/abi"
|
2020-08-06 16:20:17 +00:00
|
|
|
"github.com/filecoin-project/specs-actors/actors/runtime/exitcode"
|
2020-08-05 14:52:57 +00:00
|
|
|
"github.com/ipfs/go-cid"
|
2020-08-05 12:20:13 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Class represents the type of test this instance is.
|
|
|
|
type Class string
|
|
|
|
|
|
|
|
var (
|
|
|
|
// ClassMessage tests the VM transition over a single message
|
|
|
|
ClassMessage Class = "message"
|
|
|
|
// ClassBlock tests the VM transition over a block of messages
|
|
|
|
ClassBlock Class = "block"
|
|
|
|
// ClassTipset tests the VM transition on a tipset update
|
|
|
|
ClassTipset Class = "tipset"
|
|
|
|
// ClassChain tests the VM transition across a chain segment
|
|
|
|
ClassChain Class = "chain"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Selector provides a filter to indicate what implementations this test is relevant for
|
|
|
|
type Selector string
|
|
|
|
|
|
|
|
// Metadata provides information on the generation of this test case
|
|
|
|
type Metadata struct {
|
|
|
|
ID string `json:"id"`
|
|
|
|
Version string `json:"version"`
|
2020-08-06 16:20:17 +00:00
|
|
|
Desc string `json:"description"`
|
|
|
|
Comment string `json:"comment"`
|
2020-08-05 12:20:13 +00:00
|
|
|
Gen GenerationData `json:"gen"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// GenerationData tags the source of this test case
|
|
|
|
type GenerationData struct {
|
|
|
|
Source string `json:"source"`
|
|
|
|
Version string `json:"version"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// StateTree represents a state tree within preconditions and postconditions.
|
|
|
|
type StateTree struct {
|
2020-08-05 14:52:57 +00:00
|
|
|
RootCID cid.Cid `json:"root_cid"`
|
2020-08-05 12:20:13 +00:00
|
|
|
}
|
|
|
|
|
2020-08-14 17:05:29 +00:00
|
|
|
// Base64EncodedBytes is a base64-encoded binary value.
|
|
|
|
type Base64EncodedBytes []byte
|
2020-08-05 12:20:13 +00:00
|
|
|
|
|
|
|
// Preconditions contain a representation of VM state at the beginning of the test
|
|
|
|
type Preconditions struct {
|
|
|
|
Epoch abi.ChainEpoch `json:"epoch"`
|
|
|
|
StateTree *StateTree `json:"state_tree"`
|
|
|
|
}
|
|
|
|
|
2020-08-06 16:20:17 +00:00
|
|
|
// Receipt represents a receipt to match against.
|
|
|
|
type Receipt struct {
|
2020-08-14 17:05:29 +00:00
|
|
|
ExitCode exitcode.ExitCode `json:"exit_code"`
|
|
|
|
ReturnValue Base64EncodedBytes `json:"return"`
|
|
|
|
GasUsed int64 `json:"gas_used"`
|
2020-08-06 16:20:17 +00:00
|
|
|
}
|
|
|
|
|
2020-08-05 12:20:13 +00:00
|
|
|
// Postconditions contain a representation of VM state at th end of the test
|
|
|
|
type Postconditions struct {
|
|
|
|
StateTree *StateTree `json:"state_tree"`
|
2020-08-06 16:20:17 +00:00
|
|
|
Receipts []*Receipt `json:"receipts"`
|
2020-08-05 12:20:13 +00:00
|
|
|
}
|
|
|
|
|
2020-08-14 17:05:29 +00:00
|
|
|
// MarshalJSON implements json.Marshal for Base64EncodedBytes
|
|
|
|
func (beb Base64EncodedBytes) MarshalJSON() ([]byte, error) {
|
|
|
|
return json.Marshal(base64.StdEncoding.EncodeToString(beb))
|
2020-08-05 12:20:13 +00:00
|
|
|
}
|
|
|
|
|
2020-08-14 17:05:29 +00:00
|
|
|
// UnmarshalJSON implements json.Unmarshal for Base64EncodedBytes
|
|
|
|
func (beb *Base64EncodedBytes) UnmarshalJSON(v []byte) error {
|
2020-08-05 12:20:13 +00:00
|
|
|
var s string
|
|
|
|
if err := json.Unmarshal(v, &s); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-08-14 17:05:29 +00:00
|
|
|
bytes, err := base64.StdEncoding.DecodeString(s)
|
2020-08-05 12:20:13 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-08-14 17:05:29 +00:00
|
|
|
*beb = bytes
|
2020-08-05 12:20:13 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestVector is a single test case
|
|
|
|
type TestVector struct {
|
2020-08-05 14:52:57 +00:00
|
|
|
Class `json:"class"`
|
|
|
|
Selector `json:"selector"`
|
|
|
|
Meta *Metadata `json:"_meta"`
|
|
|
|
|
|
|
|
// CAR binary data to be loaded into the test environment, usually a CAR
|
|
|
|
// containing multiple state trees, addressed by root CID from the relevant
|
|
|
|
// objects.
|
2020-08-14 17:05:29 +00:00
|
|
|
CAR Base64EncodedBytes `json:"car"`
|
2020-08-05 14:52:57 +00:00
|
|
|
|
2020-08-06 16:57:15 +00:00
|
|
|
Pre *Preconditions `json:"preconditions"`
|
|
|
|
ApplyMessages []Message `json:"apply_messages"`
|
|
|
|
Post *Postconditions `json:"postconditions"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type Message struct {
|
2020-08-14 17:05:29 +00:00
|
|
|
Bytes Base64EncodedBytes `json:"bytes"`
|
|
|
|
Epoch *abi.ChainEpoch `json:"epoch,omitempty"`
|
2020-08-05 12:20:13 +00:00
|
|
|
}
|
2020-08-06 16:20:17 +00:00
|
|
|
|
|
|
|
// Validate validates this test vector against the JSON schema, and applies
|
|
|
|
// further validation rules that cannot be enforced through JSON Schema.
|
|
|
|
func (tv TestVector) Validate() error {
|
|
|
|
// TODO validate against JSON Schema.
|
|
|
|
if tv.Class == ClassMessage {
|
|
|
|
if len(tv.Post.Receipts) != len(tv.ApplyMessages) {
|
|
|
|
return fmt.Errorf("length of postcondition receipts must match length of messages to apply")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
2020-08-07 13:09:10 +00:00
|
|
|
|
|
|
|
// MustMarshalJSON encodes the test vector to JSON and panics if it errors.
|
|
|
|
func (tv TestVector) MustMarshalJSON() []byte {
|
|
|
|
b, err := json.Marshal(&tv)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return b
|
|
|
|
}
|