mirror of
https://github.com/tendermint/tendermint.git
synced 2026-01-10 15:07:24 +00:00
This pull request adds the report tool and modifies the loadtime libraries to better support its use.
(cherry picked from commit 8655080a0f)
88 lines
2.4 KiB
Go
88 lines
2.4 KiB
Go
package payload
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
|
)
|
|
|
|
const keyPrefix = "a="
|
|
|
|
// NewBytes generates a new payload and returns the encoded representation of
|
|
// the payload as a slice of bytes. NewBytes uses the fields on the Options
|
|
// to create the payload.
|
|
func NewBytes(p *Payload) ([]byte, error) {
|
|
p.Padding = make([]byte, 1)
|
|
if p.Time == nil {
|
|
p.Time = timestamppb.Now()
|
|
}
|
|
us, err := CalculateUnpaddedSize(p)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if p.Size < uint64(us) {
|
|
return nil, fmt.Errorf("configured size %d not large enough to fit unpadded transaction of size %d", p.Size, us)
|
|
}
|
|
p.Padding = make([]byte, p.Size-uint64(us))
|
|
_, err = rand.Read(p.Padding)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
b, err := proto.Marshal(p)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// prepend a single key so that the kv store only ever stores a single
|
|
// transaction instead of storing all tx and ballooning in size.
|
|
return append([]byte(keyPrefix), b...), nil
|
|
}
|
|
|
|
// FromBytes extracts a paylod from the byte representation of the payload.
|
|
// FromBytes leaves the padding untouched, returning it to the caller to handle
|
|
// or discard per their preference.
|
|
func FromBytes(b []byte) (*Payload, error) {
|
|
p := &Payload{}
|
|
tr := bytes.TrimPrefix(b, []byte(keyPrefix))
|
|
if bytes.Equal(b, tr) {
|
|
return nil, errors.New("payload bytes missing key prefix")
|
|
}
|
|
err := proto.Unmarshal(tr, p)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return p, nil
|
|
}
|
|
|
|
// MaxUnpaddedSize returns the maximum size that a payload may be if no padding
|
|
// is included.
|
|
func MaxUnpaddedSize() (int, error) {
|
|
p := &Payload{
|
|
Time: timestamppb.Now(),
|
|
Connections: math.MaxUint64,
|
|
Rate: math.MaxUint64,
|
|
Size: math.MaxUint64,
|
|
Padding: make([]byte, 1),
|
|
}
|
|
return CalculateUnpaddedSize(p)
|
|
}
|
|
|
|
// CalculateUnpaddedSize calculates the size of the passed in payload for the
|
|
// purpose of determining how much padding to add to add to reach the target size.
|
|
// CalculateUnpaddedSize returns an error if the payload Padding field is longer than 1.
|
|
func CalculateUnpaddedSize(p *Payload) (int, error) {
|
|
if len(p.Padding) != 1 {
|
|
return 0, fmt.Errorf("expected length of padding to be 1, received %d", len(p.Padding))
|
|
}
|
|
b, err := proto.Marshal(p)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return len(b) + len(keyPrefix), nil
|
|
}
|