Skip to content

Commit

Permalink
go/consensus/api/transaction/testvectors: Add ValidTx to TestVector
Browse files Browse the repository at this point in the history
Update MakeTestVector() and MakeTestVectorWithSigner() functions to take
the validTx argument indicating whether the transaction is (statically)
valid or not.

Update go/registry/gen_vectors, go/staking/gen_vectors and
go/governance/gen_vectors packages.

Expand go/governance/gen_vectors package to cover more (invalid) transaction
cases.
  • Loading branch information
tjanez committed Apr 9, 2021
1 parent 1e01c3c commit 47a5aa3
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 59 deletions.
11 changes: 11 additions & 0 deletions .changelog/3845.internal.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
go/consensus/api/transaction/testvectors: Add `ValidTx` field to `TestVector`

Update `MakeTestVector()` and `MakeTestVectorWithSigner()` functions to take
the `validTx` argument indicating whether the transaction is (statically)
valid or not.

Update go/registry/gen_vectors, go/staking/gen_vectors and
go/governance/gen_vectors packages.

Expand go/governance/gen_vectors package to cover more (invalid) transaction
cases.
9 changes: 9 additions & 0 deletions docs/consensus/test-vectors.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,11 @@ of test vectors. They can be generated for the following consensus services:

* [Staking]
* [Registry]
* [Governance]

[Staking]: staking.md#test-vectors
[Registry]: registry.md#test-vectors
[Governance]: governance.md#test-vectors

## Structure

Expand All @@ -26,6 +28,13 @@ objects (test vectors). Each test vector has the following fields:
directly (e.g., [addresses] may be represented as Bech32-encoded strings while
in the [encoded] transaction, these would be binary blobs).**

* `valid_tx` is a boolean flag indicating whether the transaction is
(statically) valid.

_NOTE: This means that the transaction passes basic static validation, but it
may still not be valid on the given network due to invalid nonce, or due to
some specific parameters set on the network._

* `signed_tx` is the human-readable signed transaction to make it easier for the
implementer to understand how the [signature envelope] looks like.

