Merge pull request #1546 from harmony-ek/version_block

Version "./core/types".{Block,extblock,Body}
pull/1552/head pangaea-20190909.0
Eugene Kim 5 years ago committed by GitHub
commit 7fad7d8725
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      core/rawdb/accessors_chain.go
  2. 6
      core/rawdb/accessors_chain_test.go
  3. 13
      core/rawdb/accessors_indexes.go
  4. 185
      core/types/block.go
  5. 680
      core/types/block_test.go
  6. 31
      core/types/bodyfieldsetter.go
  7. 93
      core/types/bodyv0.go
  8. 90
      core/types/bodyv1.go
  9. 53
      core/types/cx_receipt.go
  10. 38
      core/types/transaction.go

@ -341,7 +341,7 @@ func ReadBlock(db DatabaseReader, hash common.Hash, number uint64) *types.Block
if body == nil {
return nil
}
return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles, body.IncomingReceipts)
return types.NewBlockWithHeader(header).WithBody(body.Transactions(), body.Uncles(), body.IncomingReceipts())
}
// WriteBlock serializes a block into the database, header and body separately.

@ -74,7 +74,7 @@ func TestBodyStorage(t *testing.T) {
db := ethdb.NewMemDatabase()
// Create a test body to move around the database and make sure it's really new
body := &types.Body{Uncles: []*block.Header{blockfactory.NewTestHeader().With().Extra([]byte("test header")).Header()}}
body := types.NewTestBody().With().Uncles([]*block.Header{blockfactory.NewTestHeader().With().Extra([]byte("test header")).Header()}).Body()
hasher := sha3.NewLegacyKeccak256()
rlp.Encode(hasher, body)
@ -87,7 +87,7 @@ func TestBodyStorage(t *testing.T) {
WriteBody(db, hash, 0, body)
if entry := ReadBody(db, hash, 0); entry == nil {
t.Fatalf("Stored body not found")
} else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(types.Transactions(body.Transactions)) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(body.Uncles) {
} else if types.DeriveSha(types.Transactions(entry.Transactions())) != types.DeriveSha(types.Transactions(body.Transactions())) || types.CalcUncleHash(entry.Uncles()) != types.CalcUncleHash(body.Uncles()) {
t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, body)
}
if entry := ReadBodyRLP(db, hash, 0); entry == nil {
@ -142,7 +142,7 @@ func TestBlockStorage(t *testing.T) {
}
if entry := ReadBody(db, block.Hash(), block.NumberU64()); entry == nil {
t.Fatalf("Stored body not found")
} else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(block.Transactions()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) {
} else if types.DeriveSha(types.Transactions(entry.Transactions())) != types.DeriveSha(block.Transactions()) || types.CalcUncleHash(entry.Uncles()) != types.CalcUncleHash(block.Uncles()) {
t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, block.Body())
}
if actual, err := ReadEpochBlockNumber(db, big.NewInt(0)); err != nil {

@ -71,7 +71,16 @@ func ReadTransaction(db DatabaseReader, hash common.Hash) (*types.Transaction, c
return nil, common.Hash{}, 0, 0
}
body := ReadBody(db, blockHash, blockNumber)
if body == nil || len(body.Transactions) <= int(txIndex) {
if body == nil {
utils.Logger().Error().
Uint64("number", blockNumber).
Str("hash", blockHash.Hex()).
Uint64("index", txIndex).
Msg("block Body referenced missing")
return nil, common.Hash{}, 0, 0
}
tx := body.TransactionAt(int(txIndex))
if tx == nil {
utils.Logger().Error().
Uint64("number", blockNumber).
Str("hash", blockHash.Hex()).
@ -79,7 +88,7 @@ func ReadTransaction(db DatabaseReader, hash common.Hash) (*types.Transaction, c
Msg("Transaction referenced missing")
return nil, common.Hash{}, 0, 0
}
return body.Transactions[txIndex], blockHash, blockNumber, txIndex
return tx, blockHash, blockNumber, txIndex
}
// ReadReceipt retrieves a specific transaction receipt from the database, along with

@ -21,6 +21,7 @@ import (
"encoding/binary"
"io"
"math/big"
"reflect"
"sort"
"sync/atomic"
"time"
@ -29,9 +30,14 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/taggedrlp"
"github.com/pkg/errors"
"github.com/rs/zerolog"
"github.com/harmony-one/harmony/block"
blockfactory "github.com/harmony-one/harmony/block/factory"
v0 "github.com/harmony-one/harmony/block/v0"
v1 "github.com/harmony-one/harmony/block/v1"
"github.com/harmony-one/harmony/crypto/hash"
"github.com/harmony-one/harmony/internal/utils"
"github.com/harmony-one/harmony/shard"
@ -70,12 +76,104 @@ func (n *BlockNonce) UnmarshalText(input []byte) error {
return hexutil.UnmarshalFixedText("BlockNonce", input, n[:])
}
// BodyInterface is a simple accessor interface for block body.
type BodyInterface interface {
// Transactions returns a deep copy the list of transactions in this block.
Transactions() []*Transaction
// TransactionAt returns the transaction at the given index in this block.
// It returns nil if index is out of bounds.
TransactionAt(index int) *Transaction
// SetTransactions sets the list of transactions with a deep copy of the
// given list.
SetTransactions(newTransactions []*Transaction)
// Uncles returns a deep copy of the list of uncle headers of this block.
Uncles() []*block.Header
// SetUncles sets the list of uncle headers with a deep copy of the given
// list.
SetUncles(newUncle []*block.Header)
// IncomingReceipts returns a deep copy of the list of incoming cross-shard
// transaction receipts of this block.
IncomingReceipts() CXReceiptsProofs
// SetIncomingReceipts sets the list of incoming cross-shard transaction
// receipts of this block with a dep copy of the given list.
SetIncomingReceipts(newIncomingReceipts CXReceiptsProofs)
}
// Body is a simple (mutable, non-safe) data container for storing and moving
// a block's data contents (transactions and uncles) together.
type Body struct {
Transactions []*Transaction
Uncles []*block.Header
IncomingReceipts CXReceiptsProofs
BodyInterface
}
// NewBodyForMatchingHeader returns a new block body struct whose implementation
// matches the version of the given field.
//
// TODO ek – this is a stopgap, and works only while there is a 1:1 mapping
// between header and body versions. Replace usage with factory.
func NewBodyForMatchingHeader(h *block.Header) (*Body, error) {
var bi BodyInterface
switch h.Header.(type) {
case *v1.Header:
bi = new(BodyV1)
case *v0.Header:
bi = new(BodyV0)
default:
return nil, errors.Errorf("unsupported header type %s",
taggedrlp.TypeName(reflect.TypeOf(h)))
}
return &Body{bi}, nil
}
// NewTestBody creates a new, empty body object for epoch 0 using the test
// factory. Use for unit tests.
func NewTestBody() *Body {
body, err := NewBodyForMatchingHeader(blockfactory.NewTestHeader())
if err != nil {
panic(err)
}
return body
}
// With returns a field setter context for the receiver.
func (b *Body) With() BodyFieldSetter {
return BodyFieldSetter{b}
}
// EncodeRLP RLP-encodes the block body onto the given writer. It uses tagged RLP
// encoding for non-Genesis body formats.
func (b *Body) EncodeRLP(w io.Writer) error {
return BodyRegistry.Encode(w, b.BodyInterface)
}
// DecodeRLP decodes a block body out of the given RLP stream into the receiver.
// It uses tagged RLP encoding for non-Genesis body formats.
func (b *Body) DecodeRLP(s *rlp.Stream) error {
decoded, err := BodyRegistry.Decode(s)
if err != nil {
return err
}
bif, ok := decoded.(BodyInterface)
if !ok {
return errors.Errorf(
"decoded body (type %s) does not implement BodyInterface",
taggedrlp.TypeName(reflect.TypeOf(decoded)))
}
b.BodyInterface = bif
return nil
}
// BodyRegistry is the tagged RLP registry for block body types.
var BodyRegistry = taggedrlp.NewRegistry()
func init() {
BodyRegistry.MustRegister(taggedrlp.LegacyTag, new(BodyV0))
BodyRegistry.MustRegister("v1", new(BodyV1))
}
// Block represents an entire block in the Ethereum blockchain.
@ -121,27 +219,26 @@ func (b *Block) DeprecatedTd() *big.Int {
return b.td
}
// StorageBlock defines the RLP encoding of a Block stored in the
// state database. The StorageBlock encoding contains fields that
// would otherwise need to be recomputed.
// [deprecated by eth/63]
type StorageBlock Block
// "external" block encoding. used for eth protocol, etc.
type extblock struct {
Header *block.Header
Txs []*Transaction
Uncles []*block.Header
}
// CX-ready extblock
type extblockV1 struct {
Header *block.Header
Txs []*Transaction
Uncles []*block.Header
IncomingReceipts CXReceiptsProofs
}
// [deprecated by eth/63]
// "storage" block encoding. used for database.
type storageblock struct {
Header *block.Header
Txs []*Transaction
Uncles []*block.Header
TD *big.Int
var extblockReg = taggedrlp.NewRegistry()
func init() {
extblockReg.MustRegister(taggedrlp.LegacyTag, &extblock{})
extblockReg.MustRegister("v1", &extblockV1{})
}
// NewBlock creates a new block. The input data is copied,
@ -192,7 +289,6 @@ func NewBlockWithHeader(header *block.Header) *Block {
// CopyHeader creates a deep copy of a block header to prevent side effects from
// modifying a header variable.
// TODO ek – no longer necessary
func CopyHeader(h *block.Header) *block.Header {
cpy := *h
cpy.Header = cpy.Header.Copy()
@ -201,35 +297,39 @@ func CopyHeader(h *block.Header) *block.Header {
// DecodeRLP decodes the Ethereum
func (b *Block) DecodeRLP(s *rlp.Stream) error {
var eb extblock
_, size, _ := s.Kind()
if err := s.Decode(&eb); err != nil {
eb, err := extblockReg.Decode(s)
if err != nil {
return err
}
b.header, b.uncles, b.transactions, b.incomingReceipts = eb.Header, eb.Uncles, eb.Txs, eb.IncomingReceipts
switch eb := eb.(type) {
case *extblockV1:
b.header, b.uncles, b.transactions, b.incomingReceipts = eb.Header, eb.Uncles, eb.Txs, eb.IncomingReceipts
case *extblock:
b.header, b.uncles, b.transactions, b.incomingReceipts = eb.Header, eb.Uncles, eb.Txs, nil
default:
return errors.Errorf("unknown extblock type %s", taggedrlp.TypeName(reflect.TypeOf(eb)))
}
b.size.Store(common.StorageSize(rlp.ListSize(size)))
return nil
}
// EncodeRLP serializes b into the Ethereum RLP block format.
func (b *Block) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, extblock{
Header: b.header,
Txs: b.transactions,
Uncles: b.uncles,
IncomingReceipts: b.incomingReceipts,
})
}
// DecodeRLP decodes RLP
// [deprecated by eth/63]
func (b *StorageBlock) DecodeRLP(s *rlp.Stream) error {
var sb storageblock
if err := s.Decode(&sb); err != nil {
return err
var eb interface{}
switch h := b.header.Header.(type) {
case *v1.Header:
eb = extblockV1{b.header, b.transactions, b.uncles, b.incomingReceipts}
case *v0.Header:
if len(b.incomingReceipts) > 0 {
return errors.New("incomingReceipts unsupported in v0 block")
}
eb = extblock{b.header, b.transactions, b.uncles}
default:
return errors.Errorf("unsupported block header type %s",
taggedrlp.TypeName(reflect.TypeOf(h)))
}
b.header, b.uncles, b.transactions, b.td = sb.Header, sb.Uncles, sb.Txs, sb.TD
return nil
return extblockReg.Encode(w, eb)
}
// Uncles return uncles.
@ -309,7 +409,18 @@ func (b *Block) Extra() []byte { return b.header.Extra() }
func (b *Block) Header() *block.Header { return CopyHeader(b.header) }
// Body returns the non-header content of the block.
func (b *Block) Body() *Body { return &Body{b.transactions, b.uncles, b.incomingReceipts} }
func (b *Block) Body() *Body {
body, err := NewBodyForMatchingHeader(b.header)
if err != nil {
utils.Logger().Warn().Err(err).Msg("cannot create block Body struct")
return nil
}
return body.With().
Transactions(b.transactions).
Uncles(b.uncles).
IncomingReceipts(b.incomingReceipts).
Body()
}
// Vdf returns header Vdf.
func (b *Block) Vdf() []byte { return b.header.Vdf() }

@ -19,9 +19,17 @@ package types
import (
"bytes"
"reflect"
"testing"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/taggedrlp"
"github.com/harmony-one/harmony/block"
blockfactory "github.com/harmony-one/harmony/block/factory"
blockif "github.com/harmony-one/harmony/block/interface"
v0 "github.com/harmony-one/harmony/block/v0"
v1 "github.com/harmony-one/harmony/block/v1"
)
var (
@ -110,3 +118,675 @@ func TestBlock_SetLastCommitSig(t *testing.T) {
})
}
}
func TestBlock_DecodeRLP(t *testing.T) {
type args struct {
s *rlp.Stream
}
tests := []struct {
name string
args args
wantErr bool
wantHeaderType reflect.Type
}{
{
"v0",
args{s: rlp.NewStream(bytes.NewBuffer([]byte{
// BEGIN 591-byte extblock
0xf9, 0x02, 0x4f,
// BEGIN 586-byte Header
0xf9, 0x02, 0x4a,
0xa0, // 32-byte ParentHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x94, // 20-byte Coinbase
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte Root
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte TxHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte ReceiptHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb9, 0x01, 0x00, // 256-byte Bloom
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte Number
0x80, // 0-byte GasLimit
0x80, // 0-byte GasUsed
0x80, // 0-byte Time
0x80, // 0-byte Extra
0xa0, // 32-byte MixDigest
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte ViewID
0x80, // 0-byte Epoch
0x80, // 0-byte ShardID
0xb8, 0x60, // 96-byte LastCommitSignature
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte LastCommitBitmap
0xa0, // 32-byte ShardStateHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte ShardState
// END Header
// BEGIN 0-byte Txs
0xc0,
// END Txs
// BEGIN 0-byte Uncles
0xc0,
// END Uncles
// END extblock
}), 0)},
false,
reflect.TypeOf(v0.NewHeader()),
},
{
"v1",
args{s: rlp.NewStream(bytes.NewBuffer([]byte{
// BEGIN 689-byte tagged RLP envelope
0xf9, 0x02, 0xb1,
0x87, // 7-byte tagged RLP signature
'H', 'm', 'n', 'y', 'T', 'g', 'd',
0x82, // 2-byte v1 header tag
'v', '1',
// BEGIN 675-byte extblockV1
0xf9, 0x02, 0xa3,
// BEGIN 669-byte tagged RLP envelope
0xf9, 0x02, 0x9d,
0x87, // 7-byte tagged RLP signature
'H', 'm', 'n', 'y', 'T', 'g', 'd',
0x82, // 2-byte v1 header tag
'v', '1',
// BEGIN 655-byte Header
0xf9, 0x02, 0x8f,
0xa0, // 32-byte ParentHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x94, // 20-byte Coinbase
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte Root
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte TxHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte ReceiptHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte OutgoingReceiptHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte IncomingReceiptHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb9, 0x01, 0x00, // 256-byte Bloom
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte Number
0x80, // 0-byte GasLimit
0x80, // 0-byte GasUsed
0x80, // 0-byte Time
0x80, // 0-byte Extra
0xa0, // 32-byte MixDigest
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte ViewID
0x80, // 0-byte Epoch
0x80, // 0-byte ShardID
0xb8, 0x60, // 96-byte LastCommitSignature
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte LastCommitBitmap
0xa0, // 32-byte ShardStateHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte Vrf
0x80, // 0-byte Vdf
0x80, // 0-byte ShardState
0x80, // 0-byte CrossLinks
// END Header
// END tagged RLP envelope
// BEGIN 0-byte Txs
0xc0,
// END Txs
// BEGIN 0-byte Uncles
0xc0,
// END Uncles
// BEGIN 0-byte IncomingReceipts
0xc0,
// END IncomingReceipts
// END extblockV1
// END tagged RLP envelope
}), 0)},
false,
reflect.TypeOf(v1.NewHeader()),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &Block{}
err := b.DecodeRLP(tt.args.s)
if (err != nil) != tt.wantErr {
t.Errorf("DecodeRLP() error = %v, wantErr %v", err, tt.wantErr)
}
if err != nil {
return
}
gotHeaderType := reflect.TypeOf(b.header.Header)
if gotHeaderType != tt.wantHeaderType {
t.Errorf("DecodeRLP() got header type %s, want %s",
taggedrlp.TypeName(gotHeaderType),
taggedrlp.TypeName(tt.wantHeaderType))
}
})
}
}
func TestBlock_EncodeRLP(t *testing.T) {
tests := []struct {
name string
header blockif.Header
wantBytes []byte
wantErr bool
}{
{
"v0",
&v0.Header{},
[]byte{
// BEGIN 591-byte extblock
0xf9, 0x02, 0x4f,
// BEGIN 586-byte Header
0xf9, 0x02, 0x4a,
0xa0, // 32-byte ParentHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x94, // 20-byte Coinbase
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte Root
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte TxHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte ReceiptHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb9, 0x01, 0x00, // 256-byte Bloom
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte Number
0x80, // 0-byte GasLimit
0x80, // 0-byte GasUsed
0x80, // 0-byte Time
0x80, // 0-byte Extra
0xa0, // 32-byte MixDigest
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte ViewID
0x80, // 0-byte Epoch
0x80, // 0-byte ShardID
0xb8, 0x60, // 96-byte LastCommitSignature
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte LastCommitBitmap
0xa0, // 32-byte ShardStateHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte ShardState
// END Header
// BEGIN 0-byte Txs
0xc0,
// END Txs
// BEGIN 0-byte Uncles
0xc0,
// END Uncles
// END extblock
},
false,
},
{
"v1",
&v1.Header{},
[]byte{
// BEGIN 689-byte tagged RLP envelope
0xf9, 0x02, 0xb1,
0x87, // 7-byte tagged RLP signature
'H', 'm', 'n', 'y', 'T', 'g', 'd',
0x82, // 2-byte v1 header tag
'v', '1',
// BEGIN 675-byte extblockV1
0xf9, 0x02, 0xa3,
// BEGIN 669-byte tagged RLP envelope
0xf9, 0x02, 0x9d,
0x87, // 7-byte tagged RLP signature
'H', 'm', 'n', 'y', 'T', 'g', 'd',
0x82, // 2-byte v1 header tag
'v', '1',
// BEGIN 655-byte Header
0xf9, 0x02, 0x8f,
0xa0, // 32-byte ParentHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x94, // 20-byte Coinbase
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte Root
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte TxHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte ReceiptHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte OutgoingReceiptHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xa0, // 32-byte IncomingReceiptHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb9, 0x01, 0x00, // 256-byte Bloom
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte Number
0x80, // 0-byte GasLimit
0x80, // 0-byte GasUsed
0x80, // 0-byte Time
0x80, // 0-byte Extra
0xa0, // 32-byte MixDigest
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte ViewID
0x80, // 0-byte Epoch
0x80, // 0-byte ShardID
0xb8, 0x60, // 96-byte LastCommitSignature
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte LastCommitBitmap
0xa0, // 32-byte ShardStateHash
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, // 0-byte Vrf
0x80, // 0-byte Vdf
0x80, // 0-byte ShardState
0x80, // 0-byte CrossLinks
// END Header
// END tagged RLP envelope
// BEGIN 0-byte Txs
0xc0,
// END Txs
// BEGIN 0-byte Uncles
0xc0,
// END Uncles
// BEGIN 0-byte IncomingReceipts
0xc0,
// END IncomingReceipts
// END extblockV1
// END tagged RLP envelope
},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &Block{header: &block.Header{tt.header}}
w := &bytes.Buffer{}
err := b.EncodeRLP(w)
if (err != nil) != tt.wantErr {
t.Errorf("EncodeRLP() error = %v, wantErr %v", err, tt.wantErr)
return
}
if gotBytes := w.Bytes(); bytes.Compare(gotBytes, tt.wantBytes) != 0 {
t.Errorf("EncodeRLP() got %x", gotBytes)
t.Errorf("EncodeRLP() want %x", tt.wantBytes)
}
})
}
}
func TestBody_EncodeRLP(t *testing.T) {
tests := []struct {
name string
bodyImpl BodyInterface
wantBytes []byte
wantErr bool
}{
{
"v0",
&BodyV0{},
[]byte{
0xc2, // BEGIN 2-byte BodyV0 struct
0xc0, // BEGIN 0-byte Transactions slice
// END Transactions slice
0xc0, // BEGIN 0-byte Uncles slice
// END Uncles slice
// END BodyV0 struct
},
false,
},
{
"v1",
&BodyV1{},
[]byte{
0xcf, // BEGIN 15-byte tagged RLP envelope
0x87, // BEGIN 7-byte tagged RLP signature
'H', 'm', 'n', 'y', 'T', 'g', 'd',
0x82, // BEGIN 2-byte type tag
'v', '1',
0xc3, // BEGIN 3-byte BodyV1 struct
0xc0, // BEGIN 0-byte Transactions slice
// END Transactions slice
0xc0, // BEGIN 0-byte Uncles slice
// END Uncles slice
0xc0, // BEGIN 0-byte IncomingReceipts slice
// END IncomingReceipts slice
// END BodyV1 struct
// END tagged RLP envelope
},
false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &Body{BodyInterface: tt.bodyImpl}
w := &bytes.Buffer{}
err := b.EncodeRLP(w)
if (err != nil) != tt.wantErr {
t.Errorf("EncodeRLP() error = %v, wantErr %v", err, tt.wantErr)
return
}
if haveBytes := w.Bytes(); bytes.Compare(haveBytes, tt.wantBytes) != 0 {
t.Errorf("EncodeRLP() have %x", haveBytes)
t.Errorf("EncodeRLP() want %x", tt.wantBytes)
}
})
}
}
func TestBody_DecodeRLP(t *testing.T) {
type args struct {
s *rlp.Stream
}
tests := []struct {
name string
args args
wantErr bool
wantBodyType reflect.Type
}{
{
"v0",
args{rlp.NewStream(bytes.NewBuffer([]byte{
0xc2, // BEGIN 2-byte BodyV0 struct
0xc0, // BEGIN 0-byte Transactions slice
// END Transactions slice
0xc0, // BEGIN 0-byte Uncles slice
// END Uncles slice
// END BodyV0 struct
}), 0)},
false,
reflect.TypeOf(&BodyV0{}),
},
{
"v1",
args{rlp.NewStream(bytes.NewBuffer([]byte{
0xcf, // BEGIN 15-byte tagged RLP envelope
0x87, // BEGIN 7-byte tagged RLP signature
'H', 'm', 'n', 'y', 'T', 'g', 'd',
0x82, // BEGIN 2-byte type tag
'v', '1',
0xc3, // BEGIN 3-byte BodyV1 struct
0xc0, // BEGIN 0-byte Transactions slice
// END Transactions slice
0xc0, // BEGIN 0-byte Uncles slice
// END Uncles slice
0xc0, // BEGIN 0-byte IncomingReceipts slice
// END IncomingReceipts slice
// END BodyV1 struct
// END tagged RLP envelope
}), 0)},
false,
reflect.TypeOf(&BodyV1{}),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
b := &Body{}
err := b.DecodeRLP(tt.args.s)
if (err != nil) != tt.wantErr {
t.Errorf("DecodeRLP() error = %v, wantErr %v", err, tt.wantErr)
}
if err != nil {
return
}
haveBodyType := reflect.TypeOf(b.BodyInterface)
if haveBodyType != tt.wantBodyType {
t.Errorf("DecodeRLP() got body type %s, want %s",
taggedrlp.TypeName(haveBodyType),
taggedrlp.TypeName(tt.wantBodyType))
}
})
}
}

@ -0,0 +1,31 @@
package types
import "github.com/harmony-one/harmony/block"
// BodyFieldSetter is a body field setter.
type BodyFieldSetter struct {
b *Body
}
// Transactions sets the Transactions field of the body.
func (bfs BodyFieldSetter) Transactions(newTransactions []*Transaction) BodyFieldSetter {
bfs.b.SetTransactions(newTransactions)
return bfs
}
// Uncles sets the Uncles field of the body.
func (bfs BodyFieldSetter) Uncles(newUncles []*block.Header) BodyFieldSetter {
bfs.b.SetUncles(newUncles)
return bfs
}
// IncomingReceipts sets the IncomingReceipts field of the body.
func (bfs BodyFieldSetter) IncomingReceipts(newIncomingReceipts CXReceiptsProofs) BodyFieldSetter {
bfs.b.SetIncomingReceipts(newIncomingReceipts)
return bfs
}
// Body ends the field setter chain and returns the underlying body itself.
func (bfs BodyFieldSetter) Body() *Body {
return bfs.b
}

@ -0,0 +1,93 @@
package types
import (
"io"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/block"
"github.com/harmony-one/harmony/internal/utils"
)
// BodyV0 is the V0 block body
type BodyV0 struct {
f bodyFieldsV0
}
type bodyFieldsV0 struct {
Transactions []*Transaction
Uncles []*block.Header
}
// Transactions returns the list of transactions.
//
// The returned list is a deep copy; the caller may do anything with it without
// affecting the original.
func (b *BodyV0) Transactions() (txs []*Transaction) {
for _, tx := range b.f.Transactions {
txs = append(txs, tx.Copy())
}
return txs
}
// TransactionAt returns the transaction at the given index in this block.
// It returns nil if index is out of bounds.
func (b *BodyV0) TransactionAt(index int) *Transaction {
if index < 0 || index >= len(b.f.Transactions) {
return nil
}
return b.f.Transactions[index].Copy()
}
// SetTransactions sets the list of transactions with a deep copy of the given
// list.
func (b *BodyV0) SetTransactions(newTransactions []*Transaction) {
var txs []*Transaction
for _, tx := range newTransactions {
txs = append(txs, tx.Copy())
}
b.f.Transactions = txs
}
// Uncles returns a deep copy of the list of uncle headers of this block.
func (b *BodyV0) Uncles() (uncles []*block.Header) {
for _, uncle := range b.f.Uncles {
uncles = append(uncles, CopyHeader(uncle))
}
return uncles
}
// SetUncles sets the list of uncle headers with a deep copy of the given list.
func (b *BodyV0) SetUncles(newUncle []*block.Header) {
var uncles []*block.Header
for _, uncle := range newUncle {
uncles = append(uncles, CopyHeader(uncle))
}
b.f.Uncles = uncles
}
// IncomingReceipts returns a deep copy of the list of incoming cross-shard
// transaction receipts of this block.
func (b *BodyV0) IncomingReceipts() (incomingReceipts CXReceiptsProofs) {
return nil
}
// SetIncomingReceipts sets the list of incoming cross-shard transaction
// receipts of this block with a dep copy of the given list.
func (b *BodyV0) SetIncomingReceipts(newIncomingReceipts CXReceiptsProofs) {
if len(newIncomingReceipts) > 0 {
utils.Logger().Warn().
Msg("cannot store incoming CX receipts in v0 block body")
}
}
// EncodeRLP RLP-encodes the block body into the given writer.
func (b *BodyV0) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, &b.f)
}
// DecodeRLP RLP-decodes a block body from the given RLP stream into the
// receiver.
func (b *BodyV0) DecodeRLP(s *rlp.Stream) error {
return s.Decode(&b.f)
}

