From 746a107e2a7bb1f66049240d320e29d0a0536eae Mon Sep 17 00:00:00 2001 From: Determinant Date: Sun, 2 Aug 2020 18:44:47 -0400 Subject: make block-format backward-compatible and future-proof --- core/types/block.go | 61 +++++++++++++++++++-- examples/block/main.go | 146 +++++++++++++++++++++++++++++++++++++++++++++++++ go.sum | 3 + 3 files changed, 204 insertions(+), 6 deletions(-) create mode 100644 examples/block/main.go diff --git a/core/types/block.go b/core/types/block.go index 2fdc904..fcbd8ab 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -18,6 +18,7 @@ package types import ( + "bytes" "encoding/binary" "fmt" "io" @@ -149,6 +150,7 @@ type Block struct { header *Header uncles []*Header transactions Transactions + extdata []byte // caches hash atomic.Value @@ -184,6 +186,14 @@ type extblock struct { Uncles []*Header } +type myextblock struct { + Header *Header + Txs []*Transaction + Uncles []*Header + VersionNumber uint32 + ExtData []byte +} + // [deprecated by eth/63] // "storage" block encoding. used for database. type storageblock struct { @@ -258,18 +268,35 @@ func CopyHeader(h *Header) *Header { // DecodeRLP decodes the Ethereum func (b *Block) DecodeRLP(s *rlp.Stream) error { + bs, _ := s.Raw() + copied := make([]byte, len(bs)) + copy(copied, bs) + ss := rlp.NewStream(bytes.NewReader(bs), 0) + var eb extblock - _, size, _ := s.Kind() - if err := s.Decode(&eb); err != nil { - return err + _, size, _ := ss.Kind() + if err := ss.Decode(&eb); err != nil { + var meb myextblock + ss = rlp.NewStream(bytes.NewReader(copied), 0) + if err := ss.Decode(&meb); err != nil { + return err + } + b.header, b.uncles, b.transactions = meb.Header, meb.Uncles, meb.Txs + b.extdata = meb.ExtData + } else { + b.header, b.uncles, b.transactions = eb.Header, eb.Uncles, eb.Txs + b.extdata = nil } - b.header, b.uncles, b.transactions = eb.Header, eb.Uncles, eb.Txs 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 { +func (b *Block) RawExtraData() []byte { + return b.extdata +} + +// EncodeRLPEth serializes b into the Ethereum RLP block format. +func (b *Block) EncodeRLPEth(w io.Writer) error { return rlp.Encode(w, extblock{ Header: b.header, Txs: b.transactions, @@ -277,6 +304,28 @@ func (b *Block) EncodeRLP(w io.Writer) error { }) } +func (b *Block) EncodeRLPTest(w io.Writer, ver uint32, data []byte) error { + return rlp.Encode(w, myextblock{ + Header: b.header, + Txs: b.transactions, + Uncles: b.uncles, + VersionNumber: ver, + ExtData: data, + }) +} + +// EncodeRLP serializes b into an extended format. +func (b *Block) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, myextblock{ + Header: b.header, + Txs: b.transactions, + Uncles: b.uncles, + VersionNumber: 0, + // TODO: add actual extra data for the current version + ExtData: []byte{}, + }) +} + // [deprecated by eth/63] func (b *StorageBlock) DecodeRLP(s *rlp.Stream) error { var sb storageblock diff --git a/examples/block/main.go b/examples/block/main.go new file mode 100644 index 0000000..d9ea16b --- /dev/null +++ b/examples/block/main.go @@ -0,0 +1,146 @@ +package main + +import ( + "bytes" + "crypto/rand" + "fmt" + "github.com/ava-labs/coreth" + "github.com/ava-labs/coreth/core" + "github.com/ava-labs/coreth/core/types" + "github.com/ava-labs/coreth/eth" + "github.com/ava-labs/coreth/params" + "github.com/ava-labs/go-ethereum/common" + "github.com/ava-labs/go-ethereum/common/hexutil" + "github.com/ava-labs/go-ethereum/rlp" + "math/big" +) + +func checkError(err error) { + if err != nil { + panic(err) + } +} + +func main() { + // configure the chain + config := eth.DefaultConfig + config.ManualCanonical = true + chainConfig := ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + HomesteadBlock: big.NewInt(0), + DAOForkBlock: big.NewInt(0), + DAOForkSupport: true, + EIP150Block: big.NewInt(0), + EIP150Hash: common.HexToHash("0x2086799aeebeae135c246c65021c82b4e15a2c451340993aacfd2751886514f0"), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: nil, + Ethash: nil, + } + + // configure the genesis block + genBalance := big.NewInt(100000000000000000) + genKey, _ := coreth.NewKey(rand.Reader) + + config.Genesis = &core.Genesis{ + Config: chainConfig, + Nonce: 0, + Number: 0, + ExtraData: hexutil.MustDecode("0x00"), + GasLimit: 100000000, + Difficulty: big.NewInt(0), + Alloc: core.GenesisAlloc{genKey.Address: {Balance: genBalance}}, + } + + // grab the control of block generation and disable auto uncle + config.Miner.ManualMining = true + config.Miner.DisableUncle = true + + chain := coreth.NewETHChain(&config, nil, nil, nil) + buff := new(bytes.Buffer) + blk := chain.GetGenesisBlock() + err := blk.EncodeRLPEth(buff) + buff.WriteString("somesuffix") + checkError(err) + var blk2 *types.Block + blk2 = new(types.Block) + fmt.Println(buff.Len()) + fmt.Println(common.ToHex(buff.Bytes())) + + err = rlp.Decode(buff, blk2) + fmt.Println(buff.Len()) + checkError(err) + buff.Reset() + err = blk2.EncodeRLPEth(buff) + checkError(err) + fmt.Println(buff.Len()) + fmt.Println(common.ToHex(buff.Bytes())) + + err = rlp.Decode(buff, blk2) + fmt.Println(buff.Len()) + checkError(err) + buff.Reset() + err = blk2.EncodeRLP(buff) + checkError(err) + buff.WriteString("somesuffix") + fmt.Println(buff.Len()) + fmt.Println(common.ToHex(buff.Bytes())) + + err = rlp.Decode(buff, blk2) + fmt.Println(buff.Len()) + checkError(err) + buff.Reset() + err = blk2.EncodeRLP(buff) + checkError(err) + fmt.Println(buff.Len()) + fmt.Println(common.ToHex(buff.Bytes())) + + err = rlp.Decode(buff, blk2) + fmt.Println(buff.Len()) + checkError(err) + buff.Reset() + extra, err := rlp.EncodeToBytes("test extra data") + err = blk2.EncodeRLPTest(buff, 0xffffffff, extra) + checkError(err) + buff.WriteString("somesuffix") + fmt.Println(buff.Len()) + fmt.Println(common.ToHex(buff.Bytes())) + + err = rlp.Decode(buff, blk2) + fmt.Println(buff.Len(), (string)(blk2.RawExtraData())) + checkError(err) + buff.Reset() + type NestedData struct { + A uint16 + B uint16 + S string + } + type MyData struct { + X uint32 + Y uint32 + Msg string + Inner NestedData + } + extra, err = rlp.EncodeToBytes(MyData{ + X: 4200, Y: 4300, Msg: "hello", Inner: NestedData{A: 1, B: 2, S: "world"}, + }) + checkError(err) + err = blk2.EncodeRLPTest(buff, 0xfffffffe, extra) + checkError(err) + decoded1 := new(string) + err = rlp.DecodeBytes(blk2.RawExtraData(), decoded1) + checkError(err) + fmt.Println(buff.Len(), decoded1) + fmt.Println(common.ToHex(buff.Bytes())) + + err = rlp.Decode(buff, blk2) + checkError(err) + decoded2 := new(MyData) + err = rlp.DecodeBytes(blk2.RawExtraData(), decoded2) + checkError(err) + fmt.Println(buff.Len(), decoded2) + buff.Reset() +} diff --git a/go.sum b/go.sum index ff050d6..e8621cb 100644 --- a/go.sum +++ b/go.sum @@ -126,8 +126,10 @@ github.com/klauspost/reedsolomon v1.9.3/go.mod h1:CwCi+NUr9pqSVktrkN+Ondf06rkhYZ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -309,6 +311,7 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/bsm/ratelimit.v1 v1.0.0-20160220154919-db14e161995a/go.mod h1:KF9sEfUPAXdG8Oev9e99iLGnl2uJMjc5B+4y3O7x610= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/jcmturner/aescts.v1 v1.0.1/go.mod h1:nsR8qBOg+OucoIW+WMhB3GspUQXq9XorLnQb9XtvcOo= -- cgit v1.2.3