2018-03-04 13:56:49 +00:00
|
|
|
package transaction
|
|
|
|
|
|
|
|
import (
|
2019-02-20 17:39:32 +00:00
|
|
|
"encoding/hex"
|
|
|
|
"encoding/json"
|
2020-05-13 21:17:39 +00:00
|
|
|
"errors"
|
2018-03-17 11:53:21 +00:00
|
|
|
"fmt"
|
2018-03-04 13:56:49 +00:00
|
|
|
|
2020-03-03 14:21:42 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
2018-03-04 13:56:49 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Attribute represents a Transaction attribute.
|
|
|
|
type Attribute struct {
|
2020-05-13 21:17:39 +00:00
|
|
|
Usage AttrUsage
|
|
|
|
Data []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
// attrJSON is used for JSON I/O of Attribute.
|
|
|
|
type attrJSON struct {
|
|
|
|
Usage string `json:"usage"`
|
|
|
|
Data string `json:"data"`
|
2018-03-04 13:56:49 +00:00
|
|
|
}
|
|
|
|
|
2019-09-16 16:31:49 +00:00
|
|
|
// DecodeBinary implements Serializable interface.
|
|
|
|
func (attr *Attribute) DecodeBinary(br *io.BinReader) {
|
2019-12-12 17:17:50 +00:00
|
|
|
attr.Usage = AttrUsage(br.ReadB())
|
2019-08-28 16:27:06 +00:00
|
|
|
|
|
|
|
// very special case
|
2018-03-04 13:56:49 +00:00
|
|
|
if attr.Usage == ECDH02 || attr.Usage == ECDH03 {
|
|
|
|
attr.Data = make([]byte, 33)
|
|
|
|
attr.Data[0] = byte(attr.Usage)
|
2019-12-06 15:37:46 +00:00
|
|
|
br.ReadBytes(attr.Data[1:])
|
2019-09-16 16:31:49 +00:00
|
|
|
return
|
2018-03-04 13:56:49 +00:00
|
|
|
}
|
2019-08-28 16:27:06 +00:00
|
|
|
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 DescriptionURL:
|
2019-08-30 12:35:38 +00:00
|
|
|
// It's not VarUint as per C# implementation, dunno why
|
2019-12-12 17:17:50 +00:00
|
|
|
var urllen = br.ReadB()
|
2019-08-30 12:35:38 +00:00
|
|
|
datasize = uint64(urllen)
|
2019-08-28 16:27:06 +00:00
|
|
|
case Description, Remark, Remark1, Remark2, Remark3, Remark4,
|
|
|
|
Remark5, Remark6, Remark7, Remark8, Remark9, Remark10, Remark11,
|
|
|
|
Remark12, Remark13, Remark14, Remark15:
|
|
|
|
datasize = br.ReadVarUint()
|
|
|
|
default:
|
2019-09-16 16:31:49 +00:00
|
|
|
br.Err = fmt.Errorf("failed decoding TX attribute usage: 0x%2x", int(attr.Usage))
|
|
|
|
return
|
2018-03-04 13:56:49 +00:00
|
|
|
}
|
2019-08-28 16:27:06 +00:00
|
|
|
attr.Data = make([]byte, datasize)
|
2019-12-06 15:37:46 +00:00
|
|
|
br.ReadBytes(attr.Data)
|
2018-03-04 13:56:49 +00:00
|
|
|
}
|
|
|
|
|
2019-09-16 16:31:49 +00:00
|
|
|
// EncodeBinary implements Serializable interface.
|
|
|
|
func (attr *Attribute) EncodeBinary(bw *io.BinWriter) {
|
2019-12-12 17:17:50 +00:00
|
|
|
bw.WriteB(byte(attr.Usage))
|
2019-08-28 16:27:06 +00:00
|
|
|
switch attr.Usage {
|
|
|
|
case ECDH02, ECDH03:
|
2019-11-22 10:34:06 +00:00
|
|
|
bw.WriteBytes(attr.Data[1:])
|
2019-08-30 12:35:38 +00:00
|
|
|
case Description, Remark, Remark1, Remark2, Remark3, Remark4,
|
2019-08-28 16:27:06 +00:00
|
|
|
Remark5, Remark6, Remark7, Remark8, Remark9, Remark10, Remark11,
|
|
|
|
Remark12, Remark13, Remark14, Remark15:
|
2019-11-22 10:34:06 +00:00
|
|
|
bw.WriteVarBytes(attr.Data)
|
2019-08-30 12:35:38 +00:00
|
|
|
case DescriptionURL:
|
2019-12-12 17:17:50 +00:00
|
|
|
bw.WriteB(byte(len(attr.Data)))
|
2019-08-28 16:27:06 +00:00
|
|
|
fallthrough
|
2020-04-29 07:49:09 +00:00
|
|
|
case ContractHash, Vote, Hash1, Hash2, Hash3, Hash4, Hash5, Hash6,
|
2019-08-28 16:27:06 +00:00
|
|
|
Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15:
|
2019-11-22 10:34:06 +00:00
|
|
|
bw.WriteBytes(attr.Data)
|
2019-08-28 16:27:06 +00:00
|
|
|
default:
|
2019-09-16 16:31:49 +00:00
|
|
|
bw.Err = fmt.Errorf("failed encoding TX attribute usage: 0x%2x", attr.Usage)
|
2018-03-04 13:56:49 +00:00
|
|
|
}
|
|
|
|
}
|
2019-02-20 17:39:32 +00:00
|
|
|
|
2019-10-22 14:56:03 +00:00
|
|
|
// MarshalJSON implements the json Marshaller interface.
|
2019-02-20 17:39:32 +00:00
|
|
|
func (attr *Attribute) MarshalJSON() ([]byte, error) {
|
2020-05-13 21:17:39 +00:00
|
|
|
return json.Marshal(attrJSON{
|
|
|
|
Usage: attr.Usage.String(),
|
|
|
|
Data: hex.EncodeToString(attr.Data),
|
2019-02-20 17:39:32 +00:00
|
|
|
})
|
|
|
|
}
|
2020-05-13 21:17:39 +00:00
|
|
|
|
|
|
|
// 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 "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
|
|
|
|
}
|