neo-go/pkg/core/transaction/attribute.go
Roman Khimov 200cce9f02 transaction: fix Size() calculation for attribute
It wasn't accounting for attr.Data length properly.
2019-08-30 11:41:10 +03:00

97 lines
2.6 KiB
Go

package transaction
import (
"encoding/hex"
"encoding/json"
"fmt"
"io"
"github.com/CityOfZion/neo-go/pkg/util"
)
// Attribute represents a Transaction attribute.
type Attribute struct {
Usage AttrUsage
Data []byte
}
// DecodeBinary implements the Payload interface.
func (attr *Attribute) DecodeBinary(r io.Reader) error {
br := util.BinReader{R: r}
br.ReadLE(&attr.Usage)
// very special case
if attr.Usage == ECDH02 || attr.Usage == ECDH03 {
attr.Data = make([]byte, 33)
attr.Data[0] = byte(attr.Usage)
br.ReadLE(attr.Data[1:])
return br.Err
}
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:
datasize = 1
case Description, Remark, Remark1, Remark2, Remark3, Remark4,
Remark5, Remark6, Remark7, Remark8, Remark9, Remark10, Remark11,
Remark12, Remark13, Remark14, Remark15:
datasize = br.ReadVarUint()
default:
return fmt.Errorf("failed decoding TX attribute usage: 0x%2x", int(attr.Usage))
}
attr.Data = make([]byte, datasize)
br.ReadLE(attr.Data)
return br.Err
}
// EncodeBinary implements the Payload interface.
func (attr *Attribute) EncodeBinary(w io.Writer) error {
bw := util.BinWriter{W: w}
bw.WriteLE(&attr.Usage)
switch attr.Usage {
case ECDH02, ECDH03:
bw.WriteLE(attr.Data[1:])
case DescriptionURL, Description, Remark, Remark1, Remark2, Remark3, Remark4,
Remark5, Remark6, Remark7, Remark8, Remark9, Remark10, Remark11,
Remark12, Remark13, Remark14, Remark15:
bw.WriteVarUint(uint64(len(attr.Data)))
fallthrough
case Script, ContractHash, Vote, Hash1, Hash2, Hash3, Hash4, Hash5, Hash6,
Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15:
bw.WriteLE(attr.Data)
default:
return fmt.Errorf("failed encoding TX attribute usage: 0x%2x", attr.Usage)
}
return bw.Err
}
// Size returns the size in number bytes of the Attribute
func (attr *Attribute) Size() int {
sz := 1 // usage
switch attr.Usage {
case ContractHash, ECDH02, ECDH03, Vote,
Hash1, Hash2, Hash3, Hash4, Hash5, Hash6, Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15:
sz += 32 // uint8 + 32 = size(attrUsage) + 32
case Script:
sz += 20 // uint8 + 20 = size(attrUsage) + 20
case DescriptionURL:
sz += 1
default:
sz += util.GetVarSize(attr.Data)
}
return sz
}
// MarshalJSON implements the json Marschaller interface
func (attr *Attribute) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]string{
"usage": attr.Usage.String(),
"data": hex.EncodeToString(attr.Data),
})
}