@ -0,0 +1,90 @@
package types
import (
"io"
"github.com/ethereum/go-ethereum/rlp"
"github.com/harmony-one/harmony/block"
)
// BodyV1 is the V1 block body
type BodyV1 struct {
f bodyFieldsV1
}
type bodyFieldsV1 struct {
Transactions []*Transaction
Uncles []*block.Header
IncomingReceipts CXReceiptsProofs
}
// Transactions returns the list of transactions.
//
// The returned list is a deep copy; the caller may do anything with it without
// affecting the original.
func (b *BodyV1) Transactions() (txs []*Transaction) {
for _, tx := range b.f.Transactions {
txs = append(txs, tx.Copy())
}
return txs
}
// TransactionAt returns the transaction at the given index in this block.
// It returns nil if index is out of bounds.
func (b *BodyV1) TransactionAt(index int) *Transaction {
if index < 0 || index >= len(b.f.Transactions) {
return nil
}
return b.f.Transactions[index].Copy()
}
// SetTransactions sets the list of transactions with a deep copy of the given
// list.
func (b *BodyV1) SetTransactions(newTransactions []*Transaction) {
var txs []*Transaction
for _, tx := range newTransactions {
txs = append(txs, tx.Copy())
}
b.f.Transactions = txs
}
// Uncles returns a deep copy of the list of uncle headers of this block.
func (b *BodyV1) Uncles() (uncles []*block.Header) {
for _, uncle := range b.f.Uncles {
uncles = append(uncles, CopyHeader(uncle))
}
return uncles
}
// SetUncles sets the list of uncle headers with a deep copy of the given list.
func (b *BodyV1) SetUncles(newUncle []*block.Header) {
var uncles []*block.Header
for _, uncle := range newUncle {
uncles = append(uncles, CopyHeader(uncle))
}
b.f.Uncles = uncles
}
// IncomingReceipts returns a deep copy of the list of incoming cross-shard
// transaction receipts of this block.
func (b *BodyV1) IncomingReceipts() (incomingReceipts CXReceiptsProofs) {
return b.f.IncomingReceipts.Copy()
}
// SetIncomingReceipts sets the list of incoming cross-shard transaction
// receipts of this block with a dep copy of the given list.
func (b *BodyV1) SetIncomingReceipts(newIncomingReceipts CXReceiptsProofs) {
b.f.IncomingReceipts = newIncomingReceipts.Copy()
}
// EncodeRLP RLP-encodes the block body into the given writer.
func (b *BodyV1) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, &b.f)
}
// DecodeRLP RLP-decodes a block body from the given RLP stream into the
// receiver.
func (b *BodyV1) DecodeRLP(s *rlp.Stream) error {
return s.Decode(&b.f)
}

