transaction: avoid ReadArray()

Reflection adds some real cost to it:

name               old time/op    new time/op    delta
DecodeBinary-8       3.14µs ± 5%    2.89µs ± 3%   -8.19%  (p=0.000 n=10+10)
DecodeJSON-8         12.6µs ± 3%    13.0µs ± 1%   +3.77%  (p=0.000 n=10+10)
DecodeFromBytes-8    2.73µs ± 2%    2.37µs ± 1%  -13.12%  (p=0.000 n=9+9)

name               old alloc/op   new alloc/op   delta
DecodeBinary-8       1.82kB ± 0%    1.75kB ± 0%   -3.95%  (p=0.000 n=10+10)
DecodeJSON-8         3.49kB ± 0%    3.49kB ± 0%     ~     (all equal)
DecodeFromBytes-8    1.44kB ± 0%    1.37kB ± 0%   -5.00%  (p=0.000 n=10+10)

name               old allocs/op  new allocs/op  delta
DecodeBinary-8         29.0 ± 0%      26.0 ± 0%  -10.34%  (p=0.000 n=10+10)
DecodeJSON-8           58.0 ± 0%      58.0 ± 0%     ~     (all equal)
DecodeFromBytes-8      21.0 ± 0%      18.0 ± 0%  -14.29%  (p=0.000 n=10+10)
This commit is contained in:
Roman Khimov 2021-08-04 23:34:57 +03:00
parent d2732a71d8
commit 6d10cdc2f6

View file

@ -135,8 +135,30 @@ func (t *Transaction) decodeHashableFields(br *io.BinReader) {
t.SystemFee = int64(br.ReadU64LE()) t.SystemFee = int64(br.ReadU64LE())
t.NetworkFee = int64(br.ReadU64LE()) t.NetworkFee = int64(br.ReadU64LE())
t.ValidUntilBlock = br.ReadU32LE() t.ValidUntilBlock = br.ReadU32LE()
br.ReadArray(&t.Signers, MaxAttributes) nsigners := br.ReadVarUint()
br.ReadArray(&t.Attributes, MaxAttributes-len(t.Signers)) if br.Err != nil {
return
}
if nsigners > MaxAttributes {
br.Err = errors.New("too many signers")
return
} else if nsigners == 0 {
br.Err = errors.New("missing signers")
return
}
t.Signers = make([]Signer, nsigners)
for i := 0; i < int(nsigners); i++ {
t.Signers[i].DecodeBinary(br)
}
nattrs := br.ReadVarUint()
if nattrs > MaxAttributes-nsigners {
br.Err = errors.New("too many attributes")
return
}
t.Attributes = make([]Attribute, nattrs)
for i := 0; i < int(nattrs); i++ {
t.Attributes[i].DecodeBinary(br)
}
t.Script = br.ReadVarBytes(MaxScriptLength) t.Script = br.ReadVarBytes(MaxScriptLength)
if br.Err == nil { if br.Err == nil {
br.Err = t.isValid() br.Err = t.isValid()
@ -148,11 +170,18 @@ func (t *Transaction) decodeBinaryNoSize(br *io.BinReader) {
if br.Err != nil { if br.Err != nil {
return return
} }
br.ReadArray(&t.Scripts, MaxAttributes) nscripts := br.ReadVarUint()
if br.Err == nil && len(t.Signers) != len(t.Scripts) { if nscripts > MaxAttributes {
br.Err = errors.New("too many witnesses")
return
} else if int(nscripts) != len(t.Signers) {
br.Err = fmt.Errorf("%w: %d vs %d", ErrInvalidWitnessNum, len(t.Signers), len(t.Scripts)) br.Err = fmt.Errorf("%w: %d vs %d", ErrInvalidWitnessNum, len(t.Signers), len(t.Scripts))
return return
} }
t.Scripts = make([]Witness, nscripts)
for i := 0; i < int(nscripts); i++ {
t.Scripts[i].DecodeBinary(br)
}
// Create the hash of the transaction at decode, so we dont need // Create the hash of the transaction at decode, so we dont need
// to do it anymore. // to do it anymore.