Skip to content

Commit

Permalink
sharding/utils: Changing from interfaces to rawblobs(ethereum#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
nisdas committed May 16, 2018
1 parent 89f8544 commit c1b5d04
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 74 deletions.
19 changes: 2 additions & 17 deletions sharding/collation.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"
"math"
"math/big"
"reflect"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
Expand Down Expand Up @@ -119,10 +118,8 @@ func (c *Collation) CalculateChunkRoot() {
// Serialize method serializes the collation body
func (c *Collation) Serialize() ([]byte, error) {

blob, err := utils.ConvertInterface(c.transactions, reflect.Slice)
if err != nil {
return nil, fmt.Errorf("%v", err)
}
blob := utils.ConvertToInterface(c.transactions)

serializedtx, err := utils.Serialize(blob)

if err != nil {
Expand All @@ -137,15 +134,3 @@ func (c *Collation) Serialize() ([]byte, error) {
return serializedtx, nil

}

func (c *Collation) GasUsed() *big.Int {
g := uint64(0)
for _, tx := range c.transactions {
if g > math.MaxUint64-(g+tx.Gas()) {
g = math.MaxUint64
break
}
g += tx.Gas()
}
return big.NewInt(0).SetUint64(g)
}
11 changes: 5 additions & 6 deletions sharding/collation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,11 @@ func TestSerialize(t *testing.T) {
for _, tx := range tt.transactions {
c.AddTransaction(tx)
}
/*
results, err := c.Serialize()
if err != nil {
t.Fatalf("%v ----%v---%v", err, results, c.transactions)
}
*/

results, err := c.Serialize()
if err != nil {
t.Fatalf("%v ----%v---%v", err, results, c.transactions)
}

}

Expand Down
110 changes: 69 additions & 41 deletions sharding/utils/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,27 @@ var (
chunkDataSize = chunkSize - indicatorSize
)

type Flags struct {
skipEvmExecution bool
}

type RawBlob struct {
flags Flags
data []byte
}

// ConvertInterface converts inputted interface to the required type of interface, ex: slice.
func ConvertInterface(arg interface{}, kind reflect.Kind) ([]interface{}, error) {
func ConvertInterfacetoBytes(arg interface{}) ([]byte, error) {
val := reflect.ValueOf(arg)
if val.Kind() == kind {
if val.Kind() == reflect.Slice {

return val.Interface().([]interface{}), nil
length := val.Len()
newtype := make([]byte, length)
for i := 0; i < length; i++ {
newtype[i] = val.Index(i).Interface().(byte)
}

return newtype, nil

}
err := errors.New("Interface Conversion a failure")
Expand All @@ -35,37 +50,36 @@ func convertbyteToInterface(arg []byte) []interface{} {
return newtype
}

func interfacetoByte(arg []interface{}) []byte {
length := int64(len(arg))
newtype := make([]byte, length)
for i, v := range arg {
newtype[i] = v.(byte)
func ConvertToInterface(arg interface{}) []interface{} {
val := reflect.ValueOf(arg)
length := val.Len()
newtype := make([]interface{}, length)
for i := 0; i < length; i++ {
newtype[i] = val.Index(i)
}

return newtype
}

// serializeBlob parses the blob and serializes it appropriately.
func serializeBlob(cb interface{}) ([]byte, error) {
func serializeBlob(cb RawBlob) ([]byte, error) {

interfaceblob, err := ConvertInterface(cb, reflect.Slice)
if err != nil {
return nil, fmt.Errorf("Error: %v", err)
}
blob := interfacetoByte(interfaceblob)
length := int64(len(blob))
length := int64(len(cb.data))
terminalLength := length % chunkDataSize
chunksNumber := length / chunkDataSize
indicatorByte := make([]byte, 1)
indicatorByte[0] = 0
if cb.flags.skipEvmExecution {
indicatorByte[0] |= (1 << 7)
}
tempbody := []byte{}

// if blob is less than 31 bytes, it adds the indicator chunk and pads the remaining empty bytes to the right

if chunksNumber == 0 {
paddedbytes := make([]byte, (chunkDataSize - length))
indicatorByte[0] = byte(terminalLength)
tempbody = append(indicatorByte, append(blob, paddedbytes...)...)
tempbody = append(indicatorByte, append(cb.data, paddedbytes...)...)
return tempbody, nil
}

Expand All @@ -78,17 +92,21 @@ func serializeBlob(cb interface{}) ([]byte, error) {
// This loop loops through all non-terminal chunks and add a indicator byte of 00000000, each chunk
// is created by appending the indcator byte to the data chunks. The data chunks are separated into sets of
// 31

tempbody = append(tempbody,
append(indicatorByte,
blob[(i-1)*chunkDataSize:i*chunkDataSize]...)...)
cb.data[(i-1)*chunkDataSize:i*chunkDataSize]...)...)

}
indicatorByte[0] = byte(chunkDataSize)
if cb.flags.skipEvmExecution {
indicatorByte[0] |= (1 << 7)
}

// Terminal chunk has its indicator byte added, chunkDataSize*chunksNumber refers to the total size of the blob
tempbody = append(tempbody,
append(indicatorByte,
blob[(chunksNumber-1)*chunkDataSize:chunkDataSize*chunksNumber]...)...)
cb.data[(chunksNumber-1)*chunkDataSize:chunkDataSize*chunksNumber]...)...)

return tempbody, nil

Expand All @@ -102,16 +120,19 @@ func serializeBlob(cb interface{}) ([]byte, error) {

tempbody = append(tempbody,
append(indicatorByte,
blob[(i-1)*chunkDataSize:i*chunkDataSize]...)...)
cb.data[(i-1)*chunkDataSize:i*chunkDataSize]...)...)

}
// Appends indicator bytes to terminal-chunks , and if the index of the chunk delimiter is non-zero adds it to the chunk.
// Also pads empty bytes to the terminal chunk.chunkDataSize*chunksNumber refers to the total size of the blob.
// finalchunkIndex refers to the index of the last data byte
indicatorByte[0] = byte(terminalLength)
if cb.flags.skipEvmExecution {
indicatorByte[0] |= (1 << 7)
}
tempbody = append(tempbody,
append(indicatorByte,
blob[chunkDataSize*chunksNumber:length]...)...)
cb.data[chunkDataSize*chunksNumber:length]...)...)

emptyBytes := make([]byte, (chunkDataSize - terminalLength))
tempbody = append(tempbody, emptyBytes...)
Expand All @@ -121,8 +142,8 @@ func serializeBlob(cb interface{}) ([]byte, error) {
}

// Serialize takes a set of blobs and converts them to a single byte array.
func Serialize(rawtx []interface{}) ([]byte, error) {
length := int64(len(rawtx))
func Serialize(rawblobs []RawBlob) ([]byte, error) {
length := int64(len(rawblobs))

if length == 0 {
return nil, fmt.Errorf("Validation failed: Collation Body has to be a non-zero value")
Expand All @@ -132,10 +153,10 @@ func Serialize(rawtx []interface{}) ([]byte, error) {
//Loops through all the blobs and serializes them into chunks
for i := int64(0); i < length; i++ {

data := rawtx[i]
data := rawblobs[i]
refinedData, err := serializeBlob(data)
if err != nil {
return nil, fmt.Errorf("Error: %v at index: %v", i, err)
return nil, fmt.Errorf("Index %v : %v", i, err)
}
serialisedData = append(serialisedData, refinedData...)

Expand All @@ -144,42 +165,49 @@ func Serialize(rawtx []interface{}) ([]byte, error) {
}

// Deserialize results in the byte array being deserialised and separated into its respective interfaces.
func Deserialize(collationbody []byte, rawtx interface{}) error {
func Deserialize(collationbody []byte) ([]RawBlob, error) {

length := int64(len(collationbody))
chunksNumber := length / chunkSize
indicatorByte := byte(0)
tempbody := []byte{}
var deserializedblob []interface{}
var tempbody RawBlob
var deserializedblob []RawBlob

// This separates the byte array into its separate blobs
for i := int64(1); i <= chunksNumber; i++ {
indicatorIndex := (i - 1) * chunkSize
var terminalIndex int64
// Tests if the chunk delimiter is zero, if it is it will append the data chunk
// to tempbody
if collationbody[indicatorIndex] == indicatorByte {
tempbody = append(tempbody, collationbody[(indicatorIndex+1):(i)*chunkSize]...)
if collationbody[indicatorIndex] == indicatorByte || collationbody[indicatorIndex] == byte(128) {
tempbody.data = append(tempbody.data, collationbody[(indicatorIndex+1):(i)*chunkSize]...)

} else if collationbody[indicatorIndex] == byte(1) {

tempbody = append(tempbody, collationbody[(indicatorIndex+1)])
deserializedblob = append(deserializedblob, convertbyteToInterface(tempbody))
tempbody = []byte{}
} else if collationbody[indicatorIndex] == byte(31) || collationbody[indicatorIndex] == byte(159) {
if collationbody[indicatorIndex] == byte(159) {
tempbody.flags.skipEvmExecution = true
}
tempbody.data = append(tempbody.data, collationbody[(indicatorIndex+1)])
deserializedblob = append(deserializedblob, tempbody)
tempbody = RawBlob{}

} else {
// Since the chunk delimiter in non-zero now we can infer that it is a terminal chunk and
// add it and append to the deserializedblob slice. The tempbody signifies a single deserialized blob
terminalIndex := int64(collationbody[indicatorIndex])
tempbody = append(tempbody, collationbody[(indicatorIndex+1):(indicatorIndex+1+terminalIndex)]...)
deserializedblob = append(deserializedblob, convertbyteToInterface(tempbody))
tempbody = []byte{}
flagindex := collationbody[indicatorIndex] >> 7
if flagindex == byte(1) {
terminalIndex = int64(collationbody[indicatorIndex]) - 128
tempbody.flags.skipEvmExecution = true
} else {
terminalIndex = int64(collationbody[indicatorIndex])
}
tempbody.data = append(tempbody.data, collationbody[(indicatorIndex+1):(indicatorIndex+1+terminalIndex)]...)
deserializedblob = append(deserializedblob, tempbody)
tempbody = RawBlob{}

}

}

*rawtx.(*interface{}) = deserializedblob

return nil
return deserializedblob, nil

}
33 changes: 23 additions & 10 deletions sharding/utils/marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,27 @@ import (
"testing"
)

func buildtxblobs(size int64) []interface{} {
tempbody := make([]interface{}, size)
func buildrawblob(size int64) []RawBlob {
tempbody := make([]RawBlob, size)
for i := int64(0); i < size; i++ {
tempbody[i] = buildblob(size)
var rawblob RawBlob
rawblob.data = buildblob(size)
flagset := byte(rand.Int()) >> 7
if flagset == byte(1) {
rawblob.flags.skipEvmExecution = true

}

tempbody[i] = rawblob

}
return tempbody

}

func buildblob(size int64) []interface{} {
func buildblob(size int64) []byte {

tempbody := make([]interface{}, size)
tempbody := make([]byte, size)
for i := int64(0); i < size; i++ {
tempbody[i] = byte(rand.Int())

Expand All @@ -26,17 +35,21 @@ func buildblob(size int64) []interface{} {
return tempbody

}

/*
Might be required in the future for part 2 of serialization
func TestConvertInterface(t *testing.T) {
slice := []interface{}{0, 1, 2, 3, 4, 5}
convertedValue, err := ConvertInterface(slice, reflect.Slice)
if err != nil {
t.Fatalf("Error: %v %v", err, convertedValue)
}
}
} */
func TestSize(t *testing.T) {
size := int64(800)
blob := buildtxblobs(size)
blob := buildrawblob(size)
chunksafterSerialize := size / chunkDataSize
terminalchunk := size % chunkDataSize
if terminalchunk != 0 {
Expand All @@ -60,16 +73,16 @@ func TestSerializeAndDeserializeblob(t *testing.T) {

var testbody interface{}

blob := buildtxblobs(1000)
blob := buildrawblob(10)

serializedblob, err := Serialize(blob)

if err != nil {
t.Fatalf("Error Serializing blob:%v %v", err, serializedblob)
}
err2 := Deserialize(serializedblob, &testbody)
raw, err2 := Deserialize(serializedblob)
if err2 != nil {
t.Fatalf("Error Serializing blob:%v", err2)
t.Fatalf("Error Serializing blob:%v due to %v", raw, err2)
}

if !reflect.DeepEqual(blob, testbody) {
Expand Down

0 comments on commit c1b5d04

Please sign in to comment.