forked from bnb-chain/bsc
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tool: add a tool extradump to parse extra data after luban (bnb-chain…
- Loading branch information
Showing
2 changed files
with
270 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package main | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestExtraParse(t *testing.T) { | ||
// case 1, |---Extra Vanity---|---Empty---|---Empty---|---Extra Seal---| | ||
{ | ||
extraData := "0xd983010209846765746889676f312e31392e3131856c696e75780000a6bf97c1e99f701bb14cb7dfb68b90bd3e6d1ca656964630de71beffc7f33f7f08ec99d336ec51ad9fad0ac84ae77ca2e8ad9512acc56e0d7c93f3c2ce7de1b69149a5a400" | ||
_, err := parseExtra(extraData) | ||
assert.NoError(t, err) | ||
} | ||
|
||
// case 2, |---Extra Vanity---|---Validators Number and Validators Bytes---|---Empty---|---Extra Seal---| | ||
{ | ||
extraData := "0xd983010209846765746889676f312e31392e3131856c696e75780000a6bf97c1152465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e912d4c407bbe49438ed859fe965b140dcf1aab71a993c1f7f6929d1fe2a17b4e14614ef9fc5bdc713d6631d675403fbeefac55611bf612700b1b65f4744861b80b0f7d6ab03f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000069c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b218c5d6af1f979ac42bc68d98a5a0d796c6ab01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e2d3a739effcd3a99387d015e260eefac72ebea1956c470ddff48cb49300200b5f83497f3a3ccb3aeb83c5edd9818569038e61d197184f4aa6939ea5e9911e3e98ac6d21e9ae3261a475a27bb1028f140bc2a7c843318afd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ef0274e31810c9df02f98fafde0f841f4e66a1cd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e99f701bb14cb7dfb68b90bd3e6d1ca656964630de71beffc7f33f7f08ec99d336ec51ad9fad0ac84ae77ca2e8ad9512acc56e0d7c93f3c2ce7de1b69149a5a400" | ||
extra, err := parseExtra(extraData) | ||
assert.NoError(t, err) | ||
{ | ||
var have = extra.ValidatorSize | ||
var want = uint8(21) | ||
if have != want { | ||
t.Fatalf("extra.ValidatorSize mismatch, have %d, want %d", have, want) | ||
} | ||
} | ||
{ | ||
var have = common.Bytes2Hex(extra.Validators[14].Address[:]) | ||
var want = "cc8e6d00c17eb431350c6c50d8b8f05176b90b11" | ||
if have != want { | ||
t.Fatalf("extra.Validators[14].Address mismatch, have %s, want %s", have, want) | ||
} | ||
} | ||
{ | ||
var have = common.Bytes2Hex(extra.Validators[18].BLSPublicKey[:]) | ||
var want = "b2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183" | ||
if have != want { | ||
t.Fatalf("extra.Validators[18].BLSPublicKey mismatch, have %s, want %s", have, want) | ||
} | ||
} | ||
} | ||
|
||
// case 3, |---Extra Vanity---|---Empty---|---Vote Attestation---|---Extra Seal---| | ||
{ | ||
extraData := "0xd883010205846765746888676f312e32302e35856c696e75780000002995c52af8b5830563efb86089cf168dcf4c5d3cb057926628ad1bf0f03ea67eef1458485578a4f8489afa8a853ecc7af45e2d145c21b70641c4b29f0febd2dd2c61fa1ba174be3fd47f1f5fa2ab9b5c318563d8b70ca58d0d51e79ee32b2fb721649e2cb9d36538361fba11f84c8401d14bb7a0fa67ddb3ba654d6006bf788710032247aa4d1be0707273e696b422b3ff72e9798401d14bbaa01225f505f5a0e1aefadcd2913b7aac9009fe4fb3d1bf57399e0b9dce5947f94280fe6d3647276c4127f437af59eb7c7985b2ae1ebe432619860695cb6106b80cc66c735bc1709afd11f233a2c97409d38ebaf7178aa53e895aea2fe0a229f71ec601" | ||
extra, err := parseExtra(extraData) | ||
assert.NoError(t, err) | ||
{ | ||
var have = common.Bytes2Hex(extra.Data.TargetHash[:]) | ||
var want = "1225f505f5a0e1aefadcd2913b7aac9009fe4fb3d1bf57399e0b9dce5947f942" | ||
if have != want { | ||
t.Fatalf("extra.Data.TargetHash mismatch, have %s, want %s", have, want) | ||
} | ||
} | ||
{ | ||
var have = extra.Data.TargetNumber | ||
var want = uint64(30493626) | ||
if have != want { | ||
t.Fatalf("extra.Data.TargetNumber mismatch, have %d, want %d", have, want) | ||
} | ||
} | ||
} | ||
|
||
// case 4, |---Extra Vanity---|---Validators Number and Validators Bytes---|---Vote Attestation---|---Extra Seal---| | ||
{ | ||
extraData := "0xd883010209846765746888676f312e31392e38856c696e7578000000dc55905c071284214b9b9c85549ab3d2b972df0deef66ac2c98e82934ca974fdcd97f3309de967d3c9c43fa711a8d673af5d75465844bf8969c8d1948d903748ac7b8b1720fa64e50c35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f247788386d0ed6c748e03a53160b4b30ed3748cc5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b878f8b27bb8608c11016739b3f8a19e54ab8c7abacd936cfeba200f3645a98b65adb0dd3692b69ce0b3ae10e7176b9a4b0d83f04065b1042b4bcb646a34b75c550f92fc34b8b2b1db0fa0d3172db23ba92727c80bcd306320d0ff411bf858525fde13bc8e0370f84c8401e9c2e6a0820dc11d63176a0eb1b828bc5376867b275579112b7013358da40317e7bab6e98401e9c2e7a00edc71ce80105a3220a87bea2792fa340d66c59002f02b0a09349ed1ed284070808b972fac2b9077a4dcb6fc37093799a652858016c99142b227500c844fa97ec22e3f9d3b1e982f14bcd999a7453e89ce5ef5c55f1c7f8f74ba904186cd67828200" | ||
extra, err := parseExtra(extraData) | ||
assert.NoError(t, err) | ||
{ | ||
var have = common.Bytes2Hex(extra.Validators[0].Address[:]) | ||
var want = "1284214b9b9c85549ab3d2b972df0deef66ac2c9" | ||
if have != want { | ||
t.Fatalf("extra.Validators[0].Address mismatch, have %s, want %s", have, want) | ||
} | ||
} | ||
{ | ||
var have = common.Bytes2Hex(extra.Validators[0].BLSPublicKey[:]) | ||
var want = "8e82934ca974fdcd97f3309de967d3c9c43fa711a8d673af5d75465844bf8969c8d1948d903748ac7b8b1720fa64e50c" | ||
if have != want { | ||
t.Fatalf("extra.Validators[0].BLSPublicKey mismatch, have %s, want %s", have, want) | ||
} | ||
} | ||
{ | ||
var have = extra.Validators[0].VoteIncluded | ||
var want = true | ||
if have != want { | ||
t.Fatalf("extra.Validators[0].VoteIncluded mismatch, have %t, want %t", have, want) | ||
} | ||
} | ||
{ | ||
var have = common.Bytes2Hex(extra.Data.TargetHash[:]) | ||
var want = "0edc71ce80105a3220a87bea2792fa340d66c59002f02b0a09349ed1ed284070" | ||
if have != want { | ||
t.Fatalf("extra.Data.TargetHash mismatch, have %s, want %s", have, want) | ||
} | ||
} | ||
{ | ||
var have = extra.Data.TargetNumber | ||
var want = uint64(32096999) | ||
if have != want { | ||
t.Fatalf("extra.Data.TargetNumber mismatch, have %d, want %d", have, want) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,162 @@ | ||
// Copyright 2023 The bsc Authors | ||
// This file is part of bsc. | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"encoding/hex" | ||
"flag" | ||
"fmt" | ||
"os" | ||
"sort" | ||
"strings" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
"github.com/ethereum/go-ethereum/core/types" | ||
"github.com/ethereum/go-ethereum/rlp" | ||
"github.com/willf/bitset" | ||
) | ||
|
||
// follow define in parlia | ||
const ( | ||
AddressLength = 20 | ||
BLSPublicKeyLength = 48 | ||
|
||
// follow order in extra field | ||
// |---Extra Vanity---|---Validators Number and Validators Bytes (or Empty)---|---Vote Attestation (or Empty)---|---Extra Seal---| | ||
extraVanityLength = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity | ||
validatorNumberSize = 1 // Fixed number of extra prefix bytes reserved for validator number after Luban | ||
validatorBytesLength = common.AddressLength + types.BLSPublicKeyLength | ||
extraSealLength = 65 // Fixed number of extra-data suffix bytes reserved for signer seal | ||
) | ||
|
||
type Extra struct { | ||
ExtraVanity string | ||
ValidatorSize uint8 | ||
Validators validatorsAscending | ||
*types.VoteAttestation | ||
ExtraSeal []byte | ||
} | ||
|
||
type ValidatorInfo struct { | ||
common.Address | ||
types.BLSPublicKey | ||
VoteIncluded bool | ||
} | ||
|
||
// validatorsAscending implements the sort interface to allow sorting a list of ValidatorInfo | ||
type validatorsAscending []ValidatorInfo | ||
|
||
func (s validatorsAscending) Len() int { return len(s) } | ||
func (s validatorsAscending) Less(i, j int) bool { | ||
return bytes.Compare(s[i].Address[:], s[j].Address[:]) < 0 | ||
} | ||
func (s validatorsAscending) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | ||
|
||
func init() { | ||
flag.Usage = func() { | ||
fmt.Fprintln(os.Stderr, "Usage:", os.Args[0], "[extraHexData]") | ||
flag.PrintDefaults() | ||
fmt.Fprintln(os.Stderr, ` | ||
Dumps extra info from the given hex data, only support extra after luban upgrade.`) | ||
} | ||
} | ||
|
||
func main() { | ||
flag.Parse() | ||
extraHexData := os.Args[1] | ||
if extra, err := parseExtra(extraHexData); err == nil { | ||
fmt.Println("extra parsed successly") | ||
prettyExtra(*extra) | ||
} else { | ||
fmt.Println("extra parsed failed", "err", err) | ||
} | ||
} | ||
|
||
// parseExtra parse hex data into type Extra | ||
func parseExtra(hexData string) (*Extra, error) { | ||
// decode hex into bytes | ||
data, err := hex.DecodeString(strings.TrimPrefix(hexData, "0x")) | ||
if err != nil { | ||
return nil, fmt.Errorf("invalid hex data") | ||
} | ||
|
||
// parse ExtraVanity and ExtraSeal | ||
dataLength := len(data) | ||
var extra Extra | ||
if dataLength < extraVanityLength+extraSealLength { | ||
fmt.Println("length less than min required") | ||
} | ||
extra.ExtraVanity = string(data[:extraVanityLength]) | ||
extra.ExtraSeal = data[dataLength-extraSealLength:] | ||
data = data[extraVanityLength : dataLength-extraSealLength] | ||
dataLength = len(data) | ||
|
||
// parse Validators and Vote Attestation | ||
if dataLength > 0 { | ||
// parse Validators | ||
if data[0] != '\xf8' { // rlp format of attestation begin with 'f8' | ||
validatorNum := int(data[0]) | ||
validatorBytesTotalLength := validatorNumberSize + validatorNum*validatorBytesLength | ||
if dataLength < validatorBytesTotalLength { | ||
return nil, fmt.Errorf("parse validators failed") | ||
} | ||
extra.ValidatorSize = uint8(validatorNum) | ||
data = data[validatorNumberSize:] | ||
for i := 0; i < validatorNum; i++ { | ||
var validatorInfo ValidatorInfo | ||
validatorInfo.Address = common.BytesToAddress(data[i*validatorBytesLength : i*validatorBytesLength+common.AddressLength]) | ||
copy(validatorInfo.BLSPublicKey[:], data[i*validatorBytesLength+common.AddressLength:(i+1)*validatorBytesLength]) | ||
extra.Validators = append(extra.Validators, validatorInfo) | ||
} | ||
sort.Sort(extra.Validators) | ||
data = data[validatorBytesTotalLength-validatorNumberSize:] | ||
dataLength = len(data) | ||
} | ||
|
||
// parse Vote Attestation | ||
if dataLength > 0 { | ||
if err := rlp.Decode(bytes.NewReader(data), &extra.VoteAttestation); err != nil { | ||
return nil, fmt.Errorf("parse voteAttestation failed") | ||
} | ||
if extra.ValidatorSize > 0 { | ||
validatorsBitSet := bitset.From([]uint64{uint64(extra.VoteAddressSet)}) | ||
for i := 0; i < int(extra.ValidatorSize); i++ { | ||
if validatorsBitSet.Test(uint(i)) { | ||
extra.Validators[i].VoteIncluded = true | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
return &extra, nil | ||
} | ||
|
||
// prettyExtra print Extra with a pretty format | ||
func prettyExtra(extra Extra) { | ||
fmt.Printf("ExtraVanity : %s\n", extra.ExtraVanity) | ||
|
||
if extra.ValidatorSize > 0 { | ||
fmt.Printf("ValidatorSize : %d\n", extra.ValidatorSize) | ||
for i := 0; i < int(extra.ValidatorSize); i++ { | ||
fmt.Printf("Validator %d\n", i+1) | ||
fmt.Printf("\tAddress : %s\n", common.Bytes2Hex(extra.Validators[i].Address[:])) | ||
fmt.Printf("\tVoteKey : %s\n", common.Bytes2Hex(extra.Validators[i].BLSPublicKey[:])) | ||
fmt.Printf("\tVoteIncluded : %t\n", extra.Validators[i].VoteIncluded) | ||
} | ||
} | ||
|
||
if extra.VoteAttestation != nil { | ||
fmt.Printf("Attestation :\n") | ||
fmt.Printf("\tVoteAddressSet : %b, %d\n", extra.VoteAddressSet, bitset.From([]uint64{uint64(extra.VoteAddressSet)}).Count()) | ||
fmt.Printf("\tAggSignature : %s\n", common.Bytes2Hex(extra.AggSignature[:])) | ||
fmt.Printf("\tVoteData :\n") | ||
fmt.Printf("\t\tSourceNumber : %d\n", extra.Data.SourceNumber) | ||
fmt.Printf("\t\tSourceHash : %s\n", common.Bytes2Hex(extra.Data.SourceHash[:])) | ||
fmt.Printf("\t\tTargetNumber : %d\n", extra.Data.TargetNumber) | ||
fmt.Printf("\t\tTargetHash : %s\n", common.Bytes2Hex(extra.Data.TargetHash[:])) | ||
} | ||
|
||
fmt.Printf("ExtraSeal : %s\n", common.Bytes2Hex(extra.ExtraSeal)) | ||
} |