diff --git a/pkg/serialize/prefix.go b/pkg/serialize/prefix.go index 25fd7a89e..5c3db0e43 100644 --- a/pkg/serialize/prefix.go +++ b/pkg/serialize/prefix.go @@ -1,25 +1,20 @@ package serialize import ( - "bytes" "encoding/binary" "fmt" ) // addSerializedTypePrefix adds a prefix to the encoded value to indicate the encoding type. func addSerializedTypePrefix(encoding encodingType, encodedValue []byte) (SerializedData, error) { - result, err := uint16ToBytes(uint16(encoding)) - if err != nil { - return nil, err - } - - return append(result, encodedValue...), nil + encodingTypeBytes := uint16ToBytes(uint16(encoding)) + return append(encodingTypeBytes, encodedValue...), nil } // removeSerializedTypePrefix removes the prefix from the encoded value. func removeSerializedTypePrefix(data SerializedData) (encodingType, []byte, error) { - if len(data) == 0 { - return encodingTypeInvalid, nil, fmt.Errorf("cannot deserialize encoded value: data is empty") + if len(data) < 3 { + return encodingTypeInvalid, nil, fmt.Errorf("cannot deserialize encoded value: data is too short") } typ, err := bytesToUint16(data[:2]) if err != nil { @@ -29,27 +24,17 @@ func removeSerializedTypePrefix(data SerializedData) (encodingType, []byte, erro return encodingType(typ), data[2:], nil } -// uint16ToBytes converts a uint16 to a byte slice. -func uint16ToBytes(n uint16) ([]byte, error) { - buf := new(bytes.Buffer) - err := binary.Write(buf, binary.BigEndian, n) - if err != nil { - return nil, err - } - return buf.Bytes(), nil +// uint16ToBytes converts a uint16 to a byte slice (big endian). +func uint16ToBytes(n uint16) []byte { + b := make([]byte, 2) + binary.BigEndian.PutUint16(b, n) + return b } // bytesToUint16 converts a byte slice to a uint16. func bytesToUint16(b []byte) (uint16, error) { - if len(b) < 2 { - return 0, fmt.Errorf("cannot convert bytes to uint16: bytes are too short") - } - - buf := bytes.NewReader(b) - var n uint16 - err := binary.Read(buf, binary.BigEndian, &n) - if err != nil { - return 0, err + if len(b) != 2 { + return 0, fmt.Errorf("cannot convert bytes to uint16: incorrect length") } - return n, nil + return binary.BigEndian.Uint16(b), nil } diff --git a/pkg/transactions/transaction.go b/pkg/transactions/transaction.go index 2fb4a5d4c..9e7547d94 100644 --- a/pkg/transactions/transaction.go +++ b/pkg/transactions/transaction.go @@ -119,24 +119,19 @@ func CreateTransaction(contents Payload, nonce uint64) (*Transaction, error) { } type Transaction struct { - // Signature is the signature of the transaction - // It can be nil if the transaction is unsigned + // Signature is the signature of the transaction. Signature *crypto.Signature - // Body is the body of the transaction - // It gets serialized and signed + // Body is the body of the transaction. It gets serialized and signed. Body *TransactionBody // Serialization is the serialization performed on `Body` - // inorder to generate the message that being signed + // in order to generate the message that being signed. Serialization SignedMsgSerializationType // Sender is the public key of the sender // NOTE: we could not use crypto.PublicKey, since it's not RLP-serializable Sender []byte - - // hash of the transaction that is signed. it is kept here as a cache - hash []byte } func (t *Transaction) GetSenderPubKey() (crypto.PublicKey, error) { @@ -189,43 +184,12 @@ func (t *Transaction) Sign(signer crypto.Signer) error { return nil } -// GetHash gets the hash for the transaction -// If a hash has already been generated, it is returned -func (t *Transaction) GetHash() ([]byte, error) { - if t.hash != nil { - return t.hash, nil - } - - return t.SetHash() -} - -// SetHash re-hashes the transaction and caches the new hash -func (t *Transaction) SetHash() ([]byte, error) { - bts, err := t.Body.MarshalBinary() - if err != nil { - return nil, err - } - - t.hash = crypto.Sha256(bts) - - return t.hash, nil -} - func (t *Transaction) MarshalBinary() (serialize.SerializedData, error) { return serialize.Encode(t) } -// TODO: I am not sure if this will actually work, since it is unserializing into an interface -// I am quite sure it wont; an alternative is to decode into a struct where public key is bytes, and -// create the public key from there func (t *Transaction) UnmarshalBinary(data serialize.SerializedData) error { - res, err := serialize.Decode[Transaction](data) - if err != nil { - return err - } - - *t = *res - return nil + return serialize.DecodeInto(data, t) } // TransactionBody is the body of a transaction that gets included in the signature diff --git a/pkg/transactions/transaction_test.go b/pkg/transactions/transaction_test.go index 1db87a1d0..9e12a896e 100644 --- a/pkg/transactions/transaction_test.go +++ b/pkg/transactions/transaction_test.go @@ -8,10 +8,23 @@ import ( "github.com/kwilteam/kwil-db/pkg/crypto" "github.com/kwilteam/kwil-db/pkg/transactions" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) +// NOTE: this fails because of legacy issues with RLP itself. +// +// func Test_TransactionMarshalUnmarshal(t *testing.T) { +// tx := &transactions.Transaction{} +// serialized, err := tx.MarshalBinary() +// require.NoError(t, err) + +// tx2 := &transactions.Transaction{} +// err = tx2.UnmarshalBinary(serialized) +// require.NoError(t, err) +// } + // testing serialization of a transaction, since Luke found a bug func Test_TransactionMarshal(t *testing.T) { tx := &transactions.Transaction{