Skip to content

Commit

Permalink
go/common/prettyprint: Add PrettyType for use in test vectors
Browse files Browse the repository at this point in the history
  • Loading branch information
kostko committed Jun 29, 2020
1 parent c4e8991 commit 617ce09
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 38 deletions.
1 change: 1 addition & 0 deletions .changelog/3059.internal.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
go/common/prettyprint: Add PrettyType for use in test vectors
32 changes: 28 additions & 4 deletions go/common/crypto/signature/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -453,13 +453,25 @@ func (p PrettySigned) PrettyPrint(prefix string, w io.Writer) {
fmt.Fprintf(w, "%s%s\n", prefix, data)
}

// PrettyType returns a representation of the type that can be used for pretty printing.
func (p PrettySigned) PrettyType() (interface{}, error) {
return p, nil
}

// NewPrettySigned creates a new PrettySigned instance that can be
// used for pretty printing signed values.
func NewPrettySigned(s Signed, b interface{}) *PrettySigned {
func NewPrettySigned(s Signed, b interface{}) (*PrettySigned, error) {
if pp, ok := b.(prettyprint.PrettyPrinter); ok {
var err error
if b, err = pp.PrettyType(); err != nil {
return nil, fmt.Errorf("failed to pretty print body: %w", err)
}
}

return &PrettySigned{
Body: b,
Signature: s.Signature,
}
}, nil
}

// MultiSigned is a blob signed by multiple public keys.
Expand Down Expand Up @@ -557,13 +569,25 @@ func (p PrettyMultiSigned) PrettyPrint(prefix string, w io.Writer) {
fmt.Fprintf(w, "%s%s\n", prefix, data)
}

// PrettyType returns a representation of the type that can be used for pretty printing.
func (p PrettyMultiSigned) PrettyType() (interface{}, error) {
return p, nil
}

// NewPrettyMultiSigned creates a new PrettySigned instance that can be
// used for pretty printing multi-signed values.
func NewPrettyMultiSigned(s MultiSigned, b interface{}) *PrettyMultiSigned {
func NewPrettyMultiSigned(s MultiSigned, b interface{}) (*PrettyMultiSigned, error) {
if pp, ok := b.(prettyprint.PrettyPrinter); ok {
var err error
if b, err = pp.PrettyType(); err != nil {
return nil, fmt.Errorf("failed to pretty print body: %w", err)
}
}

return &PrettyMultiSigned{
Body: b,
Signatures: s.Signatures,
}
}, nil
}

