neo-go/pkg/core/transaction/attribute.go
Roman Khimov 83febead59 transaction: add json.Unmarshaler to Attribute
It actually was missing and it might affect Transaction conversion to/from
JSON.
2020-05-14 17:28:14 +03:00

184 lines
4.2 KiB
Go

package transaction
import (
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/nspcc-dev/neo-go/pkg/io"
)
// Attribute represents a Transaction attribute.
type Attribute struct {
Usage AttrUsage
Data []byte
}
// attrJSON is used for JSON I/O of Attribute.
type attrJSON struct {
Usage string `json:"usage"`
Data string `json:"data"`
}
// DecodeBinary implements Serializable interface.
func (attr *Attribute) DecodeBinary(br *io.BinReader) {
attr.Usage = AttrUsage(br.ReadB())
// very special case
if attr.Usage == ECDH02 || attr.Usage == ECDH03 {
attr.Data = make([]byte, 33)
attr.Data[0] = byte(attr.Usage)
br.ReadBytes(attr.Data[1:])
return
}
var datasize uint64
switch attr.Usage {
case ContractHash, Vote, Hash1, Hash2, Hash3, Hash4, Hash5,
Hash6, Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13,
Hash14, Hash15:
datasize = 32
case Script:
datasize = 20
case DescriptionURL:
// It's not VarUint as per C# implementation, dunno why
var urllen = br.ReadB()
datasize = uint64(urllen)
case Description, Remark, Remark1, Remark2, Remark3, Remark4,
Remark5, Remark6, Remark7, Remark8, Remark9, Remark10, Remark11,
Remark12, Remark13, Remark14, Remark15:
datasize = br.ReadVarUint()
default:
br.Err = fmt.Errorf("failed decoding TX attribute usage: 0x%2x", int(attr.Usage))
return
}
attr.Data = make([]byte, datasize)
br.ReadBytes(attr.Data)
}
// EncodeBinary implements Serializable interface.
func (attr *Attribute) EncodeBinary(bw *io.BinWriter) {
bw.WriteB(byte(attr.Usage))
switch attr.Usage {
case ECDH02, ECDH03:
bw.WriteBytes(attr.Data[1:])
case Description, Remark, Remark1, Remark2, Remark3, Remark4,
Remark5, Remark6, Remark7, Remark8, Remark9, Remark10, Remark11,
Remark12, Remark13, Remark14, Remark15:
bw.WriteVarBytes(attr.Data)
case DescriptionURL:
bw.WriteB(byte(len(attr.Data)))
fallthrough
case Script, ContractHash, Vote, Hash1, Hash2, Hash3, Hash4, Hash5, Hash6,
Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15:
bw.WriteBytes(attr.Data)
default:
bw.Err = fmt.Errorf("failed encoding TX attribute usage: 0x%2x", attr.Usage)
}
}
// MarshalJSON implements the json Marshaller interface.
func (attr *Attribute) MarshalJSON() ([]byte, error) {
return json.Marshal(attrJSON{
Usage: attr.Usage.String(),
Data: hex.EncodeToString(attr.Data),
})
}
// UnmarshalJSON implements the json.Unmarshaller interface.
func (attr *Attribute) UnmarshalJSON(data []byte) error {
aj := new(attrJSON)
err := json.Unmarshal(data, aj)
if err != nil {
return err
}
binData, err := hex.DecodeString(aj.Data)
if err != nil {
return err
}
switch aj.Usage {
case "ContractHash":
attr.Usage = ContractHash
case "ECDH02":
attr.Usage = ECDH02
case "ECDH03":
attr.Usage = ECDH03
case "Script":
attr.Usage = Script
case "Vote":
attr.Usage = Vote
case "CertURL":
attr.Usage = CertURL
case "DescriptionURL":
attr.Usage = DescriptionURL
case "Description":
attr.Usage = Description
case "Hash1":
attr.Usage = Hash1
case "Hash2":
attr.Usage = Hash2
case "Hash3":
attr.Usage = Hash3
case "Hash4":
attr.Usage = Hash4
case "Hash5":
attr.Usage = Hash5
case "Hash6":
attr.Usage = Hash6
case "Hash7":
attr.Usage = Hash7
case "Hash8":
attr.Usage = Hash8
case "Hash9":
attr.Usage = Hash9
case "Hash10":
attr.Usage = Hash10
case "Hash11":
attr.Usage = Hash11
case "Hash12":
attr.Usage = Hash12
case "Hash13":
attr.Usage = Hash13
case "Hash14":
attr.Usage = Hash14
case "Hash15":
attr.Usage = Hash15
case "Remark":
attr.Usage = Remark
case "Remark1":
attr.Usage = Remark1
case "Remark2":
attr.Usage = Remark2
case "Remark3":
attr.Usage = Remark3
case "Remark4":
attr.Usage = Remark4
case "Remark5":
attr.Usage = Remark5
case "Remark6":
attr.Usage = Remark6
case "Remark7":
attr.Usage = Remark7
case "Remark8":
attr.Usage = Remark8
case "Remark9":
attr.Usage = Remark9
case "Remark10":
attr.Usage = Remark10
case "Remark11":
attr.Usage = Remark11
case "Remark12":
attr.Usage = Remark12
case "Remark13":
attr.Usage = Remark13
case "Remark14":
attr.Usage = Remark14
case "Remark15":
attr.Usage = Remark15
default:
return errors.New("wrong Usage")
}
attr.Data = binData
return nil
}