mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2024-11-26 09:42:22 +00:00
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
|
||||
}
|
||||
|
||||
// DecodeBinary implements Serializable interface.
|
||||
func (t *Transaction) DecodeBinary(br *io.BinReader) {
|
||||
// decodeHashableFields decodes the fields that are used for signing the
|
||||
// transaction, which are all fields except the scripts.
|
||||
func (t *Transaction) decodeHashableFields(br *io.BinReader) {
|
||||
t.Version = uint8(br.ReadB())
|
||||
if t.Version > 0 {
|
||||
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")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// DecodeBinary implements Serializable interface.
|
||||
func (t *Transaction) DecodeBinary(br *io.BinReader) {
|
||||
t.decodeHashableFields(br)
|
||||
if br.Err != nil {
|
||||
return
|
||||
}
|
||||
br.ReadArray(&t.Scripts)
|
||||
|
||||
// Create the hash of the transaction at decode, so we dont need
|
||||
|
@ -218,6 +226,23 @@ func (t *Transaction) GetSignedPart() []byte {
|
|||
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
|
||||
func (t *Transaction) Bytes() []byte {
|
||||
buf := io.NewBufBinWriter()
|
||||
|
|
|
@ -4,3 +4,10 @@ package crypto
|
|||
type Verifiable interface {
|
||||
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"
|
||||
|
||||
"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/io"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
||||
|
@ -24,7 +25,7 @@ type ParameterContext struct {
|
|||
// Type is a type of a verifiable item.
|
||||
Type string
|
||||
// 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 map[util.Uint160]*Item
|
||||
}
|
||||
|
@ -41,7 +42,7 @@ type sigWithIndex struct {
|
|||
}
|
||||
|
||||
// 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{
|
||||
Type: typ,
|
||||
Verifiable: verif,
|
||||
|
@ -144,11 +145,7 @@ func (c *ParameterContext) getItemForContract(ctr *wallet.Contract) *Item {
|
|||
|
||||
// MarshalJSON implements json.Marshaler interface.
|
||||
func (c ParameterContext) MarshalJSON() ([]byte, error) {
|
||||
bw := io.NewBufBinWriter()
|
||||
c.Verifiable.EncodeBinary(bw.BinWriter)
|
||||
if bw.Err != nil {
|
||||
return nil, bw.Err
|
||||
}
|
||||
verif := c.Verifiable.GetSignedPart()
|
||||
items := make(map[string]json.RawMessage, len(c.Items))
|
||||
for u := range c.Items {
|
||||
data, err := json.Marshal(c.Items[u])
|
||||
|
@ -159,7 +156,7 @@ func (c ParameterContext) MarshalJSON() ([]byte, error) {
|
|||
}
|
||||
pc := ¶mContext{
|
||||
Type: c.Type,
|
||||
Hex: hex.EncodeToString(bw.Bytes()),
|
||||
Hex: hex.EncodeToString(verif),
|
||||
Items: items,
|
||||
}
|
||||
return json.Marshal(pc)
|
||||
|
@ -176,17 +173,16 @@ func (c *ParameterContext) UnmarshalJSON(data []byte) error {
|
|||
return err
|
||||
}
|
||||
|
||||
var verif io.Serializable
|
||||
var verif crypto.VerifiableDecodable
|
||||
switch pc.Type {
|
||||
case "Neo.Core.ContractTransaction":
|
||||
verif = new(transaction.Transaction)
|
||||
default:
|
||||
return fmt.Errorf("unsupported type: %s", c.Type)
|
||||
}
|
||||
br := io.NewBinReaderFromBuf(data)
|
||||
verif.DecodeBinary(br)
|
||||
if br.Err != nil {
|
||||
return br.Err
|
||||
err = verif.DecodeSignedPart(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
items := make(map[util.Uint160]*Item, len(pc.Items))
|
||||
for h := range pc.Items {
|
||||
|
|
Loading…
Reference in a new issue