Skip to content

Commit

Permalink
Enforce EncodeTo arguments to ensure high performance encoding
Browse files Browse the repository at this point in the history
  • Loading branch information
2opremio committed Nov 10, 2021
1 parent b434d7d commit 8494f90
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ func (i *transactionBatchInsertBuilder) transactionToRow(transaction ingest.Ledg
if err != nil {
return TransactionWithoutLedger{}, err
}
resultBase64, err := i.encodingBuffer.MarshalBase64(transaction.Result.Result)
resultBase64, err := i.encodingBuffer.MarshalBase64(&transaction.Result.Result)
if err != nil {
return TransactionWithoutLedger{}, err
}
Expand Down
8 changes: 4 additions & 4 deletions services/horizon/internal/ingest/orderbook.go
Original file line number Diff line number Diff line change
Expand Up @@ -228,11 +228,11 @@ func (o *OrderBookStream) verifyAllOffers(ctx context.Context) (bool, error) {
for i, offerRow := range ingestionOffers {
offerEntry := offers[i]
offerRowXDR := offerToXDR(offerRow)
offerEntryBase64, err := o.encodingBuffer.MarshalBase64(offerEntry)
offerEntryBase64, err := o.encodingBuffer.MarshalBase64(&offerEntry)
if err != nil {
return false, errors.Wrap(err, "Error from marshalling offerEntry")
}
offerRowBase64, err := o.encodingBuffer.MarshalBase64(offerRowXDR)
offerRowBase64, err := o.encodingBuffer.MarshalBase64(&offerRowXDR)
if err != nil {
return false, errors.Wrap(err, "Error from marshalling offerRowXDR")
}
Expand Down Expand Up @@ -277,11 +277,11 @@ func (o *OrderBookStream) verifyAllLiquidityPools(ctx context.Context) (bool, er
if err != nil {
return false, errors.Wrap(err, "Error from converting liquidity pool row to xdr")
}
liquidityPoolEntryBase64, err := o.encodingBuffer.MarshalBase64(liquidityPoolEntry)
liquidityPoolEntryBase64, err := o.encodingBuffer.MarshalBase64(&liquidityPoolEntry)
if err != nil {
return false, errors.Wrap(err, "Error from marshalling liquidityPoolEntry")
}
liquidityPoolRowBase64, err := o.encodingBuffer.MarshalBase64(liquidityPoolRowXDR)
liquidityPoolRowBase64, err := o.encodingBuffer.MarshalBase64(&liquidityPoolRowXDR)
if err != nil {
return false, errors.Wrap(err, "Error from marshalling liquidityPoolRowXDR")
}
Expand Down
53 changes: 28 additions & 25 deletions xdr/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,18 +83,28 @@ func SafeUnmarshal(data []byte, dest interface{}) error {
return nil
}

func marshalString(encoder func([]byte) string, v interface{}) (string, error) {
var raw bytes.Buffer

_, err := Marshal(&raw, v)

if err != nil {
return "", err
}

return encoder(raw.Bytes()), nil
}

func MarshalBase64(v interface{}) (string, error) {
e := NewEncodingBuffer()
return e.MarshalBase64(v)
return marshalString(base64.StdEncoding.EncodeToString, v)
}

func MarshalHex(v interface{}) (string, error) {
e := NewEncodingBuffer()
return e.MarshalHex(v)
return marshalString(hex.EncodeToString, v)
}

// EncodingBuffer reuses internal buffers between invocations
// to minimize allocations.
// EncodingBuffer reuses internal buffers between invocations to minimize allocations.
// It intentionally only allows EncodeTo method arguments, to guarantee high performance encoding.
type EncodingBuffer struct {
encoder *xdr.Encoder
xdrEncoderBuf bytes.Buffer
Expand All @@ -111,7 +121,7 @@ func growSlice(old []byte, newSize int) []byte {
return make([]byte, newSize, 2*newSize)
}

type xdrEncodable interface {
type XDREncodable interface {
EncodeTo(e *xdr.Encoder) error
}

Expand All @@ -125,24 +135,17 @@ func NewEncodingBuffer() *EncodingBuffer {
// a slice pointing to the internal buffer. Handled with care this improveds
// performance since copying is not required.
// Subsequent calls to marshalling methods will overwrite the returned buffer.
func (e *EncodingBuffer) UnsafeMarshalBinary(v interface{}) ([]byte, error) {
func (e *EncodingBuffer) UnsafeMarshalBinary(encodable XDREncodable) ([]byte, error) {
e.xdrEncoderBuf.Reset()
if encodable, ok := v.(xdrEncodable); ok {
// higher performance
if err := encodable.EncodeTo(e.encoder); err != nil {
return nil, err
}
} else {
if _, err := e.encoder.Encode(v); err != nil {
return nil, err
}
if err := encodable.EncodeTo(e.encoder); err != nil {
return nil, err
}
return e.xdrEncoderBuf.Bytes(), nil
}

// UnsafeMarshalBase64 is the base64 version of UnsafeMarshalBinary
func (e *EncodingBuffer) UnsafeMarshalBase64(v interface{}) ([]byte, error) {
xdrEncoded, err := e.UnsafeMarshalBinary(v)
func (e *EncodingBuffer) UnsafeMarshalBase64(encodable XDREncodable) ([]byte, error) {
xdrEncoded, err := e.UnsafeMarshalBinary(encodable)
if err != nil {
return nil, err
}
Expand All @@ -153,8 +156,8 @@ func (e *EncodingBuffer) UnsafeMarshalBase64(v interface{}) ([]byte, error) {
}

// UnsafeMarshalHex is the hex version of UnsafeMarshalBinary
func (e *EncodingBuffer) UnsafeMarshalHex(v interface{}) ([]byte, error) {
xdrEncoded, err := e.UnsafeMarshalBinary(v)
func (e *EncodingBuffer) UnsafeMarshalHex(encodable XDREncodable) ([]byte, error) {
xdrEncoded, err := e.UnsafeMarshalBinary(encodable)
if err != nil {
return nil, err
}
Expand All @@ -164,16 +167,16 @@ func (e *EncodingBuffer) UnsafeMarshalHex(v interface{}) ([]byte, error) {
return e.otherEncodersBuf, nil
}

func (e *EncodingBuffer) MarshalBase64(v interface{}) (string, error) {
b, err := e.UnsafeMarshalBase64(v)
func (e *EncodingBuffer) MarshalBase64(encodable XDREncodable) (string, error) {
b, err := e.UnsafeMarshalBase64(encodable)
if err != nil {
return "", err
}
return string(b), nil
}

func (e *EncodingBuffer) MarshalHex(v interface{}) (string, error) {
b, err := e.UnsafeMarshalHex(v)
func (e *EncodingBuffer) MarshalHex(encodable XDREncodable) (string, error) {
b, err := e.UnsafeMarshalHex(encodable)
if err != nil {
return "", err
}
Expand Down

0 comments on commit 8494f90

Please sign in to comment.