Skip to content

Commit

Permalink
remove hash from Transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
jchappelow committed Oct 2, 2023
1 parent 5ecec67 commit 7654c2c
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 67 deletions.
39 changes: 12 additions & 27 deletions pkg/serialize/prefix.go
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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
}
44 changes: 4 additions & 40 deletions pkg/transactions/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions pkg/transactions/transaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down

0 comments on commit 7654c2c

Please sign in to comment.