forked from TrueCloudLab/neoneo-go
smartcontract: use new VerifiableDecodable for ParameterContext
And implement it for Transaction, the only user of ParameterContext for now. Which make correct signing/verifying possible for cases when serialization for general transmission and signing differ.
This commit is contained in:
parent
dde0763840
commit
a7cce3f894
3 changed files with 43 additions and 15 deletions
|
@ -112,8 +112,9 @@ func (t *Transaction) VerificationHash() util.Uint256 {
|
||||||
return t.verificationHash
|
return t.verificationHash
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodeBinary implements Serializable interface.
|
// decodeHashableFields decodes the fields that are used for signing the
|
||||||
func (t *Transaction) DecodeBinary(br *io.BinReader) {
|
// transaction, which are all fields except the scripts.
|
||||||
|
func (t *Transaction) decodeHashableFields(br *io.BinReader) {
|
||||||
t.Version = uint8(br.ReadB())
|
t.Version = uint8(br.ReadB())
|
||||||
if t.Version > 0 {
|
if t.Version > 0 {
|
||||||
br.Err = errors.New("only version 0 is supported")
|
br.Err = errors.New("only version 0 is supported")
|
||||||
|
@ -154,7 +155,14 @@ func (t *Transaction) DecodeBinary(br *io.BinReader) {
|
||||||
br.Err = errors.New("no script")
|
br.Err = errors.New("no script")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeBinary implements Serializable interface.
|
||||||
|
func (t *Transaction) DecodeBinary(br *io.BinReader) {
|
||||||
|
t.decodeHashableFields(br)
|
||||||
|
if br.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
br.ReadArray(&t.Scripts)
|
br.ReadArray(&t.Scripts)
|
||||||
|
|
||||||
// Create the hash of the transaction at decode, so we dont need
|
// Create the hash of the transaction at decode, so we dont need
|
||||||
|
@ -218,6 +226,23 @@ func (t *Transaction) GetSignedPart() []byte {
|
||||||
return buf.Bytes()
|
return buf.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecodeSignedPart decodes a part of transaction from GetSignedPart data.
|
||||||
|
func (t *Transaction) DecodeSignedPart(buf []byte) error {
|
||||||
|
r := io.NewBinReaderFromBuf(buf)
|
||||||
|
t.decodeHashableFields(r)
|
||||||
|
if r.Err != nil {
|
||||||
|
return r.Err
|
||||||
|
}
|
||||||
|
// Ensure all the data was read.
|
||||||
|
_ = r.ReadB()
|
||||||
|
if r.Err == nil {
|
||||||
|
return errors.New("additional data after the signed part")
|
||||||
|
}
|
||||||
|
t.Scripts = make([]Witness, 0)
|
||||||
|
_ = t.createHash()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Bytes converts the transaction to []byte
|
// Bytes converts the transaction to []byte
|
||||||
func (t *Transaction) Bytes() []byte {
|
func (t *Transaction) Bytes() []byte {
|
||||||
buf := io.NewBufBinWriter()
|
buf := io.NewBufBinWriter()
|
||||||
|
|
|
@ -4,3 +4,10 @@ package crypto
|
||||||
type Verifiable interface {
|
type Verifiable interface {
|
||||||
GetSignedPart() []byte
|
GetSignedPart() []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VerifiableDecodable represents an object which can be both verified and
|
||||||
|
// decoded from given data.
|
||||||
|
type VerifiableDecodable interface {
|
||||||
|
Verifiable
|
||||||
|
DecodeSignedPart([]byte) error
|
||||||
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/crypto"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/io"
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||||
|
@ -24,7 +25,7 @@ type ParameterContext struct {
|
||||||
// Type is a type of a verifiable item.
|
// Type is a type of a verifiable item.
|
||||||
Type string
|
Type string
|
||||||
// Verifiable is an object which can be (de-)serialized.
|
// Verifiable is an object which can be (de-)serialized.
|
||||||
Verifiable io.Serializable
|
Verifiable crypto.VerifiableDecodable
|
||||||
// Items is a map from script hashes to context items.
|
// Items is a map from script hashes to context items.
|
||||||
Items map[util.Uint160]*Item
|
Items map[util.Uint160]*Item
|
||||||
}
|
}
|
||||||
|
@ -41,7 +42,7 @@ type sigWithIndex struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewParameterContext returns ParameterContext with the specified type and item to sign.
|
// NewParameterContext returns ParameterContext with the specified type and item to sign.
|
||||||
func NewParameterContext(typ string, verif io.Serializable) *ParameterContext {
|
func NewParameterContext(typ string, verif crypto.VerifiableDecodable) *ParameterContext {
|
||||||
return &ParameterContext{
|
return &ParameterContext{
|
||||||
Type: typ,
|
Type: typ,
|
||||||
Verifiable: verif,
|
Verifiable: verif,
|
||||||
|
@ -144,11 +145,7 @@ func (c *ParameterContext) getItemForContract(ctr *wallet.Contract) *Item {
|
||||||
|
|
||||||
// MarshalJSON implements json.Marshaler interface.
|
// MarshalJSON implements json.Marshaler interface.
|
||||||
func (c ParameterContext) MarshalJSON() ([]byte, error) {
|
func (c ParameterContext) MarshalJSON() ([]byte, error) {
|
||||||
bw := io.NewBufBinWriter()
|
verif := c.Verifiable.GetSignedPart()
|
||||||
c.Verifiable.EncodeBinary(bw.BinWriter)
|
|
||||||
if bw.Err != nil {
|
|
||||||
return nil, bw.Err
|
|
||||||
}
|
|
||||||
items := make(map[string]json.RawMessage, len(c.Items))
|
items := make(map[string]json.RawMessage, len(c.Items))
|
||||||
for u := range c.Items {
|
for u := range c.Items {
|
||||||
data, err := json.Marshal(c.Items[u])
|
data, err := json.Marshal(c.Items[u])
|
||||||
|
@ -159,7 +156,7 @@ func (c ParameterContext) MarshalJSON() ([]byte, error) {
|
||||||
}
|
}
|
||||||
pc := ¶mContext{
|
pc := ¶mContext{
|
||||||
Type: c.Type,
|
Type: c.Type,
|
||||||
Hex: hex.EncodeToString(bw.Bytes()),
|
Hex: hex.EncodeToString(verif),
|
||||||
Items: items,
|
Items: items,
|
||||||
}
|
}
|
||||||
return json.Marshal(pc)
|
return json.Marshal(pc)
|
||||||
|
@ -176,17 +173,16 @@ func (c *ParameterContext) UnmarshalJSON(data []byte) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var verif io.Serializable
|
var verif crypto.VerifiableDecodable
|
||||||
switch pc.Type {
|
switch pc.Type {
|
||||||
case "Neo.Core.ContractTransaction":
|
case "Neo.Core.ContractTransaction":
|
||||||
verif = new(transaction.Transaction)
|
verif = new(transaction.Transaction)
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("unsupported type: %s", c.Type)
|
return fmt.Errorf("unsupported type: %s", c.Type)
|
||||||
}
|
}
|
||||||
br := io.NewBinReaderFromBuf(data)
|
err = verif.DecodeSignedPart(data)
|
||||||
verif.DecodeBinary(br)
|
if err != nil {
|
||||||
if br.Err != nil {
|
return err
|
||||||
return br.Err
|
|
||||||
}
|
}
|
||||||
items := make(map[util.Uint160]*Item, len(pc.Items))
|
items := make(map[util.Uint160]*Item, len(pc.Items))
|
||||||
for h := range pc.Items {
|
for h := range pc.Items {
|
||||||
|
|
Loading…
Add table
Reference in a new issue