Skip to content

Commit

Permalink
Merge pull request ethereum#92 from nisdas/blobSerialization
Browse files Browse the repository at this point in the history
Blob Serialisation
  • Loading branch information
rauljordan authored May 17, 2018
2 parents f5f0877 + 6a2ebd3 commit bc00aea
Show file tree
Hide file tree
Showing 4 changed files with 457 additions and 6 deletions.
85 changes: 85 additions & 0 deletions sharding/collation.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package sharding

import (
"fmt"
"math"
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto/sha3"
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/sharding/utils"
)

// Collation base struct.
Expand Down Expand Up @@ -38,6 +41,8 @@ type collationHeaderData struct {
ProposerSignature []byte // the proposer's signature for calculating collation hash.
}

var collationSizelimit = int64(math.Pow(float64(2), float64(20)))

// NewCollation initializes a collation and leaves it up to clients to serialize, deserialize
// and provide the body and transactions upon creation.
func NewCollation(header *CollationHeader, body []byte, transactions []*types.Transaction) *Collation {
Expand Down Expand Up @@ -105,3 +110,83 @@ func (c *Collation) CalculateChunkRoot() {
chunkRoot := common.BytesToHash(c.body)
c.header.data.ChunkRoot = &chunkRoot
}

// CreateRawBlobs creates raw blobs from transactions.
func (c Collation) CreateRawBlobs() ([]*utils.RawBlob, error) {

// It does not skip evm execution by default
blobs := make([]*utils.RawBlob, len(c.transactions))
for i := 0; i < len(c.transactions); i++ {

err := error(nil)
blobs[i], err = utils.NewRawBlob(c.transactions[i], false)

if err != nil {
return nil, fmt.Errorf("Creation of raw blobs from transactions failed: %v", err)
}

}

return blobs, nil

}

// ConvertBackToTx converts raw blobs back to their original transactions.
func ConvertBackToTx(rawBlobs []utils.RawBlob) ([]*types.Transaction, error) {

blobs := make([]*types.Transaction, len(rawBlobs))

for i := 0; i < len(rawBlobs); i++ {

blobs[i] = types.NewTransaction(0, common.HexToAddress("0x"), nil, 0, nil, nil)

err := utils.ConvertFromRawBlob(&rawBlobs[i], blobs[i])
if err != nil {
return nil, fmt.Errorf("Creation of transactions from raw blobs failed: %v", err)
}
}
return blobs, nil

}

// Serialize method serializes the collation body to a byte array.
func (c *Collation) Serialize() ([]byte, error) {

blobs, err := c.CreateRawBlobs()

if err != nil {
return nil, fmt.Errorf("%v", err)
}

serializedTx, err := utils.Serialize(blobs)

if err != nil {
return nil, fmt.Errorf("%v", err)
}

if int64(len(serializedTx)) > collationSizelimit {

return nil, fmt.Errorf("The serialized body exceeded the collation size limit: %v", serializedTx)

}

return serializedTx, nil

}

// Deserialize takes a byte array and converts its back to its original transactions.
func Deserialize(serialisedBlob []byte) (*[]*types.Transaction, error) {

deserializedBlobs, err := utils.Deserialize(serialisedBlob)
if err != nil {
return nil, fmt.Errorf("%v", err)
}

txs, err := ConvertBackToTx(deserializedBlobs)

if err != nil {
return nil, fmt.Errorf("%v", err)
}

return &txs, nil
}
96 changes: 90 additions & 6 deletions sharding/collation_test.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
package sharding

import (
"bytes"
"math/big"
"reflect"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
)

// fieldAccess is to access unexported fields in structs in another package
func fieldAccess(i interface{}, fields []string) reflect.Value {
val := reflect.ValueOf(i)
for i := 0; i < len(fields); i++ {
val = reflect.Indirect(val).FieldByName(fields[i])
}
return val

}
func TestCollation_Transactions(t *testing.T) {
header := NewCollationHeader(big.NewInt(1), nil, big.NewInt(1), nil, []byte{})
body := []byte{}
Expand All @@ -27,16 +38,89 @@ func TestCollation_Transactions(t *testing.T) {
}
}

func TestCollation_ProposerAddress(t *testing.T) {
proposerAddr := common.BytesToAddress([]byte("proposer"))
header := NewCollationHeader(big.NewInt(1), nil, big.NewInt(1), &proposerAddr, []byte{})
//TODO: Add test for converting *types.Transaction into raw blobs

//Tests that Transactions can be serialised
func TestSerialize_Deserialize(t *testing.T) {

header := NewCollationHeader(big.NewInt(1), nil, big.NewInt(1), nil, []byte{})
body := []byte{}
transactions := []*types.Transaction{
makeTxWithGasLimit(0),
makeTxWithGasLimit(5),
makeTxWithGasLimit(20),
makeTxWithGasLimit(100),
}

c := NewCollation(header, body, transactions)

tx := c.transactions

results, err := c.Serialize()

collation := NewCollation(header, body, nil)
if err != nil {
t.Errorf("Unable to Serialize transactions, %v", err)
}

deserializedTxs, err := Deserialize(results)

if err != nil {
t.Errorf("Unable to deserialize collation body, %v", err)
}

if collation.ProposerAddress().String() != proposerAddr.String() {
t.Errorf("initialized collation does not contain correct proposer address")
if len(tx) != len(*deserializedTxs) {
t.Errorf("Transaction length is different before and after serialization: %v, %v", len(tx), len(*deserializedTxs))
}

for i := 0; i < len(tx); i++ {

beforeSerialization := tx[i]
afterDeserialization := (*deserializedTxs)[i]

if beforeSerialization.Nonce() != afterDeserialization.Nonce() {

t.Errorf("Data before serialization and after deserialization are not the same ,AccountNonce: %v, %v", beforeSerialization.Nonce(), afterDeserialization.Nonce())

}

if beforeSerialization.Gas() != afterDeserialization.Gas() {

t.Errorf("Data before serialization and after deserialization are not the same ,GasLimit: %v, %v", beforeSerialization.Gas(), afterDeserialization.Gas())

}

if beforeSerialization.GasPrice().Cmp(afterDeserialization.GasPrice()) != 0 {

t.Errorf("Data before serialization and after deserialization are not the same ,Price: %v, %v", beforeSerialization.GasPrice(), afterDeserialization.GasPrice())

}

beforeAddress := reflect.ValueOf(beforeSerialization.To())
afterAddress := reflect.ValueOf(afterDeserialization.To())

if reflect.DeepEqual(beforeAddress, afterAddress) {

t.Errorf("Data before serialization and after deserialization are not the same ,Recipient: %v, %v", beforeAddress, afterAddress)

}

if beforeSerialization.Value().Cmp(afterDeserialization.Value()) != 0 {

t.Errorf("Data before serialization and after deserialization are not the same ,Amount: %v, %v", beforeSerialization.Value(), afterDeserialization.Value())

}

beforeData := beforeSerialization.Data()
afterData := afterDeserialization.Data()

if !bytes.Equal(beforeData, afterData) {

t.Errorf("Data before serialization and after deserialization are not the same ,Payload: %v, %v", beforeData, afterData)

}

}

}

func makeTxWithGasLimit(gl uint64) *types.Transaction {
Expand Down
Loading

0 comments on commit bc00aea

Please sign in to comment.