// SignedPublicKey is a signed blob containing a PublicKey.
Expand Down
18 changes: 13 additions & 5 deletions go/common/entity/entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,14 +189,22 @@ func (s *SignedEntity) Open(context signature.Context, entity *Entity) error { /
// PrettyPrint writes a pretty-printed representation of the type
// to the given writer.
func (s SignedEntity) PrettyPrint(prefix string, w io.Writer) {
var e Entity
if err := cbor.Unmarshal(s.Signed.Blob, &e); err != nil {
fmt.Fprintf(w, "%s<malformed: %s>\n", prefix, err)
pt, err := s.PrettyType()
if err != nil {
fmt.Fprintf(w, "%s<error: %s>\n", prefix, err)
return
}

pp := signature.NewPrettySigned(s.Signed, e)
pp.PrettyPrint(prefix, w)
pt.(prettyprint.PrettyPrinter).PrettyPrint(prefix, w)
}

// PrettyType returns a representation of the type that can be used for pretty printing.
func (s SignedEntity) PrettyType() (interface{}, error) {
var e Entity
if err := cbor.Unmarshal(s.Signed.Blob, &e); err != nil {
return nil, fmt.Errorf("malformed signed blob: %w", err)
}
return signature.NewPrettySigned(s.Signed, e)
}

// SignEntity serializes the Entity and signs the result.
Expand Down
18 changes: 13 additions & 5 deletions go/common/node/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -394,14 +394,22 @@ func (s *MultiSignedNode) Open(context signature.Context, node *Node) error {
// PrettyPrint writes a pretty-printed representation of the type
// to the given writer.
func (s MultiSignedNode) PrettyPrint(prefix string, w io.Writer) {
var n Node
if err := cbor.Unmarshal(s.MultiSigned.Blob, &n); err != nil {
fmt.Fprintf(w, "%s<malformed: %s>\n", prefix, err)
pt, err := s.PrettyType()
if err != nil {
fmt.Fprintf(w, "%s<error: %s>\n", prefix, err)
return
}

pp := signature.NewPrettyMultiSigned(s.MultiSigned, n)
pp.PrettyPrint(prefix, w)
pt.(prettyprint.PrettyPrinter).PrettyPrint(prefix, w)
}

// PrettyType returns a representation of the type that can be used for pretty printing.
func (s MultiSignedNode) PrettyType() (interface{}, error) {
var n Node
if err := cbor.Unmarshal(s.MultiSigned.Blob, &n); err != nil {
return nil, fmt.Errorf("malformed signed blob: %w", err)
}
return signature.NewPrettyMultiSigned(s.MultiSigned, n)
}

// MultiSignNode serializes the Node and multi-signs the result.
Expand Down
3 changes: 3 additions & 0 deletions go/common/prettyprint/prettyprint.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ type PrettyPrinter interface {
// PrettyPrint writes a pretty-printed representation of the type
// to the given writer.
PrettyPrint(prefix string, w io.Writer)

// PrettyType returns a representation of the type that can be used for pretty printing.
PrettyType() (interface{}, error)
}
24 changes: 5 additions & 19 deletions go/consensus/api/transaction/testvectors/testvectors.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,11 @@ import (

const keySeedPrefix = "oasis-core test vectors: "

// TestTransactions is a test transaction suitable for JSON serialization.
//
// The only difference between this and transaction.Transaction is that
// body is not represented as raw bytes but rather as an interface so
// it contains the actual body document.
type TestTransaction struct {
Nonce uint64 `json:"nonce"`
Fee *transaction.Fee `json:"fee,omitempty"`
Method transaction.MethodName `json:"method"`
Body interface{} `json:"body,omitempty"`
}

// TestVector is a staking message test vector.
type TestVector struct {
Kind string `json:"kind"`
SignatureContext string `json:"signature_context"`
Tx TestTransaction `json:"tx"`
Tx interface{} `json:"tx"`
SignedTx transaction.SignedTransaction `json:"signed_tx"`
EncodedTx []byte `json:"encoded_tx"`
EncodedSignedTx []byte `json:"encoded_signed_tx"`
Expand Down Expand Up @@ -60,17 +48,15 @@ func MakeTestVectorWithSigner(kind string, tx *transaction.Transaction, signer s
panic(err)
}

testTx := TestTransaction{
Nonce: tx.Nonce,
Fee: tx.Fee,
Method: tx.Method,
Body: v,
prettyTx, err := tx.PrettyType()
if err != nil {
panic(err)
}

return TestVector{
Kind: kind,
SignatureContext: string(sigCtx),
Tx: testTx,
Tx: prettyTx,
SignedTx: *sigTx,
EncodedTx: cbor.Marshal(tx),
EncodedSignedTx: cbor.Marshal(sigTx),
Expand Down
49 changes: 49 additions & 0 deletions go/consensus/api/transaction/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,35 @@ func (t Transaction) PrettyPrint(prefix string, w io.Writer) {
fmt.Fprintf(w, "%s %s\n", prefix, data)
}

// PrettyType returns a representation of the type that can be used for pretty printing.
func (t *Transaction) PrettyType() (interface{}, error) {
bodyType := t.Method.BodyType()
if bodyType == nil {
return nil, fmt.Errorf("unknown method body type")
}

// Deserialize into correct type.
body := reflect.New(reflect.TypeOf(bodyType)).Interface()
if err := cbor.Unmarshal(t.Body, body); err != nil {
return nil, fmt.Errorf("failed to unmarshal transaction body: %w", err)
}

// If the body type supports pretty printing, use that.
if pp, ok := body.(prettyprint.PrettyPrinter); ok {
var err error
if body, err = pp.PrettyType(); err != nil {
return nil, fmt.Errorf("failed to pretty print transaction body: %w", err)
}
}

return &PrettyTransaction{
Nonce: t.Nonce,
Fee: t.Fee,
Method: t.Method,
Body: body,
}, nil
}

// SanityCheck performs a basic sanity check on the transaction.
func (t *Transaction) SanityCheck() error {
return t.Method.SanityCheck()
Expand All @@ -106,6 +135,17 @@ func NewTransaction(nonce uint64, fee *Fee, method MethodName, body interface{})
}
}

// PrettyTransaction is used for pretty-printing transactions so that the actual content is
// displayed instead of the binary blob.
//
// It should only be used for pretty printing.
type PrettyTransaction struct {
Nonce uint64 `json:"nonce"`
Fee *Fee `json:"fee,omitempty"`
Method MethodName `json:"method"`
Body interface{} `json:"body,omitempty"`
}

// SignedTransaction is a signed transaction.
type SignedTransaction struct {
signature.Signed
Expand Down Expand Up @@ -142,6 +182,15 @@ func (s SignedTransaction) PrettyPrint(prefix string, w io.Writer) {
tx.PrettyPrint(prefix+" ", w)
}

// PrettyType returns a representation of the type that can be used for pretty printing.
func (s SignedTransaction) PrettyType() (interface{}, error) {
var tx Transaction
if err := cbor.Unmarshal(s.Blob, &tx); err != nil {
return nil, fmt.Errorf("malformed signed blob: %w", err)
}
return signature.NewPrettySigned(s.Signed, tx)
}

// Open first verifies the blob signature and then unmarshals the blob.
func (s *SignedTransaction) Open(tx *Transaction) error { // nolint: interfacer
return s.Signed.Open(SignatureContext, tx)
Expand Down
18 changes: 13 additions & 5 deletions go/registry/api/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,14 +317,22 @@ func (s *SignedRuntime) Open(context signature.Context, runtime *Runtime) error
// PrettyPrint writes a pretty-printed representation of the type
// to the given writer.
func (s SignedRuntime) PrettyPrint(prefix string, w io.Writer) {
var rt Runtime
if err := cbor.Unmarshal(s.Signed.Blob, &rt); err != nil {
fmt.Fprintf(w, "%s<malformed: %s>\n", prefix, err)
pt, err := s.PrettyType()
if err != nil {
fmt.Fprintf(w, "%s<error: %s>\n", prefix, err)
return
}

pp := signature.NewPrettySigned(s.Signed, rt)
pp.PrettyPrint(prefix, w)
pt.(prettyprint.PrettyPrinter).PrettyPrint(prefix, w)
}

// PrettyType returns a representation of the type that can be used for pretty printing.
func (s SignedRuntime) PrettyType() (interface{}, error) {
var rt Runtime
if err := cbor.Unmarshal(s.Signed.Blob, &rt); err != nil {
return nil, fmt.Errorf("malformed signed blob: %w", err)
}
return signature.NewPrettySigned(s.Signed, rt)
}

// SignRuntime serializes the Runtime and signs the result.
Expand Down

0 comments on commit 617ce09

Please sign in to comment.