Expand Down
26 changes: 16 additions & 10 deletions go/consensus/api/transaction/testvectors/testvectors.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,32 @@ import (
const keySeedPrefix = "oasis-core test vectors: "

// TestVector is an Oasis transaction test vector.
type TestVector struct {
Kind string `json:"kind"`
SignatureContext string `json:"signature_context"`
Tx interface{} `json:"tx"`
SignedTx transaction.SignedTransaction `json:"signed_tx"`
EncodedTx []byte `json:"encoded_tx"`
EncodedSignedTx []byte `json:"encoded_signed_tx"`
type TestVector struct { // nolint: maligned
Kind string `json:"kind"`
SignatureContext string `json:"signature_context"`
Tx interface{} `json:"tx"`
// ValidTx indicates whether the transaction is (statically) valid.
// NOTE: This means that the transaction passes basic static validation, but
// it may still not be valid on the given network due to invalid nonce,
// or due to some specific parameters set on the network.
ValidTx bool `json:"valid_tx"`
SignedTx transaction.SignedTransaction `json:"signed_tx"`
EncodedTx []byte `json:"encoded_tx"`
EncodedSignedTx []byte `json:"encoded_signed_tx"`
// ValidSignature indicates whether the signature is valid.
ValidSignature bool `json:"valid_signature"`
SignerPrivateKey []byte `json:"signer_private_key"`
SignerPublicKey signature.PublicKey `json:"signer_public_key"`
}

// MakeTestVector generates a new test vector from a transaction.
func MakeTestVector(kind string, tx *transaction.Transaction) TestVector {
func MakeTestVector(kind string, tx *transaction.Transaction, validTx bool) TestVector {
signer := memorySigner.NewTestSigner(keySeedPrefix + kind)
return MakeTestVectorWithSigner(kind, tx, signer)
return MakeTestVectorWithSigner(kind, tx, validTx, signer)
}

// MakeTestVectorWithSigner generates a new test vector from a transaction using a specific signer.
func MakeTestVectorWithSigner(kind string, tx *transaction.Transaction, signer signature.Signer) TestVector {
func MakeTestVectorWithSigner(kind string, tx *transaction.Transaction, validTx bool, signer signature.Signer) TestVector {
sigTx, err := transaction.Sign(signer, tx)
if err != nil {
panic(err)
Expand All @@ -58,6 +63,7 @@ func MakeTestVectorWithSigner(kind string, tx *transaction.Transaction, signer s
Kind: kind,
SignatureContext: string(sigCtx),
Tx: prettyTx,
ValidTx: validTx,
SignedTx: *sigTx,
EncodedTx: cbor.Marshal(tx),
EncodedSignedTx: cbor.Marshal(sigTx),
Expand Down
60 changes: 45 additions & 15 deletions go/governance/gen_vectors/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"math"
"os"

beacon "github.com/oasisprotocol/oasis-core/go/beacon/api"
"github.com/oasisprotocol/oasis-core/go/common/cbor"
Expand All @@ -15,9 +16,30 @@ import (
"github.com/oasisprotocol/oasis-core/go/consensus/api/transaction"
"github.com/oasisprotocol/oasis-core/go/consensus/api/transaction/testvectors"
governance "github.com/oasisprotocol/oasis-core/go/governance/api"
"github.com/oasisprotocol/oasis-core/go/upgrade/api"
upgrade "github.com/oasisprotocol/oasis-core/go/upgrade/api"
)

func validSubmitProposalTxFields(v uint16, epoch uint64, handler string, target version.ProtocolVersions) bool {
if v < upgrade.MinDescriptorVersion || v > upgrade.MaxDescriptorVersion ||
epoch < uint64(upgrade.MinUpgradeEpoch) || epoch > uint64(upgrade.MaxUpgradeEpoch) ||
len(handler) < upgrade.MinUpgradeHandlerLength || len(handler) > upgrade.MaxUpgradeHandlerLength {
return false
}
if err := target.ValidateBasic(); err != nil {
return false
}
return true
}

func validCastVoteTxFields(vote governance.Vote) bool {
for _, v := range []governance.Vote{governance.VoteAbstain, governance.VoteYes, governance.VoteNo} {
if vote == v {
return true
}
}
return false
}

func main() {
// Configure chain context for all signatures using chain domain separation.
var chainContext hash.Hash
Expand All @@ -35,11 +57,12 @@ func main() {
} {
// Generate different nonces.
for _, nonce := range []uint64{0, 1, 10, 42, 1000, 1_000_000, 10_000_000, math.MaxUint64} {
// Valid submit upgrade proposal transaction.
for _, v := range []uint16{0, api.LatestDescriptorVersion} {
for _, epoch := range []uint64{0, 1000, 10_000_000} {
for _, handler := range []string{"", "descriptor-handler"} {
for _, version := range []version.ProtocolVersions{

// Generate upgrade proposal transactions.
for _, v := range []uint16{0, upgrade.LatestDescriptorVersion} {
for _, epoch := range []uint64{0, 1000, 10_000_000, math.MaxUint64 - 1, math.MaxUint64} {
for _, handler := range []string{"", "descriptor-handler", "tooooooo-long-33-char-description"} {
for _, target := range []version.ProtocolVersions{
{},
{ConsensusProtocol: version.Version{Major: 1, Minor: 2, Patch: 3}},
{
Expand All @@ -64,23 +87,24 @@ func main() {
for _, tx := range []*transaction.Transaction{
governance.NewSubmitProposalTx(nonce, fee, &governance.ProposalContent{
Upgrade: &governance.UpgradeProposal{
Descriptor: api.Descriptor{
Descriptor: upgrade.Descriptor{
Versioned: cbor.NewVersioned(v),
Handler: handler,
Target: version,
Target: target,
Epoch: beacon.EpochTime(epoch),
},
},
}),
} {
vectors = append(vectors, testvectors.MakeTestVector("SubmitProposal", tx))
validTx := validSubmitProposalTxFields(v, epoch, handler, target)
vectors = append(vectors, testvectors.MakeTestVector("SubmitProposal", tx, validTx))
}
}
}
}
}

// Valid submit cancel upgrade proposal transaction.
// Generate cancel upgrade proposal transactions.
for _, id := range []uint64{0, 1000, 10_000_000, math.MaxUint64} {
for _, tx := range []*transaction.Transaction{
governance.NewSubmitProposalTx(nonce, fee, &governance.ProposalContent{
Expand All @@ -89,27 +113,33 @@ func main() {
},
}),
} {
vectors = append(vectors, testvectors.MakeTestVector("SubmitProposal", tx))
vectors = append(vectors, testvectors.MakeTestVector("SubmitProposal", tx, true))
}
}

// Valid cast vote transactions.
// Generate cast vote transactions.
for _, id := range []uint64{0, 1000, 10_000_000, math.MaxUint64} {
for _, vote := range []governance.Vote{governance.VoteAbstain, governance.VoteYes, governance.VoteNo} {
for _, vote := range []governance.Vote{
governance.VoteAbstain, governance.VoteYes, governance.VoteNo,
} {
for _, tx := range []*transaction.Transaction{
governance.NewCastVoteTx(nonce, fee, &governance.ProposalVote{
ID: id,
Vote: vote,
}),
} {
vectors = append(vectors, testvectors.MakeTestVector("SubmitProposal", tx))
validTx := validCastVoteTxFields(vote)
vectors = append(vectors, testvectors.MakeTestVector("SubmitProposal", tx, validTx))
}
}
}
}
}

// Generate output.
jsonOut, _ := json.MarshalIndent(&vectors, "", " ")
jsonOut, err := json.MarshalIndent(&vectors, "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "Error encoding test vectors: %v\n", err)
}
fmt.Printf("%s", jsonOut)
}
53 changes: 34 additions & 19 deletions go/registry/gen_vectors/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"math"
"os"

"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-core/go/common/crypto/hash"
Expand All @@ -17,6 +18,13 @@ import (
registry "github.com/oasisprotocol/oasis-core/go/registry/api"
)

func validRegisterEntityTxFields(v uint16) bool {
if v < entity.MinDescriptorVersion || v > entity.MaxDescriptorVersion {
return false
}
return true
}

func main() {
// Configure chain context for all signatures using chain domain separation.
var chainContext hash.Hash
Expand All @@ -34,35 +42,42 @@ func main() {
} {
// Generate different nonces.
for _, nonce := range []uint64{0, 1, 10, 42, 1000, 1_000_000, 10_000_000, math.MaxUint64} {
// Valid register entity transactions.
entitySigner := memorySigner.NewTestSigner("oasis-core registry test vectors: RegisterEntity signer")
for _, numNodes := range []int{0, 1, 2, 5} {
ent := entity.Entity{
Versioned: cbor.NewVersioned(entity.LatestDescriptorVersion),
ID: entitySigner.Public(),
}
for i := 0; i < numNodes; i++ {
nodeSigner := memorySigner.NewTestSigner(fmt.Sprintf("oasis core registry test vectors: node signer %d", i))
ent.Nodes = append(ent.Nodes, nodeSigner.Public())
}
sigEnt, err := entity.SignEntity(entitySigner, registry.RegisterEntitySignatureContext, &ent)
if err != nil {
panic(err)

// Generate register entity transactions.
for _, v := range []uint16{1, entity.LatestDescriptorVersion} {
for _, numNodes := range []int{0, 1, 2, 5} {
entitySigner := memorySigner.NewTestSigner("oasis-core registry test vectors: RegisterEntity signer")
ent := entity.Entity{
Versioned: cbor.NewVersioned(v),
ID: entitySigner.Public(),
}
for i := 0; i < numNodes; i++ {
nodeSigner := memorySigner.NewTestSigner(fmt.Sprintf("oasis core registry test vectors: node signer %d", i))
ent.Nodes = append(ent.Nodes, nodeSigner.Public())
}
sigEnt, err := entity.SignEntity(entitySigner, registry.RegisterEntitySignatureContext, &ent)
if err != nil {
panic(err)
}
tx := registry.NewRegisterEntityTx(nonce, fee, sigEnt)
validTx := validRegisterEntityTxFields(v)
vectors = append(vectors, testvectors.MakeTestVectorWithSigner("RegisterEntity", tx, validTx, entitySigner))
}
tx := registry.NewRegisterEntityTx(nonce, fee, sigEnt)
vectors = append(vectors, testvectors.MakeTestVectorWithSigner("RegisterEntity", tx, entitySigner))
}

// Valid unfreeze node transactions.
// Generate unfreeze node transactions.
nodeSigner := memorySigner.NewTestSigner("oasis-core registry test vectors: UnfreezeNode signer")
tx := registry.NewUnfreezeNodeTx(nonce, fee, &registry.UnfreezeNode{
NodeID: nodeSigner.Public(),
})
vectors = append(vectors, testvectors.MakeTestVector("UnfreezeNode", tx))
vectors = append(vectors, testvectors.MakeTestVector("UnfreezeNode", tx, true))
}
}

// Generate output.
jsonOut, _ := json.MarshalIndent(&vectors, "", " ")
jsonOut, err := json.MarshalIndent(&vectors, "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "Error encoding test vectors: %v\n", err)
}
fmt.Printf("%s", jsonOut)
}
Loading

0 comments on commit 47a5aa3

Please sign in to comment.