From 9637d74c72de9bbd92ae61b09875ebe7c5fc3139 Mon Sep 17 00:00:00 2001
From: Alex Sharov <AskAlexSharov@gmail.com>
Date: Wed, 9 Jun 2021 14:20:47 +0700
Subject: [PATCH] More correct rlp of Sokol headers (#2124)

* save

* better rlp support

* save
---
 core/genesis.go              |  8 ++--
 core/types/block.go          | 49 +++++++++++++++++-------
 turbo/stages/genesis_test.go | 72 ++++++++++++++++++++++++------------
 3 files changed, 87 insertions(+), 42 deletions(-)

diff --git a/core/genesis.go b/core/genesis.go
index 37de2cf836..b15017f245 100644
--- a/core/genesis.go
+++ b/core/genesis.go
@@ -40,7 +40,6 @@ import (
 	"github.com/ledgerwatch/erigon/ethdb"
 	"github.com/ledgerwatch/erigon/log"
 	"github.com/ledgerwatch/erigon/params"
-	"github.com/ledgerwatch/erigon/rlp"
 	"github.com/ledgerwatch/erigon/turbo/trie"
 )
 
@@ -66,7 +65,7 @@ type Genesis struct {
 	Mixhash    common.Hash         `json:"mixHash"`
 	Coinbase   common.Address      `json:"coinbase"`
 	Alloc      GenesisAlloc        `json:"alloc"      gencodec:"required"`
-	Seal       []rlp.RawValue      `json:"seal"`
+	Seal       [][]byte            `json:"seal"`
 
 	// These fields are used for consensus tests. Please don't use them
 	// in actual genesis blocks.
@@ -590,8 +589,9 @@ func DefaultSokolGenesisBlock() *Genesis {
 	return &Genesis{
 		Config:    params.SokolChainConfig,
 		Timestamp: 0x0,
-		Seal: []rlp.RawValue{
-			hexutil.MustDecode("0xb8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
+		Seal: [][]byte{
+			common.FromHex(""),
+			common.FromHex("0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"),
 		},
 		GasLimit:   0x663BE0,
 		Difficulty: big.NewInt(0x20000),
diff --git a/core/types/block.go b/core/types/block.go
index b0e3b0a6ae..a2a7ca86ab 100644
--- a/core/types/block.go
+++ b/core/types/block.go
@@ -88,7 +88,7 @@ type Header struct {
 	Nonce       BlockNonce     `json:"nonce"`
 	BaseFee     *big.Int       `json:"baseFee"`
 	Eip1559     bool           // to avoid relying on BaseFee != nil for that
-	Seal        []rlp.RawValue // AuRa POA network field
+	Seal        [][]byte       // AuRa POA network field
 	WithSeal    bool           // to avoid relying on Seal != nil for that
 }
 
@@ -96,12 +96,24 @@ func (h Header) EncodingSize() int {
 	encodingSize := 33 /* ParentHash */ + 33 /* UncleHash */ + 21 /* Coinbase */ + 33 /* Root */ + 33 /* TxHash */ +
 		33 /* ReceiptHash */ + 259 /* Bloom */
 
+	var sealListLen int
 	if h.WithSeal {
-		encodingSize++
 		for i := range h.Seal {
-			//encodingSize++
-			encodingSize += len(h.Seal[i])
+			sealListLen++
+			switch len(h.Seal[i]) {
+			case 0:
+			case 1:
+				if h.Seal[i][0] >= 128 {
+					sealListLen++
+				}
+			default:
+				if len(h.Seal[i]) >= 56 {
+					sealListLen += (bits.Len(uint(len(h.Seal[i]))) + 7) / 8
+				}
+				sealListLen += len(h.Seal[i])
+			}
 		}
+		encodingSize += sealListLen
 	} else {
 		encodingSize += 33 /* MixDigest */ + 9 /* BlockNonce */
 	}
@@ -166,12 +178,25 @@ func (h Header) EncodeRLP(w io.Writer) error {
 	// Precompute the size of the encoding
 	encodingSize := 33 /* ParentHash */ + 33 /* UncleHash */ + 21 /* Coinbase */ + 33 /* Root */ + 33 /* TxHash */ +
 		33 /* ReceiptHash */ + 259 /* Bloom */
+
+	var sealListLen int
 	if h.WithSeal {
-		encodingSize++
 		for i := range h.Seal {
-			//encodingSize++
-			encodingSize += len(h.Seal[i])
+			sealListLen++
+			switch len(h.Seal[i]) {
+			case 0:
+			case 1:
+				if h.Seal[i][0] >= 128 {
+					sealListLen++
+				}
+			default:
+				if len(h.Seal[i]) >= 56 {
+					sealListLen += (bits.Len(uint(len(h.Seal[i]))) + 7) / 8
+				}
+				sealListLen += len(h.Seal[i])
+			}
 		}
+		encodingSize += sealListLen
 	} else {
 		encodingSize += 33 /* MixDigest */ + 9 /* BlockNonce */
 	}
@@ -351,12 +376,8 @@ func (h Header) EncodeRLP(w io.Writer) error {
 	}
 
 	if h.WithSeal {
-		b[0] = 128
-		if _, err := w.Write(b[:1]); err != nil {
-			return err
-		}
 		for i := range h.Seal {
-			if _, err := w.Write(h.Seal[i]); err != nil {
+			if err := EncodeString(h.Seal[i], w, b[:]); err != nil {
 				return err
 			}
 		}
@@ -482,7 +503,7 @@ func (h *Header) DecodeRLP(s *rlp.Stream) error {
 
 	if h.WithSeal {
 		h.WithSeal = true
-		for b, err = s.Raw(); err == nil; b, err = s.Raw() {
+		for b, err = s.Bytes(); err == nil; b, err = s.Bytes() {
 			h.Seal = append(h.Seal, make(rlp.RawValue, len(b)))
 			copy(h.Seal[len(h.Seal)-1][:], b)
 		}
@@ -963,7 +984,7 @@ func CopyHeader(h *Header) *Header {
 		copy(cpy.Extra, h.Extra)
 	}
 	if len(h.Seal) > 0 {
-		cpy.Seal = make([]rlp.RawValue, len(h.Seal))
+		cpy.Seal = make([][]byte, len(h.Seal))
 		for i := range h.Seal {
 			cpy.Seal[i] = common.CopyBytes(h.Seal[i])
 		}
diff --git a/turbo/stages/genesis_test.go b/turbo/stages/genesis_test.go
index 7d86cfe7d1..e262e4dd6f 100644
--- a/turbo/stages/genesis_test.go
+++ b/turbo/stages/genesis_test.go
@@ -17,8 +17,8 @@
 package stages_test
 
 import (
-	"bytes"
 	"context"
+	"fmt"
 	"math/big"
 	"reflect"
 	"testing"
@@ -61,6 +61,8 @@ func TestDefaultGenesisBlock(t *testing.T) {
 	if err != nil {
 		t.Errorf("error: %w", err)
 	}
+	aa, _ := rlp.EncodeToBytes(block.Header())
+	fmt.Printf("a: %x\n", aa)
 	if block.Root() != params.SokolGenesisStateRoot {
 		t.Errorf("wrong sokol genesis state root, got %v, want %v", block.Root(), params.SokolGenesisStateRoot)
 	}
@@ -70,30 +72,52 @@ func TestDefaultGenesisBlock(t *testing.T) {
 }
 
 func TestSokolHeaderRLP(t *testing.T) {
-	block, _, err := core.DefaultSokolGenesisBlock().ToBlock()
-	require.NoError(t, err)
-	b, err := rlp.EncodeToBytes(block.Header())
-	require.NoError(t, err)
-	expect := common.FromHex("f9020da00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0fad4af258fd11939fae0c6c6eec9d340b1caac0b0196fd9a1bc3f489c5bf00b3a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083663be080808080b8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
-	require.Equal(t, expect, b)
-
-	{
-		h2 := &types.Header{WithSeal: true}
-		err = rlp.Decode(bytes.NewReader(expect), h2)
-		require.NoError(t, err)
-		require.Equal(t, 2, len(h2.Seal))
-		expectSeal2 := common.FromHex("b8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
-		require.Equal(t, common.FromHex("80"), []byte(h2.Seal[0]))
-		require.Equal(t, expectSeal2, []byte(h2.Seal[1]))
+	require := require.New(t)
+	{ //sokol
+		expect := common.FromHex("f9020da00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0fad4af258fd11939fae0c6c6eec9d340b1caac0b0196fd9a1bc3f489c5bf00b3a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083663be080808080b8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
+		block, _, err := core.DefaultSokolGenesisBlock().ToBlock()
+		require.NoError(err)
+		b, err := rlp.EncodeToBytes(block.Header())
+		require.NoError(err)
+		require.Equal(expect, b)
+		h := &types.Header{WithSeal: true}
+		err = rlp.DecodeBytes(expect, h)
+		require.NoError(err)
+		require.Equal(2, len(h.Seal))
+
+		expectSeal2 := common.FromHex("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")
+		require.Equal(common.FromHex(""), h.Seal[0])
+		require.Equal(expectSeal2, h.Seal[1])
+		enc, err := rlp.EncodeToBytes(h)
+		require.NoError(err)
+		require.Equal(expect, enc)
 	}
-	{
-		h3 := &types.Header{WithSeal: true}
-		err = rlp.Decode(bytes.NewReader(common.FromHex("f9020da00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0fad4af258fd11939fae0c6c6eec9d340b1caac0b0196fd9a1bc3f489c5bf00b3a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083663be080808001b8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001")), h3)
-		require.NoError(t, err)
-		require.Equal(t, 2, len(h3.Seal))
-		require.Equal(t, common.FromHex("1"), []byte(h3.Seal[0]))
-		expectSeal2 := common.FromHex("b8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001")
-		require.Equal(t, expectSeal2, []byte(h3.Seal[1]))
+
+	{ // sokol, more seals
+		h := &types.Header{WithSeal: true}
+		enc := common.FromHex("f9020da00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347940000000000000000000000000000000000000000a0fad4af258fd11939fae0c6c6eec9d340b1caac0b0196fd9a1bc3f489c5bf00b3a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000830200008083663be080808002b8410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001")
+		err := rlp.DecodeBytes(enc, h)
+		require.NoError(err)
+		require.Equal(2, len(h.Seal))
+		require.Equal(common.FromHex("2"), h.Seal[0])
+
+		expectSeal2 := common.FromHex("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001")
+		require.Equal(expectSeal2, h.Seal[1])
+
+		res, err := rlp.EncodeToBytes(h) // after encode getting source bytes
+		require.NoError(err)
+		require.Equal(enc, res)
+	}
+
+	{ // ethash
+		expect := common.FromHex("f901f9a0d405da4e66f1445d455195229624e133f5baafe72b5cf7b3c36c12c8146e98b7a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a05fb2b4bfdef7b314451cb138a534d225c922fc0e5fbe25e451142732c3e25c25a088d2ec6b9860aae1a2c3b299f72b6a5d70d7f7ba4722c78f2c49ba96273c2158a007c6fdfa8eea7e86b81f5b0fc0f78f90cc19f4aa60d323151e0cac660199e9a1b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302008003832fefba82524d84568e932a80a0a0349d8c3df71f1a48a9df7d03fd5f14aeee7d91332c009ecaff0a71ead405bd88ab4e252a7e8c2a23")
+		h := &types.Header{WithSeal: false}
+		err := rlp.DecodeBytes(expect, h)
+		require.NoError(err)
+
+		res, err := rlp.EncodeToBytes(h) // after encode getting source bytes
+		require.NoError(err)
+		require.Equal(expect, res)
 	}
 }
 
-- 
GitLab