@ -20,12 +20,34 @@ type CXReceipt struct {
Amount *big.Int
}
// Copy makes a deep copy of the receiver.
func (r *CXReceipt) Copy() *CXReceipt {
if r == nil {
return nil
}
cpy := *r
if cpy.To != nil {
to := *cpy.To
cpy.To = &to
}
cpy.Amount = new(big.Int).Set(cpy.Amount)
return &cpy
}
// CXReceipts is a list of CXReceipt
type CXReceipts []*CXReceipt
// Len returns the length of s.
func (cs CXReceipts) Len() int { return len(cs) }
// Copy makes a deep copy of the receiver.
func (cs CXReceipts) Copy() (cpy CXReceipts) {
for _, r := range cs {
cpy = append(cpy, r.Copy())
}
return cpy
}
// Swap swaps the i'th and the j'th element in s.
func (cs CXReceipts) Swap(i, j int) { cs[i], cs[j] = cs[j], cs[i] }
@ -70,6 +92,18 @@ type CXMerkleProof struct {
CXShardHashes []common.Hash // ordered hash list, each hash corresponds to one destination shard's receipts root hash
}
// Copy makes a deep copy of the receiver.
func (cxmp *CXMerkleProof) Copy() *CXMerkleProof {
if cxmp == nil {
return nil
}
cpy := *cxmp
cpy.BlockNum = new(big.Int).Set(cpy.BlockNum)
cpy.ShardIDs = append(cxmp.ShardIDs[:0:0], cpy.ShardIDs...)
cpy.CXShardHashes = append(cpy.CXShardHashes[:0:0], cpy.CXShardHashes...)
return &cpy
}
// CXReceiptsProof carrys the cross shard receipts and merkle proof
type CXReceiptsProof struct {
Receipts CXReceipts
@ -79,12 +113,31 @@ type CXReceiptsProof struct {
CommitBitmap []byte
}
// Copy makes a deep copy of the receiver.
func (cxp *CXReceiptsProof) Copy() *CXReceiptsProof {
return &CXReceiptsProof{
Receipts: cxp.Receipts.Copy(),
MerkleProof: cxp.MerkleProof.Copy(),
Header: CopyHeader(cxp.Header),
CommitSig: append(cxp.CommitSig[:0:0], cxp.CommitSig...),
CommitBitmap: append(cxp.CommitBitmap[:0:0], cxp.CommitSig...),
}
}
// CXReceiptsProofs is a list of CXReceiptsProof
type CXReceiptsProofs []*CXReceiptsProof
// Len returns the length of s.
func (cs CXReceiptsProofs) Len() int { return len(cs) }
// Copy makes a deep copy of the receiver.
func (cs CXReceiptsProofs) Copy() (cpy CXReceiptsProofs) {
for _, cxrp := range cs {
cpy = append(cpy, cxrp.Copy())
}
return cpy
}
// Swap swaps the i'th and the j'th element in s.
func (cs CXReceiptsProofs) Swap(i, j int) { cs[i], cs[j] = cs[j], cs[i] }

@ -90,6 +90,37 @@ type txdata struct {
Hash *common.Hash `json:"hash" rlp:"-"`
}
func copyAddr(addr *common.Address) *common.Address {
if addr == nil {
return nil
}
copy := *addr
return &copy
}
func copyHash(hash *common.Hash) *common.Hash {
if hash == nil {
return nil
}
copy := *hash
return &copy
}
func (d *txdata) CopyFrom(d2 *txdata) {
d.AccountNonce = d2.AccountNonce
d.Price = new(big.Int).Set(d2.Price)
d.GasLimit = d2.GasLimit
d.ShardID = d2.ShardID
d.ToShardID = d2.ToShardID
d.Recipient = copyAddr(d2.Recipient)
d.Amount = new(big.Int).Set(d2.Amount)
d.Payload = append(d2.Payload[:0:0], d2.Payload...)
d.V = new(big.Int).Set(d2.V)
d.R = new(big.Int).Set(d2.R)
d.S = new(big.Int).Set(d2.S)
d.Hash = copyHash(d2.Hash)
}
type txdataMarshaling struct {
AccountNonce hexutil.Uint64
Price *hexutil.Big
@ -356,6 +387,13 @@ func (tx *Transaction) RawSignatureValues() (*big.Int, *big.Int, *big.Int) {
return tx.data.V, tx.data.R, tx.data.S
}
// Copy returns a copy of the transaction.
func (tx *Transaction) Copy() *Transaction {
var tx2 Transaction
tx2.data.CopyFrom(&tx.data)
return &tx2
}
// Transactions is a Transaction slice type for basic sorting.
type Transactions []*Transaction

Loading…
Cancel
Save