Version block body (types.Body)

Follow the same strategy for header versioning, except put everything
into the same "./core/types" package – for now.  Adaptation of the
existing code outside the package to come next.
pull/1546/head
Eugene Kim 5 years ago
parent 1a1caa422d
commit 070a42c387
  1. 84
      core/types/block.go
  2. 31
      core/types/bodyfieldsetter.go
  3. 84
      core/types/bodyv0.go
  4. 81
      core/types/bodyv1.go

@ -35,6 +35,7 @@ import (
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/harmony-one/harmony/block" "github.com/harmony-one/harmony/block"
blockfactory "github.com/harmony-one/harmony/block/factory"
v0 "github.com/harmony-one/harmony/block/v0" v0 "github.com/harmony-one/harmony/block/v0"
v1 "github.com/harmony-one/harmony/block/v1" v1 "github.com/harmony-one/harmony/block/v1"
"github.com/harmony-one/harmony/crypto/hash" "github.com/harmony-one/harmony/crypto/hash"
@ -103,9 +104,72 @@ type BodyInterface interface {
// Body is a simple (mutable, non-safe) data container for storing and moving // Body is a simple (mutable, non-safe) data container for storing and moving
// a block's data contents (transactions and uncles) together. // a block's data contents (transactions and uncles) together.
type Body struct { type Body struct {
Transactions []*Transaction BodyInterface
Uncles []*block.Header }
IncomingReceipts CXReceiptsProofs
// 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. // Block represents an entire block in the Ethereum blockchain.
@ -221,7 +285,6 @@ func NewBlockWithHeader(header *block.Header) *Block {
// CopyHeader creates a deep copy of a block header to prevent side effects from // CopyHeader creates a deep copy of a block header to prevent side effects from
// modifying a header variable. // modifying a header variable.
// TODO ek – no longer necessary
func CopyHeader(h *block.Header) *block.Header { func CopyHeader(h *block.Header) *block.Header {
cpy := *h cpy := *h
cpy.Header = cpy.Header.Copy() cpy.Header = cpy.Header.Copy()
@ -342,7 +405,18 @@ func (b *Block) Extra() []byte { return b.header.Extra() }
func (b *Block) Header() *block.Header { return CopyHeader(b.header) } func (b *Block) Header() *block.Header { return CopyHeader(b.header) }
// Body returns the non-header content of the block. // 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. // Vdf returns header Vdf.
func (b *Block) Vdf() []byte { return b.header.Vdf() } func (b *Block) Vdf() []byte { return b.header.Vdf() }

@ -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,84 @@
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
}
// 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,81 @@
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
}
// 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)
}
Loading…
Cancel
Save