prysm-pulse/sharding/utils/marshal.go
Raul Jordan c58083ec09 sharding: fix up comment formatting in marshal and marshal_test.go
Former-commit-id: 8cc3e8f619fc65d6230f38757b499e25b342bd3b [formerly ee95d821432933f87e0701160849e831a6489813]
Former-commit-id: 93993c0d37ade450c7796020af1d30d2481ea1c7
2018-05-17 06:31:02 +08:00

195 lines
5.9 KiB
Go

package utils
import (
"fmt"
"github.com/ethereum/go-ethereum/rlp"
)
var (
chunkSize = int64(32)
indicatorSize = int64(1)
chunkDataSize = chunkSize - indicatorSize
)
// Flags to add to chunk delimiter.
type Flags struct {
skipEvmExecution bool
}
// RawBlob type which will contain flags and data for serialization.
type RawBlob struct {
flags Flags
data []byte
}
// NewRawBlob builds a raw blob from any interface by using
// RLP encoding.
func NewRawBlob(i interface{}, skipEvm bool) (*RawBlob, error) {
data, err := rlp.EncodeToBytes(i)
if err != nil {
return nil, fmt.Errorf("RLP encoding was a failure:%v", err)
}
return &RawBlob{data: data, flags: Flags{skipEvmExecution: skipEvm}}, nil
}
// ConvertFromRawBlob converts raw blob back from a byte array
// to its interface.
func ConvertFromRawBlob(blob *RawBlob, i interface{}) error {
data := (*blob).data
err := rlp.DecodeBytes(data, i)
if err != nil {
return fmt.Errorf("RLP decoding was a failure:%v", err)
}
return nil
}
// SerializeBlob parses the blob and serializes it appropriately.
func SerializeBlob(cb RawBlob) ([]byte, error) {
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, 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)
if cb.flags.skipEvmExecution {
indicatorByte[0] |= (1 << 7)
}
tempBody = append(indicatorByte, append(cb.data, paddedBytes...)...)
return tempBody, nil
}
// if there is no need to pad empty bytes, then the indicator byte
// is added as 0001111, then this chunk is returned to the
// main Serialize function.
if terminalLength == 0 {
for i := int64(1); i < chunksNumber; i++ {
// This loop loops through all non-terminal chunks and add a indicator
// byte of 00000000, each chunk is created by appending the indicator
// byte to the data chunks. The data chunks are separated into sets of
// 31 bytes.
tempBody = append(tempBody,
append(indicatorByte,
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,
cb.data[(chunksNumber-1)*chunkDataSize:chunkDataSize*chunksNumber]...)...)
return tempBody, nil
}
// 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.
for i := int64(1); i <= chunksNumber; i++ {
tempBody = append(tempBody,
append(indicatorByte,
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,
cb.data[chunkDataSize*chunksNumber:length]...)...)
emptyBytes := make([]byte, (chunkDataSize - terminalLength))
tempBody = append(tempBody, emptyBytes...)
return tempBody, nil
}
// Serialize takes a set of blobs and converts them to a single byte array.
func Serialize(rawblobs []*RawBlob) ([]byte, error) {
length := int64(len(rawblobs))
serialisedData := []byte{}
//Loops through all the blobs and serializes them into chunks
for i := int64(0); i < length; i++ {
data := *rawblobs[i]
refinedData, err := SerializeBlob(data)
if err != nil {
return nil, fmt.Errorf("Index %v: %v", i, err)
}
serialisedData = append(serialisedData, refinedData...)
}
return serialisedData, nil
}
// Deserialize results in the byte array being deserialised and
// separated into its respective interfaces.
func Deserialize(data []byte) ([]RawBlob, error) {
length := int64(len(data))
chunksNumber := length / chunkSize
indicatorByte := byte(0)
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
// Tests if the chunk delimiter is zero, if it is it will append the data chunk
// to tempBody.
if data[indicatorIndex] == indicatorByte || data[indicatorIndex] == byte(128) {
tempBody.data = append(tempBody.data, data[(indicatorIndex+1):(i)*chunkSize]...)
} else if data[indicatorIndex] == byte(31) || data[indicatorIndex] == byte(159) {
if data[indicatorIndex] == byte(159) {
tempBody.flags.skipEvmExecution = true
}
tempBody.data = append(tempBody.data, data[(indicatorIndex+1):indicatorIndex+1+chunkDataSize]...)
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(data[indicatorIndex])
//Check if EVM flag is equal to 1
flagindex := data[indicatorIndex] >> 7
if flagindex == byte(1) {
terminalIndex = int64(data[indicatorIndex]) - 128
tempBody.flags.skipEvmExecution = true
}
tempBody.data = append(tempBody.data, data[(indicatorIndex+1):(indicatorIndex+1+terminalIndex)]...)
deserializedBlob = append(deserializedBlob, tempBody)
tempBody = RawBlob{}
}
}
return deserializedBlob, nil
}