Compare commits

..

26 Commits

Author SHA1 Message Date
Rick975
d33ca4f108 initial version 2024-08-07 10:23:51 +08:00
zzzckck
b61128bd7b utils: add GetTopAddr to analyse large traffic (#2629) 2024-08-05 16:48:33 +08:00
buddho
df16ab95ab Makefile: use docker compose v2 instead of v1 (#2628) 2024-08-05 15:15:46 +08:00
Nathan
9e343669b5 core: not record zero hash beacon block root with Parlia engine (#2621) 2024-07-31 16:39:24 +08:00
Nathan
987b8c1504 consensus/parlia: exclude inturn validator when calculate backoffTime (#2618) 2024-07-31 16:37:50 +08:00
Nathan
7d907016ff tests: fix evm-test CI (#2622) 2024-07-31 15:50:43 +08:00
Satyajit Das
00cac12542 faucet: rate limit initial implementation (#2603) 2024-07-29 13:36:42 +08:00
Ethan
27f618f434 fix: update stakehub bytecode after zero address agent issue fixed (#2614) 2024-07-26 15:47:59 +08:00
irrun
46b88d11f9 fix: only take non-mempool tx to calculate bid price (#2579) 2024-07-26 09:49:16 +08:00
yuhangcangqian
f532da6ca0 chore: fix some comments (#2597)
Signed-off-by: yuhangcangqian <cuibuwei@qq.com>
2024-07-25 10:46:52 +08:00
zzzckck
c94fc290e7 Merge pull request #2612 from buddh0/merge_master_into_develop
Merge master into develop
2024-07-25 10:44:24 +08:00
buddho
7f3c5ce4cd cmd/utils: add new flag OverridePassedForkTime (#2611) 2024-07-25 10:43:32 +08:00
Nathan
313449404f consensus/parlia: modify mining time for last block in one turn (#2608) 2024-07-25 10:42:42 +08:00
buddh0
99e4e950f8 Merge branch 'master' into develop 2024-07-25 10:20:23 +08:00
Ethan
cabd0f8a21 feat: add bohr upgrade contracts bytecode (#2605)
* feat: add bohr upgrade contracts bytecode

* feat: add bohr upgrade contracts bytecode on rialto network

* feat: add protector for stakehub on rialto network
2024-07-24 10:29:01 +08:00
Nathan
17e0e45a09 BEP-341: Validators can produce consecutive blocks (#2482) 2024-07-23 13:55:45 +08:00
Chris Li
6260a26971 fix: prune-state when specify --triesInMemory 32 (#2602) 2024-07-23 10:06:19 +08:00
Nathan
a44b6d8067 core: cache block after wroten into db (#2600) 2024-07-22 20:52:07 +08:00
NathanBSC
c6cb43b7ca Revert "miner/worker: broadcast block immediately once sealed (#2576)"
This reverts commit 6d5b4ad64d.
2024-07-22 18:23:10 +08:00
NathanBSC
222e10810e core: cache block after wroten into db 2024-07-22 18:22:56 +08:00
zzzckck
26b236fb5f Merge pull request #2586 from bnb-chain/master_2_develop
Draft release v1.4.12
2024-07-17 17:45:39 +08:00
zzzckck
900cf26c65 Merge branch 'master' into master_2_develop 2024-07-17 17:29:11 +08:00
dependabot[bot]
75d162983a build(deps): bump github.com/hashicorp/go-retryablehttp (#2537)
Bumps [github.com/hashicorp/go-retryablehttp](https://github.com/hashicorp/go-retryablehttp) from 0.7.4 to 0.7.7.
- [Changelog](https://github.com/hashicorp/go-retryablehttp/blob/main/CHANGELOG.md)
- [Commits](https://github.com/hashicorp/go-retryablehttp/compare/v0.7.4...v0.7.7)

---
updated-dependencies:
- dependency-name: github.com/hashicorp/go-retryablehttp
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-28 13:51:53 +08:00
zoro
719412551a Merge pull request #2549 from bnb-chain/develop
release: prepare for v1.4.11
2024-06-27 17:37:26 +08:00
zzzckck
f0c7795542 Merge pull request #2527 from bnb-chain/develop
Draft release v1.4.10
2024-06-21 16:13:48 +08:00
zzzckck
4566ac7659 Merge pull request #2511 from bnb-chain/develop
Draft release v1.4.9
2024-06-11 11:51:22 +08:00
56 changed files with 1172 additions and 234 deletions

View File

@@ -29,11 +29,11 @@ truffle-test:
docker build . -f ./docker/Dockerfile --target bsc-genesis -t bsc-genesis
docker build . -f ./docker/Dockerfile --target bsc -t bsc
docker build . -f ./docker/Dockerfile.truffle -t truffle-test
docker-compose -f ./tests/truffle/docker-compose.yml up genesis
docker-compose -f ./tests/truffle/docker-compose.yml up -d bsc-rpc bsc-validator1
docker compose -f ./tests/truffle/docker-compose.yml up genesis
docker compose -f ./tests/truffle/docker-compose.yml up -d bsc-rpc bsc-validator1
sleep 30
docker-compose -f ./tests/truffle/docker-compose.yml up --exit-code-from truffle-test truffle-test
docker-compose -f ./tests/truffle/docker-compose.yml down
docker compose -f ./tests/truffle/docker-compose.yml up --exit-code-from truffle-test truffle-test
docker compose -f ./tests/truffle/docker-compose.yml down
#? lint: Run certain pre-selected linters
lint: ## Run linters.

View File

@@ -43,7 +43,42 @@ func TestExtraParse(t *testing.T) {
}
}
// case 3, |---Extra Vanity---|---Empty---|---Vote Attestation---|---Extra Seal---|
// case 3, |---Extra Vanity---|---Validators Number and Validators Bytes---|---Turn Length---|---Empty---|---Extra Seal---|
{
extraData := "0xd983010209846765746889676f312e31392e3131856c696e75780000a6bf97c1152465176c461afb316ebc773c61faee85a6515daa8a923564c6ffd37fb2fe9f118ef88092e8762c7addb526ab7eb1e772baef85181f892c731be0c1891a50e6b06262c816295e26495cef6f69dfa69911d9d8e4f3bbadb89b977cf58294f7239d515e15b24cfeb82494056cf691eaf729b165f32c9757c429dba5051155903067e56ebe3698678e912d4c407bbe49438ed859fe965b140dcf1aab71a993c1f7f6929d1fe2a17b4e14614ef9fc5bdc713d6631d675403fbeefac55611bf612700b1b65f4744861b80b0f7d6ab03f349bbafec1551819b8be1efea2fc46ca749aa184248a459464eec1a21e7fc7b71a053d9644e9bb8da4853b8f872cd7c1d6b324bf1922829830646ceadfb658d3de009a61dd481a114a2e761c554b641742c973867899d300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000069c77a677c40c7fbea129d4b171a39b7a8ddabfab2317f59d86abfaf690850223d90e9e7593d91a29331dfc2f84d5adecc75fc39ecab4632c1b4400a3dd1e1298835bcca70f657164e5b75689b64b7fd1fa275f334f28e1896a26afa1295da81418593bd12814463d9f6e45c36a0e47eb4cd3e5b6af29c41e2a3a5636430155a466e216585af3ba772b61c6014342d914470ec7ac2975be345796c2b81db0422a5fd08e40db1fc2368d2245e4b18b1d0b85c921aaaafd2e341760e29fc613edd39f71254614e2055c3287a517ae2f5b9e386cd1b50a4550696d957cb4900f03ab84f83ff2df44193496793b847f64e9d6db1b3953682bb95edd096eb1e69bbd357c200992ca78050d0cbe180cfaa018e8b6c8fd93d6f4cea42bbb345dbc6f0dfdb5bec73a8a257074e82b881cfa06ef3eb4efeca060c2531359abd0eab8af1e3edfa2025fca464ac9c3fd123f6c24a0d78869485a6f79b60359f141df90a0c745125b131caaffd12000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b218c5d6af1f979ac42bc68d98a5a0d796c6ab01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4dd66d7c2c7e57f628210187192fb89d4b99dd4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000be807dddb074639cd9fa61b47676c064fc50d62cb1f2c71577def3144fabeb75a8a1c8cb5b51d1d1b4a05eec67988b8685008baa17459ec425dbaebc852f496dc92196cdcc8e6d00c17eb431350c6c50d8b8f05176b90b11b3a3d4feb825ae9702711566df5dbf38e82add4dd1b573b95d2466fa6501ccb81e9d26a352b96150ccbf7b697fd0a419d1d6bf74282782b0b3eb1413c901d6ecf02e8e28000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e2d3a739effcd3a99387d015e260eefac72ebea1956c470ddff48cb49300200b5f83497f3a3ccb3aeb83c5edd9818569038e61d197184f4aa6939ea5e9911e3e98ac6d21e9ae3261a475a27bb1028f140bc2a7c843318afd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ea0a6e3c511bbd10f4519ece37dc24887e11b55db2d4c6283c44a1c7bd503aaba7666e9f0c830e0ff016c1c750a5e48757a713d0836b1cabfd5c281b1de3b77d1c192183ee226379db83cffc681495730c11fdde79ba4c0c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ef0274e31810c9df02f98fafde0f841f4e66a1cd00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004e99f701bb14cb7dfb68b90bd3e6d1ca656964630de71beffc7f33f7f08ec99d336ec51ad9fad0ac84ae77ca2e8ad9512acc56e0d7c93f3c2ce7de1b69149a5a400"
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)
}
}
{
var have = extra.TurnLength
var want = uint8(4)
if *have != want {
t.Fatalf("extra.TurnLength mismatch, have %d, want %d", *have, want)
}
}
}
// case 4, |---Extra Vanity---|---Empty---|---Vote Attestation---|---Extra Seal---|
{
extraData := "0xd883010205846765746888676f312e32302e35856c696e75780000002995c52af8b5830563efb86089cf168dcf4c5d3cb057926628ad1bf0f03ea67eef1458485578a4f8489afa8a853ecc7af45e2d145c21b70641c4b29f0febd2dd2c61fa1ba174be3fd47f1f5fa2ab9b5c318563d8b70ca58d0d51e79ee32b2fb721649e2cb9d36538361fba11f84c8401d14bb7a0fa67ddb3ba654d6006bf788710032247aa4d1be0707273e696b422b3ff72e9798401d14bbaa01225f505f5a0e1aefadcd2913b7aac9009fe4fb3d1bf57399e0b9dce5947f94280fe6d3647276c4127f437af59eb7c7985b2ae1ebe432619860695cb6106b80cc66c735bc1709afd11f233a2c97409d38ebaf7178aa53e895aea2fe0a229f71ec601"
extra, err := parseExtra(extraData)
@@ -64,9 +99,9 @@ func TestExtraParse(t *testing.T) {
}
}
// case 4, |---Extra Vanity---|---Validators Number and Validators Bytes---|---Vote Attestation---|---Extra Seal---|
// case 5, |---Extra Vanity---|---Validators Number and Validators Bytes---|---Vote Attestation---|---Extra Seal---|
{
extraData := "0xd883010209846765746888676f312e31392e38856c696e7578000000dc55905c071284214b9b9c85549ab3d2b972df0deef66ac2c98e82934ca974fdcd97f3309de967d3c9c43fa711a8d673af5d75465844bf8969c8d1948d903748ac7b8b1720fa64e50c35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f247788386d0ed6c748e03a53160b4b30ed3748cc5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b878f8b27bb8608c11016739b3f8a19e54ab8c7abacd936cfeba200f3645a98b65adb0dd3692b69ce0b3ae10e7176b9a4b0d83f04065b1042b4bcb646a34b75c550f92fc34b8b2b1db0fa0d3172db23ba92727c80bcd306320d0ff411bf858525fde13bc8e0370f84c8401e9c2e6a0820dc11d63176a0eb1b828bc5376867b275579112b7013358da40317e7bab6e98401e9c2e7a00edc71ce80105a3220a87bea2792fa340d66c59002f02b0a09349ed1ed284070808b972fac2b9077a4dcb6fc37093799a652858016c99142b227500c844fa97ec22e3f9d3b1e982f14bcd999a7453e89ce5ef5c55f1c7f8f74ba904186cd67828200"
extraData := "0xd883010209846765746888676f312e31392e38856c696e7578000000dc55905c071284214b9b9c85549ab3d2b972df0deef66ac2c98e82934ca974fdcd97f3309de967d3c9c43fa711a8d673af5d75465844bf8969c8d1948d903748ac7b8b1720fa64e50c35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f247788386d0ed6c748e03a53160b4b30ed3748cc5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b878f8b27bb8608c11016739b3f8a19e54ab8c7abacd936cfeba200f3645a98b65adb0dd3692b69ce0b3ae10e7176b9a4b0d83f04065b1042b4bcb646a34b75c550f92fc34b8b2b1db0fa0d3172db23ba92727c80bcd306320d0ff411bf858525fde13bc8e0370f84c8401e9c2e6a0820dc11d63176a0eb1b828bc5376867b275579112b7013358da40317e7bab6e98401e9c2e7a00edc71ce80105a3220a87bea2792fa340d66c59002f02b0a09349ed1ed28407080048b972fac2b9077a4dcb6fc37093799a652858016c99142b227500c844fa97ec22e3f9d3b1e982f14bcd999a7453e89ce5ef5c55f1c7f8f74ba904186cd67828200"
extra, err := parseExtra(extraData)
assert.NoError(t, err)
{
@@ -105,4 +140,53 @@ func TestExtraParse(t *testing.T) {
}
}
}
// case 6, |---Extra Vanity---|---Validators Number and Validators Bytes---|---Turn Length---|---Vote Attestation---|---Extra Seal---|
{
extraData := "0xd883010209846765746888676f312e31392e38856c696e7578000000dc55905c071284214b9b9c85549ab3d2b972df0deef66ac2c98e82934ca974fdcd97f3309de967d3c9c43fa711a8d673af5d75465844bf8969c8d1948d903748ac7b8b1720fa64e50c35552c16704d214347f29fa77f77da6d75d7c752b742ad4855bae330426b823e742da31f816cc83bc16d69a9134be0cfb4a1d17ec34f1b5b32d5c20440b8536b1e88f0f247788386d0ed6c748e03a53160b4b30ed3748cc5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000980a75ecd1309ea12fa2ed87a8744fbfc9b863d589037a9ace3b590165ea1c0c5ac72bf600b7c88c1e435f41932c1132aae1bfa0bb68e46b96ccb12c3415e4d82af717d8a2959d3f95eae5dc7d70144ce1b73b403b7eb6e0b973c2d38487e58fd6e145491b110080fb14ac915a0411fc78f19e09a399ddee0d20c63a75d8f930f1694544ad2dc01bb71b214cb885500844365e95cd9942c7276e7fd8a2750ec6dded3dcdc2f351782310b0eadc077db59abca0f0cd26776e2e7acb9f3bce40b1fa5221fd1561226c6263cc5ff474cf03cceff28abc65c9cbae594f725c80e12d96c9b86c3400e529bfe184056e257c07940bb664636f689e8d2027c834681f8f878b73445261034e946bb2d901b4b87804f8b27bb8608c11016739b3f8a19e54ab8c7abacd936cfeba200f3645a98b65adb0dd3692b69ce0b3ae10e7176b9a4b0d83f04065b1042b4bcb646a34b75c550f92fc34b8b2b1db0fa0d3172db23ba92727c80bcd306320d0ff411bf858525fde13bc8e0370f84c8401e9c2e6a0820dc11d63176a0eb1b828bc5376867b275579112b7013358da40317e7bab6e98401e9c2e7a00edc71ce80105a3220a87bea2792fa340d66c59002f02b0a09349ed1ed28407080048b972fac2b9077a4dcb6fc37093799a652858016c99142b227500c844fa97ec22e3f9d3b1e982f14bcd999a7453e89ce5ef5c55f1c7f8f74ba904186cd67828200"
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)
}
}
{
var have = extra.TurnLength
var want = uint8(4)
if *have != want {
t.Fatalf("extra.TurnLength mismatch, have %d, want %d", *have, want)
}
}
}
}

View File

@@ -24,7 +24,7 @@ const (
BLSPublicKeyLength = 48
// follow order in extra field
// |---Extra Vanity---|---Validators Number and Validators Bytes (or Empty)---|---Vote Attestation (or Empty)---|---Extra Seal---|
// |---Extra Vanity---|---Validators Number and Validators Bytes (or Empty)---|---Turn Length (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
@@ -35,6 +35,7 @@ type Extra struct {
ExtraVanity string
ValidatorSize uint8
Validators validatorsAscending
TurnLength *uint8
*types.VoteAttestation
ExtraSeal []byte
}
@@ -113,6 +114,15 @@ func parseExtra(hexData string) (*Extra, error) {
sort.Sort(extra.Validators)
data = data[validatorBytesTotalLength-validatorNumberSize:]
dataLength = len(data)
// parse TurnLength
if dataLength > 0 {
if data[0] != '\xf8' {
extra.TurnLength = &data[0]
data = data[1:]
dataLength = len(data)
}
}
}
// parse Vote Attestation
@@ -148,6 +158,10 @@ func prettyExtra(extra Extra) {
}
}
if extra.TurnLength != nil {
fmt.Printf("TurnLength : %d\n", *extra.TurnLength)
}
if extra.VoteAttestation != nil {
fmt.Printf("Attestation :\n")
fmt.Printf("\tVoteAddressSet : %b, %d\n", extra.VoteAddressSet, bitset.From([]uint64{uint64(extra.VoteAddressSet)}).Count())

View File

@@ -62,6 +62,7 @@ var (
ArgsUsage: "<genesisPath>",
Flags: flags.Merge([]cli.Flag{
utils.CachePreimagesFlag,
utils.OverridePassedForkTime,
utils.OverrideBohr,
utils.OverrideVerkle,
utils.MultiDataBaseFlag,
@@ -253,6 +254,10 @@ func initGenesis(ctx *cli.Context) error {
defer stack.Close()
var overrides core.ChainOverrides
if ctx.IsSet(utils.OverridePassedForkTime.Name) {
v := ctx.Uint64(utils.OverridePassedForkTime.Name)
overrides.OverridePassedForkTime = &v
}
if ctx.IsSet(utils.OverrideBohr.Name) {
v := ctx.Uint64(utils.OverrideBohr.Name)
overrides.OverrideBohr = &v

View File

@@ -185,6 +185,10 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
params.RialtoGenesisHash = common.HexToHash(v)
}
if ctx.IsSet(utils.OverridePassedForkTime.Name) {
v := ctx.Uint64(utils.OverridePassedForkTime.Name)
cfg.Eth.OverridePassedForkTime = &v
}
if ctx.IsSet(utils.OverrideBohr.Name) {
v := ctx.Uint64(utils.OverrideBohr.Name)
cfg.Eth.OverrideBohr = &v
@@ -206,6 +210,9 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
if ctx.IsSet(utils.OverrideBreatheBlockInterval.Name) {
params.BreatheBlockInterval = ctx.Uint64(utils.OverrideBreatheBlockInterval.Name)
}
if ctx.IsSet(utils.OverrideFixedTurnLength.Name) {
params.FixedTurnLength = ctx.Uint64(utils.OverrideFixedTurnLength.Name)
}
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)

View File

@@ -72,12 +72,14 @@ var (
utils.USBFlag,
utils.SmartCardDaemonPathFlag,
utils.RialtoHash,
utils.OverridePassedForkTime,
utils.OverrideBohr,
utils.OverrideVerkle,
utils.OverrideFullImmutabilityThreshold,
utils.OverrideMinBlocksForBlobRequests,
utils.OverrideDefaultExtraReserveForBlobRequests,
utils.OverrideBreatheBlockInterval,
utils.OverrideFixedTurnLength,
utils.EnablePersonal,
utils.TxPoolLocalsFlag,
utils.TxPoolNoLocalsFlag,

View File

@@ -13,6 +13,8 @@ const main = async () => {
let gasUsedTotal = 0;
let inturnBlocks = 0;
let justifiedBlocks = 0;
let turnLength = await provider.send("parlia_getTurnLength", [
ethers.toQuantity(program.startNum)]);
for (let i = program.startNum; i < program.endNum; i++) {
let txCount = await provider.send("eth_getBlockTransactionCountByNumber", [
ethers.toQuantity(i)]);
@@ -35,7 +37,7 @@ const main = async () => {
} else {
console.log("justified unexpected", "BlockNumber =", i,"justifiedNumber",justifiedNumber)
}
console.log("BlockNumber =", i, "mod =", i%4, "miner =", header.miner , "difficulty =", difficulty, "txCount =", ethers.toNumber(txCount), "gasUsed", gasUsed, "timestamp", timestamp)
console.log("BlockNumber =", i, "mod =", i%turnLength, "miner =", header.miner , "difficulty =", difficulty, "txCount =", ethers.toNumber(txCount), "gasUsed", gasUsed, "timestamp", timestamp)
}
let blockCount = program.endNum - program.startNum

View File

@@ -0,0 +1,164 @@
import { ethers } from "ethers";
import program from "commander";
// Global Options:
program.option("--rpc <rpc>", "Rpc");
// GetTxCount Options:
program.option("--startNum <startNum>", "start num")
program.option("--endNum <endNum>", "end num")
program.option("--miner <miner>", "miner", "")
// GetVersion Options:
program.option("--num <Num>", "validator num", 21)
// GetTopAddr Options:
program.option("--topNum <Num>", "top num of address to be displayed", 20)
program.parse(process.argv);
const provider = new ethers.JsonRpcProvider(program.rpc)
function printUsage() {
console.log("Usage:");
console.log(" node getchainstatus.js --help");
console.log(" node getchainstatus.js [subcommand] [options]");
console.log("\nSubcommands:");
console.log(" GetTxCount: find the block with max tx size of a range");
console.log(" GetVersion: dump validators' binary version, based on Header.Extra");
console.log(" GetTopAddr: get hottest $topNum target address within a block range");
console.log("\nOptions:");
console.log(" --rpc specify the url of RPC endpoint");
console.log(" --startNum the start block number, for command GetTxCount");
console.log(" --endNum the end block number, for command GetTxCount");
console.log(" --miner the miner address, for command GetTxCount");
console.log(" --num the number of blocks to be checked, for command GetVersion");
console.log(" --topNum the topNum of blocks to be checked, for command GetVersion");
console.log("\nExample:");
// mainnet https://bsc-mainnet.nodereal.io/v1/454e504917db4f82b756bd0cf6317dce
console.log(" node getchainstatus.js GetTxCount --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000005")
console.log(" node getchainstatus.js GetVersion --rpc https://bsc-testnet-dataseed.bnbchain.org --num 21")
console.log(" node getchainstatus.js GetTopAddr --rpc https://bsc-testnet-dataseed.bnbchain.org --startNum 40000001 --endNum 40000010 --topNum 10")
}
// 1.cmd: "GetTxCount", usage:
// node getchainstatus.js GetTxCount --rpc https://bsc-testnet-dataseed.bnbchain.org \
// --startNum 40000001 --endNum 40000005 \
// --miner(optional): specified: find the max txCounter from the specified validator,
// not specified: find the max txCounter from all validators
async function getTxCount() {
let txCount = 0;
let num = 0;
console.log("Find the max txs count between", program.startNum, "and", program.endNum);
for (let i = program.startNum; i < program.endNum; i++) {
if (program.miner !== "") {
let blockData = await provider.getBlock(Number(i))
if (program.miner !== blockData.miner) {
continue
}
}
let x = await provider.send("eth_getBlockTransactionCountByNumber", [
ethers.toQuantity(i)]);
let a = ethers.toNumber(x)
if (a > txCount) {
num = i;
txCount = a;
}
}
console.log("BlockNum = ", num, "TxCount =", txCount);
}
// 2.cmd: "GetVersion", usage:
// node getchainstatus.js GetVersion \
// --rpc https://bsc-testnet-dataseed.bnbchain.org \
// --num(optional): defualt 21, the number of blocks that will be checked
async function getBinaryVersion() {
const blockNum = await provider.getBlockNumber();
console.log(blockNum);
for (let i = 0; i < program.num; i++) {
let blockData = await provider.getBlock(blockNum - i);
// 1.get Geth client version
let major = ethers.toNumber(ethers.dataSlice(blockData.extraData, 2, 3))
let minor = ethers.toNumber(ethers.dataSlice(blockData.extraData, 3, 4))
let patch = ethers.toNumber(ethers.dataSlice(blockData.extraData, 4, 5))
// 2.get minimum txGasPrice based on the last non-zero-gasprice transaction
let lastGasPrice = 0
for (let txIndex = blockData.transactions.length - 1; txIndex >= 0; txIndex--) {
let txHash = blockData.transactions[txIndex]
let txData = await provider.getTransaction(txHash);
if (txData.gasPrice == 0) {
continue
}
lastGasPrice = txData.gasPrice
break
}
console.log(blockData.miner, "version =", major + "." + minor + "." + patch, " MinGasPrice = " + lastGasPrice)
}
};
// 3.cmd: "GetTopAddr", usage:
// node getchainstatus.js GetTopAddr \
// --rpc https://bsc-testnet-dataseed.bnbchain.org \
// --startNum 40000001 --endNum 40000005 \
// --topNum(optional): the top num of address to be displayed, default 20
function getTopKElements(map, k) {
let entries = Array.from(map.entries());
entries.sort((a, b) => b[1] - a[1]);
return entries.slice(0, k);
}
async function getTopAddr() {
let countMap = new Map();
let totalTxs = 0
console.log("Find the top target address, between", program.startNum, "and", program.endNum);
for (let i = program.startNum; i <= program.endNum; i++) {
let blockData = await provider.getBlock(Number(i), true)
totalTxs += blockData.transactions.length
for (let txIndex = blockData.transactions.length - 1; txIndex >= 0; txIndex--) {
let txData = await blockData.getTransaction(txIndex)
if (txData.to == null) {
console.log("Contract creation,txHash:", txData.hash)
continue
}
let toAddr = txData.to;
if (countMap.has(toAddr)) {
countMap.set(toAddr, countMap.get(toAddr) + 1);
} else {
countMap.set(toAddr, 1);
}
}
console.log("progress:", (program.endNum-i), "blocks left", "totalTxs", totalTxs)
}
let tops = getTopKElements(countMap, program.topNum)
tops.forEach((value, key) => {
// value: [ '0x40661F989826CC641Ce1601526Bb16a4221412c8', 71 ]
console.log(key+":", value[0], " ", value[1], " ", ((value[1]*100)/totalTxs).toFixed(2)+"%");
});
};
const main = async () => {
if (process.argv.length <= 2) {
console.error('invalid process.argv.length', process.argv.length);
printUsage()
return
}
const cmd = process.argv[2]
if (cmd === "--help") {
printUsage()
return
}
if (cmd === "GetTxCount") {
await getTxCount()
} else if (cmd === "GetVersion") {
await getBinaryVersion()
} else if (cmd === "GetTopAddr") {
await getTopAddr()
} else {
console.log("unsupported cmd", cmd);
printUsage()
}
}
main().then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

View File

@@ -1,41 +0,0 @@
import { ethers } from "ethers";
import program from "commander";
program.option("--rpc <rpc>", "Rpc");
program.option("--startNum <startNum>", "start num")
program.option("--endNum <endNum>", "end num")
// --miner:
// specified: find the max txCounter from the specified validator
// not specified: find the max txCounter from all validators
program.option("--miner <miner>", "miner", "")
program.parse(process.argv);
const provider = new ethers.JsonRpcProvider(program.rpc)
const main = async () => {
let txCount = 0;
let num = 0;
console.log("Find the max txs count between", program.startNum, "and", program.endNum);
for (let i = program.startNum; i < program.endNum; i++) {
if (program.miner !== "") {
let blockData = await provider.getBlock(Number(i))
if (program.miner !== blockData.miner) {
continue
}
}
let x = await provider.send("eth_getBlockTransactionCountByNumber", [
ethers.toQuantity(i)]);
let a = ethers.toNumber(x)
if (a > txCount) {
num = i;
txCount = a;
}
}
console.log("BlockNum = ", num, "TxCount =", txCount);
};
main().then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

View File

@@ -1,38 +0,0 @@
import { ethers } from "ethers";
import program from "commander";
program.option("--Rpc <Rpc>", "Rpc");
program.option("--Num <Num>", "validator num", 21)
program.parse(process.argv);
const provider = new ethers.JsonRpcProvider(program.Rpc);
const main = async () => {
const blockNum = await provider.getBlockNumber();
console.log(blockNum);
for (let i = 0; i < program.Num; i++) {
let blockData = await provider.getBlock(blockNum - i);
// 1.get Geth client version
let major = ethers.toNumber(ethers.dataSlice(blockData.extraData, 2, 3))
let minor = ethers.toNumber(ethers.dataSlice(blockData.extraData, 3, 4))
let patch = ethers.toNumber(ethers.dataSlice(blockData.extraData, 4, 5))
// 2.get minimum txGasPrice based on the last non-zero-gasprice transaction
let lastGasPrice = 0
for (let txIndex = blockData.transactions.length - 1; txIndex >= 0; txIndex--) {
let txHash = blockData.transactions[txIndex]
let txData = await provider.getTransaction(txHash);
if (txData.gasPrice == 0) {
continue
}
lastGasPrice = txData.gasPrice
break
}
console.log(blockData.miner, "version =", major + "." + minor + "." + patch, " MinGasPrice = " + lastGasPrice)
}
};
main().then(() => process.exit(0))
.catch((error) => {
console.error(error);
process.exit(1);
});

View File

@@ -305,6 +305,11 @@ var (
Usage: "Manually specify the Rialto Genesis Hash, to trigger builtin network logic",
Category: flags.EthCategory,
}
OverridePassedForkTime = &cli.Uint64Flag{
Name: "override.passedforktime",
Usage: "Manually specify the hard fork timestamp except the last one, overriding the bundled setting",
Category: flags.EthCategory,
}
OverrideBohr = &cli.Uint64Flag{
Name: "override.bohr",
Usage: "Manually specify the Bohr fork timestamp, overriding the bundled setting",
@@ -339,6 +344,12 @@ var (
Value: params.BreatheBlockInterval,
Category: flags.EthCategory,
}
OverrideFixedTurnLength = &cli.Uint64Flag{
Name: "override.fixedturnlength",
Usage: "It use fixed or random values for turn length instead of reading from the contract, only for testing purpose",
Value: params.FixedTurnLength,
Category: flags.EthCategory,
}
SyncModeFlag = &flags.TextMarshalerFlag{
Name: "syncmode",
Usage: `Blockchain sync mode ("snap" or "full")`,

View File

@@ -2306,6 +2306,19 @@ const validatorSetABI = `
],
"stateMutability": "view"
},
{
"inputs": [],
"name": "getTurnLength",
"outputs": [
{
"internalType": "uint256",
"name": "",
"type": "uint256"
}
],
"stateMutability": "view",
"type": "function"
},
{
"type": "function",
"name": "getValidators",

View File

@@ -88,6 +88,19 @@ func (api *API) GetJustifiedNumber(number *rpc.BlockNumber) (uint64, error) {
return snap.Attestation.TargetNumber, nil
}
func (api *API) GetTurnLength(number *rpc.BlockNumber) (uint8, error) {
header := api.getHeader(number)
// Ensure we have an actually valid block and return the validators from its snapshot
if header == nil {
return 0, errUnknownBlock
}
snap, err := api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
if err != nil || snap.TurnLength == 0 {
return 0, err
}
return snap.TurnLength, nil
}
func (api *API) GetFinalizedNumber(number *rpc.BlockNumber) (uint64, error) {
header := api.getHeader(number)
// Ensure we have an actually valid block and return the validators from its snapshot

View File

@@ -0,0 +1,91 @@
package parlia
import (
"context"
"errors"
"math/big"
mrand "math/rand"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/systemcontracts"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
)
func (p *Parlia) getTurnLength(chain consensus.ChainHeaderReader, header *types.Header) (*uint8, error) {
parent := chain.GetHeaderByHash(header.ParentHash)
if parent == nil {
return nil, errors.New("parent not found")
}
var turnLength uint8
if p.chainConfig.IsBohr(parent.Number, parent.Time) {
turnLengthFromContract, err := p.getTurnLengthFromContract(parent)
if err != nil {
return nil, err
}
if turnLengthFromContract == nil {
return nil, errors.New("unexpected error when getTurnLengthFromContract")
}
turnLength = uint8(turnLengthFromContract.Int64())
} else {
turnLength = defaultTurnLength
}
log.Debug("getTurnLength", "turnLength", turnLength)
return &turnLength, nil
}
func (p *Parlia) getTurnLengthFromContract(header *types.Header) (turnLength *big.Int, err error) {
// mock to get turnLength from the contract
if params.FixedTurnLength >= 1 && params.FixedTurnLength <= 9 {
if params.FixedTurnLength == 2 {
return p.getRandTurnLength(header)
}
return big.NewInt(int64(params.FixedTurnLength)), nil
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
method := "getTurnLength"
toAddress := common.HexToAddress(systemcontracts.ValidatorContract)
gas := (hexutil.Uint64)(uint64(math.MaxUint64 / 2))
data, err := p.validatorSetABI.Pack(method)
if err != nil {
log.Error("Unable to pack tx for getTurnLength", "error", err)
return nil, err
}
msgData := (hexutil.Bytes)(data)
blockNr := rpc.BlockNumberOrHashWithHash(header.Hash(), false)
result, err := p.ethAPI.Call(ctx, ethapi.TransactionArgs{
Gas: &gas,
To: &toAddress,
Data: &msgData,
}, &blockNr, nil, nil)
if err != nil {
return nil, err
}
if err := p.validatorSetABI.UnpackIntoInterface(&turnLength, method, result); err != nil {
return nil, err
}
return turnLength, nil
}
// getRandTurnLength returns a random valid value, used to test switching turn length
func (p *Parlia) getRandTurnLength(header *types.Header) (turnLength *big.Int, err error) {
turnLengths := [8]uint8{1, 3, 4, 5, 6, 7, 8, 9}
r := mrand.New(mrand.NewSource(int64(header.Time)))
lengthIndex := int(r.Int31n(int32(len(turnLengths))))
return big.NewInt(int64(turnLengths[lengthIndex])), nil
}

View File

@@ -55,10 +55,12 @@ const (
checkpointInterval = 1024 // Number of blocks after which to save the snapshot to the database
defaultEpochLength = uint64(100) // Default number of blocks of checkpoint to update validatorSet from contract
defaultTurnLength = uint8(1) // Default consecutive number of blocks a validator receives priority for block production
extraVanity = 32 // Fixed number of extra-data prefix bytes reserved for signer vanity
extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
nextForkHashSize = 4 // Fixed number of extra-data suffix bytes reserved for nextForkHash.
turnLengthSize = 1 // Fixed number of extra-data suffix bytes reserved for turnLength
validatorBytesLengthBeforeLuban = common.AddressLength
validatorBytesLength = common.AddressLength + types.BLSPublicKeyLength
@@ -127,6 +129,10 @@ var (
// invalid list of validators (i.e. non divisible by 20 bytes).
errInvalidSpanValidators = errors.New("invalid validator list on sprint end block")
// errInvalidTurnLength is returned if a block contains an
// invalid length of turn (i.e. no data left after parsing validators).
errInvalidTurnLength = errors.New("invalid turnLength")
// errInvalidMixDigest is returned if a block's mix digest is non-zero.
errInvalidMixDigest = errors.New("non-zero mix digest")
@@ -137,6 +143,10 @@ var (
// list of validators different than the one the local node calculated.
errMismatchingEpochValidators = errors.New("mismatching validator list on epoch block")
// errMismatchingEpochTurnLength is returned if a sprint block contains a
// turn length different than the one the local node calculated.
errMismatchingEpochTurnLength = errors.New("mismatching turn length on epoch block")
// errInvalidDifficulty is returned if the difficulty of a block is missing.
errInvalidDifficulty = errors.New("invalid difficulty")
@@ -370,6 +380,7 @@ func (p *Parlia) VerifyHeaders(chain consensus.ChainHeaderReader, headers []*typ
// On luban fork, we introduce vote attestation into the header's extra field, so extra format is different from before.
// Before luban fork: |---Extra Vanity---|---Validators Bytes (or Empty)---|---Extra Seal---|
// After luban fork: |---Extra Vanity---|---Validators Number and Validators Bytes (or Empty)---|---Vote Attestation (or Empty)---|---Extra Seal---|
// After bohr fork: |---Extra Vanity---|---Validators Number and Validators Bytes (or Empty)---|---Turn Length (or Empty)---|---Vote Attestation (or Empty)---|---Extra Seal---|
func getValidatorBytesFromHeader(header *types.Header, chainConfig *params.ChainConfig, parliaConfig *params.ParliaConfig) []byte {
if len(header.Extra) <= extraVanity+extraSeal {
return nil
@@ -386,11 +397,15 @@ func getValidatorBytesFromHeader(header *types.Header, chainConfig *params.Chain
return nil
}
num := int(header.Extra[extraVanity])
if num == 0 || len(header.Extra) <= extraVanity+extraSeal+num*validatorBytesLength {
return nil
}
start := extraVanity + validatorNumberSize
end := start + num*validatorBytesLength
extraMinLen := end + extraSeal
if chainConfig.IsBohr(header.Number, header.Time) {
extraMinLen += turnLengthSize
}
if num == 0 || len(header.Extra) < extraMinLen {
return nil
}
return header.Extra[start:end]
}
@@ -409,11 +424,14 @@ func getVoteAttestationFromHeader(header *types.Header, chainConfig *params.Chai
attestationBytes = header.Extra[extraVanity : len(header.Extra)-extraSeal]
} else {
num := int(header.Extra[extraVanity])
if len(header.Extra) <= extraVanity+extraSeal+validatorNumberSize+num*validatorBytesLength {
start := extraVanity + validatorNumberSize + num*validatorBytesLength
if chainConfig.IsBohr(header.Number, header.Time) {
start += turnLengthSize
}
end := len(header.Extra) - extraSeal
if end <= start {
return nil, nil
}
start := extraVanity + validatorNumberSize + num*validatorBytesLength
end := len(header.Extra) - extraSeal
attestationBytes = header.Extra[start:end]
}
@@ -896,6 +914,24 @@ func (p *Parlia) prepareValidators(header *types.Header) error {
return nil
}
func (p *Parlia) prepareTurnLength(chain consensus.ChainHeaderReader, header *types.Header) error {
if header.Number.Uint64()%p.config.Epoch != 0 ||
!p.chainConfig.IsBohr(header.Number, header.Time) {
return nil
}
turnLength, err := p.getTurnLength(chain, header)
if err != nil {
return err
}
if turnLength != nil {
header.Extra = append(header.Extra, *turnLength)
}
return nil
}
func (p *Parlia) assembleVoteAttestation(chain consensus.ChainHeaderReader, header *types.Header) error {
if !p.chainConfig.IsLuban(header.Number) || header.Number.Uint64() < 2 {
return nil
@@ -1027,6 +1063,9 @@ func (p *Parlia) Prepare(chain consensus.ChainHeaderReader, header *types.Header
return err
}
if err := p.prepareTurnLength(chain, header); err != nil {
return err
}
// add extra seal space
header.Extra = append(header.Extra, make([]byte, extraSeal)...)
@@ -1077,6 +1116,30 @@ func (p *Parlia) verifyValidators(header *types.Header) error {
return nil
}
func (p *Parlia) verifyTurnLength(chain consensus.ChainHeaderReader, header *types.Header) error {
if header.Number.Uint64()%p.config.Epoch != 0 ||
!p.chainConfig.IsBohr(header.Number, header.Time) {
return nil
}
turnLengthFromHeader, err := parseTurnLength(header, p.chainConfig, p.config)
if err != nil {
return err
}
if turnLengthFromHeader != nil {
turnLength, err := p.getTurnLength(chain, header)
if err != nil {
return err
}
if turnLength != nil && *turnLength == *turnLengthFromHeader {
log.Debug("verifyTurnLength", "turnLength", *turnLength)
return nil
}
}
return errMismatchingEpochTurnLength
}
func (p *Parlia) distributeFinalityReward(chain consensus.ChainHeaderReader, state *state.StateDB, header *types.Header,
cx core.ChainContext, txs *[]*types.Transaction, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction,
usedGas *uint64, mining bool) error {
@@ -1171,6 +1234,10 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
return err
}
if err := p.verifyTurnLength(chain, header); err != nil {
return err
}
cx := chainContext{Chain: chain, parlia: p}
parent := chain.GetHeaderByHash(header.ParentHash)
@@ -1197,7 +1264,7 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
}
}
if header.Difficulty.Cmp(diffInTurn) != 0 {
spoiledVal := snap.supposeValidator()
spoiledVal := snap.inturnValidator()
signedRecently := false
if p.chainConfig.IsPlato(header.Number) {
signedRecently = snap.SignRecently(spoiledVal)
@@ -1288,7 +1355,7 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
if err != nil {
return nil, nil, err
}
spoiledVal := snap.supposeValidator()
spoiledVal := snap.inturnValidator()
signedRecently := false
if p.chainConfig.IsPlato(header.Number) {
signedRecently = snap.SignRecently(spoiledVal)
@@ -1441,10 +1508,13 @@ func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header, leftOv
delay = delay - *leftOver
}
// The blocking time should be no more than half of period
half := time.Duration(p.config.Period) * time.Second / 2
if delay > half {
delay = half
// The blocking time should be no more than half of period when snap.TurnLength == 1
timeForMining := time.Duration(p.config.Period) * time.Second / 2
if !snap.lastBlockInOneTurn(header.Number.Uint64()) {
timeForMining = time.Duration(p.config.Period) * time.Second * 2 / 3
}
if delay > timeForMining {
delay = timeForMining
}
return &delay
}
@@ -1936,42 +2006,40 @@ func (p *Parlia) GetFinalizedHeader(chain consensus.ChainHeaderReader, header *t
// =========================== utility function ==========================
func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Address) uint64 {
if snap.inturn(val) {
log.Debug("backOffTime", "blockNumber", header.Number, "in turn validator", val)
return 0
} else {
delay := initialBackOffTime
validators := snap.validators()
if p.chainConfig.IsPlanck(header.Number) {
// reverse the key/value of snap.Recents to get recentsMap
recentsMap := make(map[common.Address]uint64, len(snap.Recents))
bound := uint64(0)
if n, limit := header.Number.Uint64(), uint64(len(validators)/2+1); n > limit {
bound = n - limit
}
for seen, recent := range snap.Recents {
if seen <= bound {
continue
}
recentsMap[recent] = seen
counts := snap.countRecents()
for addr, seenTimes := range counts {
log.Debug("backOffTime", "blockNumber", header.Number, "validator", addr, "seenTimes", seenTimes)
}
// The backOffTime does not matter when a validator has signed recently.
if _, ok := recentsMap[val]; ok {
if snap.signRecentlyByCounts(val, counts) {
return 0
}
inTurnAddr := validators[(snap.Number+1)%uint64(len(validators))]
if _, ok := recentsMap[inTurnAddr]; ok {
inTurnAddr := snap.inturnValidator()
if snap.signRecentlyByCounts(inTurnAddr, counts) {
log.Debug("in turn validator has recently signed, skip initialBackOffTime",
"inTurnAddr", inTurnAddr)
delay = 0
}
// Exclude the recently signed validators
// Exclude the recently signed validators and the in turn validator
temp := make([]common.Address, 0, len(validators))
for _, addr := range validators {
if _, ok := recentsMap[addr]; ok {
if snap.signRecentlyByCounts(addr, counts) {
continue
}
if p.chainConfig.IsBohr(header.Number, header.Time) {
if addr == inTurnAddr {
continue
}
}
temp = append(temp, addr)
}
validators = temp
@@ -1989,7 +2057,11 @@ func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Ad
return 0
}
s := rand.NewSource(int64(snap.Number))
randSeed := snap.Number
if p.chainConfig.IsBohr(header.Number, header.Time) {
randSeed = header.Number.Uint64() / uint64(snap.TurnLength)
}
s := rand.NewSource(int64(randSeed))
r := rand.New(s)
n := len(validators)
backOffSteps := make([]uint64, 0, n)

View File

@@ -22,22 +22,44 @@ func TestImpactOfValidatorOutOfService(t *testing.T) {
testCases := []struct {
totalValidators int
downValidators int
turnLength int
}{
{3, 1},
{5, 2},
{10, 1},
{10, 4},
{21, 1},
{21, 3},
{21, 5},
{21, 10},
{3, 1, 1},
{5, 2, 1},
{10, 1, 2},
{10, 4, 2},
{21, 1, 3},
{21, 3, 3},
{21, 5, 4},
{21, 10, 5},
}
for _, tc := range testCases {
simulateValidatorOutOfService(tc.totalValidators, tc.downValidators)
simulateValidatorOutOfService(tc.totalValidators, tc.downValidators, tc.turnLength)
}
}
func simulateValidatorOutOfService(totalValidators int, downValidators int) {
// refer Snapshot.SignRecently
func signRecently(idx int, recents map[uint64]int, turnLength int) bool {
recentSignTimes := 0
for _, signIdx := range recents {
if signIdx == idx {
recentSignTimes += 1
}
}
return recentSignTimes >= turnLength
}
// refer Snapshot.minerHistoryCheckLen
func minerHistoryCheckLen(totalValidators int, turnLength int) uint64 {
return uint64(totalValidators/2+1)*uint64(turnLength) - 1
}
// refer Snapshot.inturnValidator
func inturnValidator(totalValidators int, turnLength int, height int) int {
return height / turnLength % totalValidators
}
func simulateValidatorOutOfService(totalValidators int, downValidators int, turnLength int) {
downBlocks := 10000
recoverBlocks := 10000
recents := make(map[uint64]int)
@@ -55,12 +77,7 @@ func simulateValidatorOutOfService(totalValidators int, downValidators int) {
delete(validators, down[i])
}
isRecentSign := func(idx int) bool {
for _, signIdx := range recents {
if signIdx == idx {
return true
}
}
return false
return signRecently(idx, recents, turnLength)
}
isInService := func(idx int) bool {
return validators[idx]
@@ -68,10 +85,10 @@ func simulateValidatorOutOfService(totalValidators int, downValidators int) {
downDelay := uint64(0)
for h := 1; h <= downBlocks; h++ {
if limit := uint64(totalValidators/2 + 1); uint64(h) >= limit {
if limit := minerHistoryCheckLen(totalValidators, turnLength) + 1; uint64(h) >= limit {
delete(recents, uint64(h)-limit)
}
proposer := h % totalValidators
proposer := inturnValidator(totalValidators, turnLength, h)
if !isInService(proposer) || isRecentSign(proposer) {
candidates := make(map[int]bool, totalValidators/2)
for v := range validators {
@@ -99,10 +116,10 @@ func simulateValidatorOutOfService(totalValidators int, downValidators int) {
recoverDelay := uint64(0)
lastseen := downBlocks
for h := downBlocks + 1; h <= downBlocks+recoverBlocks; h++ {
if limit := uint64(totalValidators/2 + 1); uint64(h) >= limit {
if limit := minerHistoryCheckLen(totalValidators, turnLength) + 1; uint64(h) >= limit {
delete(recents, uint64(h)-limit)
}
proposer := h % totalValidators
proposer := inturnValidator(totalValidators, turnLength, h)
if !isInService(proposer) || isRecentSign(proposer) {
lastseen = h
candidates := make(map[int]bool, totalValidators/2)

View File

@@ -44,6 +44,7 @@ type Snapshot struct {
Number uint64 `json:"number"` // Block number where the snapshot was created
Hash common.Hash `json:"hash"` // Block hash where the snapshot was created
TurnLength uint8 `json:"turn_length"` // Length of `turn`, meaning the consecutive number of blocks a validator receives priority for block production
Validators map[common.Address]*ValidatorInfo `json:"validators"` // Set of authorized validators at this moment
Recents map[uint64]common.Address `json:"recents"` // Set of recent validators for spam protections
RecentForkHashes map[uint64]string `json:"recent_fork_hashes"` // Set of recent forkHash
@@ -73,6 +74,7 @@ func newSnapshot(
sigCache: sigCache,
Number: number,
Hash: hash,
TurnLength: defaultTurnLength,
Recents: make(map[uint64]common.Address),
RecentForkHashes: make(map[uint64]string),
Validators: make(map[common.Address]*ValidatorInfo),
@@ -115,6 +117,10 @@ func loadSnapshot(config *params.ParliaConfig, sigCache *lru.ARCCache, db ethdb.
if err := json.Unmarshal(blob, snap); err != nil {
return nil, err
}
if snap.TurnLength == 0 { // no TurnLength field in old snapshots
snap.TurnLength = defaultTurnLength
}
snap.config = config
snap.sigCache = sigCache
snap.ethAPI = ethAPI
@@ -139,6 +145,7 @@ func (s *Snapshot) copy() *Snapshot {
sigCache: s.sigCache,
Number: s.Number,
Hash: s.Hash,
TurnLength: s.TurnLength,
Validators: make(map[common.Address]*ValidatorInfo),
Recents: make(map[uint64]common.Address),
RecentForkHashes: make(map[uint64]string),
@@ -211,17 +218,45 @@ func (s *Snapshot) updateAttestation(header *types.Header, chainConfig *params.C
}
}
func (s *Snapshot) SignRecently(validator common.Address) bool {
for seen, recent := range s.Recents {
if recent == validator {
if limit := uint64(len(s.Validators)/2 + 1); s.Number+1 < limit || seen > s.Number+1-limit {
return true
}
}
func (s *Snapshot) versionHistoryCheckLen() uint64 {
return uint64(len(s.Validators)) * uint64(s.TurnLength)
}
func (s *Snapshot) minerHistoryCheckLen() uint64 {
return (uint64(len(s.Validators))/2+1)*uint64(s.TurnLength) - 1
}
func (s *Snapshot) countRecents() map[common.Address]uint8 {
leftHistoryBound := uint64(0) // the bound is excluded
checkHistoryLength := s.minerHistoryCheckLen()
if s.Number > checkHistoryLength {
leftHistoryBound = s.Number - checkHistoryLength
}
counts := make(map[common.Address]uint8, len(s.Validators))
for seen, recent := range s.Recents {
if seen <= leftHistoryBound || recent == (common.Address{}) /*when seen == `epochKey`*/ {
continue
}
counts[recent] += 1
}
return counts
}
func (s *Snapshot) signRecentlyByCounts(validator common.Address, counts map[common.Address]uint8) bool {
if seenTimes, ok := counts[validator]; ok && seenTimes >= s.TurnLength {
if seenTimes > s.TurnLength {
log.Warn("produce more blocks than expected!", "validator", validator, "seenTimes", seenTimes)
}
return true
}
return false
}
func (s *Snapshot) SignRecently(validator common.Address) bool {
return s.signRecentlyByCounts(validator, s.countRecents())
}
func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderReader, parents []*types.Header, chainConfig *params.ChainConfig) (*Snapshot, error) {
// Allow passing in no headers for cleaner code
if len(headers) == 0 {
@@ -248,10 +283,10 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
for _, header := range headers {
number := header.Number.Uint64()
// Delete the oldest validator from the recent list to allow it signing again
if limit := uint64(len(snap.Validators)/2 + 1); number >= limit {
if limit := snap.minerHistoryCheckLen() + 1; number >= limit {
delete(snap.Recents, number-limit)
}
if limit := uint64(len(snap.Validators)); number >= limit {
if limit := snap.versionHistoryCheckLen(); number >= limit {
delete(snap.RecentForkHashes, number-limit)
}
// Resolve the authorization key and check against signers
@@ -262,16 +297,22 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
if _, ok := snap.Validators[validator]; !ok {
return nil, errUnauthorizedValidator(validator.String())
}
for _, recent := range snap.Recents {
if recent == validator {
if chainConfig.IsBohr(header.Number, header.Time) {
if snap.SignRecently(validator) {
return nil, errRecentlySigned
}
} else {
for _, recent := range snap.Recents {
if recent == validator {
return nil, errRecentlySigned
}
}
}
snap.Recents[number] = validator
snap.RecentForkHashes[number] = hex.EncodeToString(header.Extra[extraVanity-nextForkHashSize : extraVanity])
snap.updateAttestation(header, chainConfig, s.config)
// change validator set
if number > 0 && number%s.config.Epoch == uint64(len(snap.Validators)/2) {
if number > 0 && number%s.config.Epoch == snap.minerHistoryCheckLen() {
epochKey := math.MaxUint64 - header.Number.Uint64()/s.config.Epoch // impossible used as a block number
if chainConfig.IsBohr(header.Number, header.Time) {
// after switching the validator set, snap.Validators may become larger,
@@ -281,11 +322,22 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
}
}
checkpointHeader := FindAncientHeader(header, uint64(len(snap.Validators)/2), chain, parents)
checkpointHeader := FindAncientHeader(header, snap.minerHistoryCheckLen(), chain, parents)
if checkpointHeader == nil {
return nil, consensus.ErrUnknownAncestor
}
oldVersionsLen := snap.versionHistoryCheckLen()
// get turnLength from headers and use that for new turnLength
turnLength, err := parseTurnLength(checkpointHeader, chainConfig, s.config)
if err != nil {
return nil, err
}
if turnLength != nil {
snap.TurnLength = *turnLength
log.Debug("validator set switch", "turnLength", *turnLength)
}
// get validators from headers and use that for new validator set
newValArr, voteAddrs, err := parseValidators(checkpointHeader, chainConfig, s.config)
if err != nil {
@@ -315,13 +367,6 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
}
}
}
oldLimit := len(snap.Validators)
newLimit := len(newVals)
if newLimit < oldLimit {
for i := 0; i < oldLimit-newLimit; i++ {
delete(snap.RecentForkHashes, number-uint64(newLimit)-uint64(i))
}
}
snap.Validators = newVals
if chainConfig.IsLuban(header.Number) {
validators := snap.validators()
@@ -329,6 +374,9 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
snap.Validators[val].Index = idx + 1 // offset by 1
}
}
for i := snap.versionHistoryCheckLen(); i < oldVersionsLen; i++ {
delete(snap.RecentForkHashes, number-i)
}
}
}
snap.Number += uint64(len(headers))
@@ -346,17 +394,20 @@ func (s *Snapshot) validators() []common.Address {
return validators
}
// inturn returns if a validator at a given block height is in-turn or not.
func (s *Snapshot) inturn(validator common.Address) bool {
validators := s.validators()
offset := (s.Number + 1) % uint64(len(validators))
return validators[offset] == validator
// lastBlockInOneTurn returns if the block at height `blockNumber` is the last block in current turn.
func (s *Snapshot) lastBlockInOneTurn(blockNumber uint64) bool {
return (blockNumber+1)%uint64(s.TurnLength) == 0
}
// inturnValidator returns the validator at a given block height.
// inturn returns if a validator at a given block height is in-turn or not.
func (s *Snapshot) inturn(validator common.Address) bool {
return s.inturnValidator() == validator
}
// inturnValidator returns the validator for the following block height.
func (s *Snapshot) inturnValidator() common.Address {
validators := s.validators()
offset := (s.Number + 1) % uint64(len(validators))
offset := (s.Number + 1) / uint64(s.TurnLength) % uint64(len(validators))
return validators[offset]
}
@@ -394,12 +445,6 @@ func (s *Snapshot) indexOfVal(validator common.Address) int {
return -1
}
func (s *Snapshot) supposeValidator() common.Address {
validators := s.validators()
index := (s.Number + 1) % uint64(len(validators))
return validators[index]
}
func parseValidators(header *types.Header, chainConfig *params.ChainConfig, parliaConfig *params.ParliaConfig) ([]common.Address, []types.BLSPublicKey, error) {
validatorsBytes := getValidatorBytesFromHeader(header, chainConfig, parliaConfig)
if len(validatorsBytes) == 0 {
@@ -425,6 +470,24 @@ func parseValidators(header *types.Header, chainConfig *params.ChainConfig, parl
return cnsAddrs, voteAddrs, nil
}
func parseTurnLength(header *types.Header, chainConfig *params.ChainConfig, parliaConfig *params.ParliaConfig) (*uint8, error) {
if header.Number.Uint64()%parliaConfig.Epoch != 0 ||
!chainConfig.IsBohr(header.Number, header.Time) {
return nil, nil
}
if len(header.Extra) <= extraVanity+extraSeal {
return nil, errInvalidSpanValidators
}
num := int(header.Extra[extraVanity])
pos := extraVanity + validatorNumberSize + num*validatorBytesLength
if len(header.Extra) <= pos {
return nil, errInvalidTurnLength
}
turnLength := header.Extra[pos]
return &turnLength, nil
}
func FindAncientHeader(header *types.Header, ite uint64, chain consensus.ChainHeaderReader, candidateParents []*types.Header) *types.Header {
ancient := header
for i := uint64(1); i <= ite; i++ {

View File

@@ -20,6 +20,7 @@ package core
import (
"errors"
"fmt"
"github.com/ethereum/go-ethereum/triedb/versadb"
"io"
"math/big"
"runtime"
@@ -196,6 +197,11 @@ func (c *CacheConfig) triedbConfig() *triedb.Config {
JournalFile: c.JournalFile,
}
}
if c.StateScheme == rawdb.VersaScheme {
config.VersaDB = &versadb.Config{
CleanCacheSize: c.TrieCleanLimit * 1024 * 1024,
}
}
return config
}
@@ -1393,7 +1399,7 @@ func (bc *BlockChain) Stop() {
if !bc.cacheConfig.TrieDirtyDisabled {
triedb := bc.triedb
var once sync.Once
for _, offset := range []uint64{0, 1, TriesInMemory - 1} {
for _, offset := range []uint64{0, 1, bc.TriesInMemory() - 1} {
if number := bc.CurrentBlock().Number.Uint64(); number > offset {
recent := bc.GetBlockByNumber(number - offset)
log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root())
@@ -1801,6 +1807,12 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
if err := blockBatch.Write(); err != nil {
log.Crit("Failed to write block into disk", "err", err)
}
bc.hc.tdCache.Add(block.Hash(), externTd)
bc.blockCache.Add(block.Hash(), block)
bc.receiptsCache.Add(block.Hash(), receipts)
if bc.chainConfig.IsCancun(block.Number(), block.Time()) {
bc.sidecarsCache.Add(block.Hash(), block.Sidecars())
}
wg.Done()
}()
@@ -1825,7 +1837,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
// Flush limits are not considered for the first TriesInMemory blocks.
current := block.NumberU64()
if current <= TriesInMemory {
if current <= bc.TriesInMemory() {
return nil
}
// If we exceeded our memory allowance, flush matured singleton nodes to disk
@@ -1911,18 +1923,18 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
// WriteBlockAndSetHead writes the given block and all associated state to the database,
// and applies the block as the new chain head.
func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool, mux *event.TypeMux) (status WriteStatus, err error) {
func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
if !bc.chainmu.TryLock() {
return NonStatTy, errChainStopped
}
defer bc.chainmu.Unlock()
return bc.writeBlockAndSetHead(block, receipts, logs, state, emitHeadEvent, mux)
return bc.writeBlockAndSetHead(block, receipts, logs, state, emitHeadEvent)
}
// writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead.
// This function expects the chain mutex to be held.
func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool, mux *event.TypeMux) (status WriteStatus, err error) {
func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types.Receipt, logs []*types.Log, state *state.StateDB, emitHeadEvent bool) (status WriteStatus, err error) {
currentBlock := bc.CurrentBlock()
reorg, err := bc.forker.ReorgNeededWithFastFinality(currentBlock, block.Header())
if err != nil {
@@ -1931,9 +1943,6 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
if reorg {
bc.highestVerifiedBlock.Store(types.CopyHeader(block.Header()))
bc.highestVerifiedBlockFeed.Send(HighestVerifiedBlockEvent{Header: block.Header()})
if mux != nil {
mux.Post(NewSealedBlockEvent{Block: block})
}
}
if err := bc.writeBlockWithState(block, receipts, state); err != nil {
@@ -2311,7 +2320,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
// Don't set the head, only insert the block
err = bc.writeBlockWithState(block, receipts, statedb)
} else {
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false, nil)
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
}
if err != nil {
return it.index, err

View File

@@ -27,10 +27,7 @@ type NewTxsEvent struct{ Txs []*types.Transaction }
// ReannoTxsEvent is posted when a batch of local pending transactions exceed a specified duration.
type ReannoTxsEvent struct{ Txs []*types.Transaction }
// NewSealedBlockEvent is posted when a block has been sealed.
type NewSealedBlockEvent struct{ Block *types.Block }
// NewMinedBlockEvent is posted when a block has been mined.
// NewMinedBlockEvent is posted when a block has been imported.
type NewMinedBlockEvent struct{ Block *types.Block }
// RemovedLogsEvent is posted when a reorg happens

View File

@@ -216,8 +216,9 @@ func (e *GenesisMismatchError) Error() string {
// ChainOverrides contains the changes to chain config
// Typically, these modifications involve hardforks that are not enabled on the BSC mainnet, intended for testing purposes.
type ChainOverrides struct {
OverrideBohr *uint64
OverrideVerkle *uint64
OverridePassedForkTime *uint64
OverrideBohr *uint64
OverrideVerkle *uint64
}
// SetupGenesisBlock writes or updates the genesis block in db.
@@ -243,6 +244,15 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
}
applyOverrides := func(config *params.ChainConfig) {
if config != nil {
if overrides != nil && overrides.OverridePassedForkTime != nil {
config.ShanghaiTime = overrides.OverridePassedForkTime
config.KeplerTime = overrides.OverridePassedForkTime
config.FeynmanTime = overrides.OverridePassedForkTime
config.FeynmanFixTime = overrides.OverridePassedForkTime
config.CancunTime = overrides.OverridePassedForkTime
config.HaberTime = overrides.OverridePassedForkTime
config.HaberFixTime = overrides.OverridePassedForkTime
}
if overrides != nil && overrides.OverrideBohr != nil {
config.BohrTime = overrides.OverrideBohr
}

View File

@@ -46,6 +46,8 @@ const HashScheme = "hash"
// on extra state diffs to survive deep reorg.
const PathScheme = "path"
const VersaScheme = "versa"
// hasher is used to compute the sha256 hash of the provided data.
type hasher struct{ sha crypto.KeccakState }

View File

@@ -195,6 +195,10 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
if db.triedb.IsVerkle() {
return trie.NewVerkleTrie(root, db.triedb, utils.NewPointCache(commitmentCacheItems))
}
// TODO, trie handler instead of tree pointer
if db.triedb.IsVersionedState() {
return trie.NewVersionTrie(root, db.triedb)
}
tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb)
if err != nil {
return nil, err
@@ -214,6 +218,10 @@ func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre
if db.triedb.IsVerkle() {
return self, nil
}
// TODO
if db.triedb.IsVersionedState() {
return trie.NewVersionTrie(root, db.triedb)
}
tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, crypto.Keccak256Hash(address.Bytes()), root), db.triedb)
if err != nil {
return nil, err

View File

@@ -231,6 +231,13 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
// contract. This method is exported to be used in tests.
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
// Return immediately if beaconRoot equals the zero hash when using the Parlia engine.
if beaconRoot == (common.Hash{}) {
if chainConfig := vmenv.ChainConfig(); chainConfig != nil && chainConfig.Parlia != nil {
return
}
}
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
// the new root
msg := &Message{

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,27 @@
package bohr
import _ "embed"
// contract codes for Mainnet upgrade
var (
//go:embed mainnet/ValidatorContract
MainnetValidatorContract string
//go:embed mainnet/StakeHubContract
MainnetStakeHubContract string
)
// contract codes for Chapel upgrade
var (
//go:embed chapel/ValidatorContract
ChapelValidatorContract string
//go:embed chapel/StakeHubContract
ChapelStakeHubContract string
)
// contract codes for Rialto upgrade
var (
//go:embed rialto/ValidatorContract
RialtoValidatorContract string
//go:embed rialto/StakeHubContract
RialtoStakeHubContract string
)

View File

@@ -8,6 +8,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/systemcontracts/bohr"
"github.com/ethereum/go-ethereum/core/systemcontracts/bruno"
"github.com/ethereum/go-ethereum/core/systemcontracts/euler"
"github.com/ethereum/go-ethereum/core/systemcontracts/feynman"
@@ -78,6 +79,8 @@ var (
feynmanFixUpgrade = make(map[string]*Upgrade)
haberFixUpgrade = make(map[string]*Upgrade)
bohrUpgrade = make(map[string]*Upgrade)
)
func init() {
@@ -736,6 +739,54 @@ func init() {
},
},
}
bohrUpgrade[mainNet] = &Upgrade{
UpgradeName: "bohr",
Configs: []*UpgradeConfig{
{
ContractAddr: common.HexToAddress(ValidatorContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/398c9364aad5261c1ecd90ac3ab2df89b65c45e3",
Code: bohr.MainnetValidatorContract,
},
{
ContractAddr: common.HexToAddress(StakeHubContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/398c9364aad5261c1ecd90ac3ab2df89b65c45e3",
Code: bohr.MainnetStakeHubContract,
},
},
}
bohrUpgrade[chapelNet] = &Upgrade{
UpgradeName: "bohr",
Configs: []*UpgradeConfig{
{
ContractAddr: common.HexToAddress(ValidatorContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/398c9364aad5261c1ecd90ac3ab2df89b65c45e3",
Code: bohr.ChapelValidatorContract,
},
{
ContractAddr: common.HexToAddress(StakeHubContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/398c9364aad5261c1ecd90ac3ab2df89b65c45e3",
Code: bohr.ChapelStakeHubContract,
},
},
}
bohrUpgrade[rialtoNet] = &Upgrade{
UpgradeName: "bohr",
Configs: []*UpgradeConfig{
{
ContractAddr: common.HexToAddress(ValidatorContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/398c9364aad5261c1ecd90ac3ab2df89b65c45e3",
Code: bohr.RialtoValidatorContract,
},
{
ContractAddr: common.HexToAddress(StakeHubContract),
CommitUrl: "https://github.com/bnb-chain/bsc-genesis-contract/commit/398c9364aad5261c1ecd90ac3ab2df89b65c45e3",
Code: bohr.RialtoStakeHubContract,
},
},
}
}
func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.Int, lastBlockTime uint64, blockTime uint64, statedb *state.StateDB) {
@@ -816,6 +867,10 @@ func UpgradeBuildInSystemContract(config *params.ChainConfig, blockNumber *big.I
applySystemContractUpgrade(haberFixUpgrade[network], blockNumber, statedb, logger)
}
if config.IsOnBohr(blockNumber, lastBlockTime, blockTime) {
applySystemContractUpgrade(bohrUpgrade[network], blockNumber, statedb, logger)
}
/*
apply other upgrades
*/

View File

@@ -3,6 +3,7 @@ package vote
import (
"bytes"
"fmt"
"math/big"
"sync"
"time"
@@ -19,7 +20,13 @@ import (
const blocksNumberSinceMining = 5 // the number of blocks need to wait before voting, counting from the validator begin to mine
var diffInTurn = big.NewInt(2) // Block difficulty for in-turn signatures
var votesManagerCounter = metrics.NewRegisteredCounter("votesManager/local", nil)
var notJustified = metrics.NewRegisteredCounter("votesManager/notJustified", nil)
var inTurnJustified = metrics.NewRegisteredCounter("votesManager/inTurnJustified", nil)
var notInTurnJustified = metrics.NewRegisteredCounter("votesManager/notInTurnJustified", nil)
var continuousJustified = metrics.NewRegisteredCounter("votesManager/continuousJustified", nil)
var notContinuousJustified = metrics.NewRegisteredCounter("votesManager/notContinuousJustified", nil)
// Backend wraps all methods required for voting.
type Backend interface {
@@ -155,7 +162,7 @@ func (voteManager *VoteManager) loop() {
func(bLSPublicKey *types.BLSPublicKey) bool {
return bytes.Equal(voteManager.signer.PubKey[:], bLSPublicKey[:])
}) {
log.Debug("cur validator is not within the validatorSet at curHead")
log.Debug("local validator with voteKey is not within the validatorSet at curHead")
continue
}
@@ -202,6 +209,36 @@ func (voteManager *VoteManager) loop() {
voteManager.pool.PutVote(voteMessage)
votesManagerCounter.Inc(1)
}
// check the latest justified block, which indicating the stability of the network
curJustifiedNumber, _, err := voteManager.engine.GetJustifiedNumberAndHash(voteManager.chain, []*types.Header{curHead})
if err == nil && curJustifiedNumber != 0 {
if curJustifiedNumber+1 != curHead.Number.Uint64() {
log.Debug("not justified", "blockNumber", curHead.Number.Uint64()-1)
notJustified.Inc(1)
} else {
parent := voteManager.chain.GetHeaderByHash(curHead.ParentHash)
if parent != nil {
if parent.Difficulty.Cmp(diffInTurn) == 0 {
inTurnJustified.Inc(1)
} else {
log.Debug("not in turn block justified", "blockNumber", parent.Number.Int64(), "blockHash", parent.Hash())
notInTurnJustified.Inc(1)
}
lastJustifiedNumber, _, err := voteManager.engine.GetJustifiedNumberAndHash(voteManager.chain, []*types.Header{parent})
if err == nil {
if lastJustifiedNumber == 0 || lastJustifiedNumber+1 == curJustifiedNumber {
continuousJustified.Inc(1)
} else {
log.Debug("not continuous block justified", "lastJustified", lastJustifiedNumber, "curJustified", curJustifiedNumber)
notContinuousJustified.Inc(1)
}
}
}
}
}
case event := <-voteManager.syncVoteCh:
voteMessage := event.Vote
if voteManager.eth.IsMining() || !bytes.Equal(voteManager.signer.PubKey[:], voteMessage.VoteAddress[:]) {

View File

@@ -26,6 +26,7 @@ import (
"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/parlia"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/bloombits"
"github.com/ethereum/go-ethereum/core/rawdb"
@@ -440,6 +441,16 @@ func (b *EthAPIBackend) Engine() consensus.Engine {
return b.eth.engine
}
func (b *EthAPIBackend) CurrentTurnLength() (turnLength uint8, err error) {
if p, ok := b.eth.engine.(*parlia.Parlia); ok {
service := p.APIs(b.Chain())[0].Service
currentHead := rpc.LatestBlockNumber
return service.(*parlia.API).GetTurnLength(&currentHead)
}
return 1, nil
}
func (b *EthAPIBackend) CurrentHeader() *types.Header {
return b.eth.blockchain.CurrentHeader()
}

View File

@@ -185,6 +185,16 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
}
// Override the chain config with provided settings.
var overrides core.ChainOverrides
if config.OverridePassedForkTime != nil {
chainConfig.ShanghaiTime = config.OverridePassedForkTime
chainConfig.KeplerTime = config.OverridePassedForkTime
chainConfig.FeynmanTime = config.OverridePassedForkTime
chainConfig.FeynmanFixTime = config.OverridePassedForkTime
chainConfig.CancunTime = config.OverridePassedForkTime
chainConfig.HaberTime = config.OverridePassedForkTime
chainConfig.HaberFixTime = config.OverridePassedForkTime
overrides.OverridePassedForkTime = config.OverridePassedForkTime
}
if config.OverrideBohr != nil {
chainConfig.BohrTime = config.OverrideBohr
overrides.OverrideBohr = config.OverrideBohr

View File

@@ -188,6 +188,9 @@ type Config struct {
// send-transaction variants. The unit is ether.
RPCTxFeeCap float64
// OverridePassedForkTime
OverridePassedForkTime *uint64 `toml:",omitempty"`
// OverrideBohr (TODO: remove after the fork)
OverrideBohr *uint64 `toml:",omitempty"`

View File

@@ -70,6 +70,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
RPCGasCap uint64
RPCEVMTimeout time.Duration
RPCTxFeeCap float64
OverridePassedForkTime *uint64 `toml:",omitempty"`
OverrideBohr *uint64 `toml:",omitempty"`
OverrideVerkle *uint64 `toml:",omitempty"`
BlobExtraReserve uint64
@@ -128,6 +129,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.RPCGasCap = c.RPCGasCap
enc.RPCEVMTimeout = c.RPCEVMTimeout
enc.RPCTxFeeCap = c.RPCTxFeeCap
enc.OverridePassedForkTime = c.OverridePassedForkTime
enc.OverrideBohr = c.OverrideBohr
enc.OverrideVerkle = c.OverrideVerkle
enc.BlobExtraReserve = c.BlobExtraReserve
@@ -190,6 +192,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
RPCGasCap *uint64
RPCEVMTimeout *time.Duration
RPCTxFeeCap *float64
OverridePassedForkTime *uint64 `toml:",omitempty"`
OverrideBohr *uint64 `toml:",omitempty"`
OverrideVerkle *uint64 `toml:",omitempty"`
BlobExtraReserve *uint64
@@ -357,6 +360,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
if dec.RPCTxFeeCap != nil {
c.RPCTxFeeCap = *dec.RPCTxFeeCap
}
if dec.OverridePassedForkTime != nil {
c.OverridePassedForkTime = dec.OverridePassedForkTime
}
if dec.OverrideBohr != nil {
c.OverrideBohr = dec.OverrideBohr
}

View File

@@ -436,7 +436,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
}
}
// TestLogFilterUninstall tests invalid getLogs requests
// TestInvalidGetLogsRequest tests invalid getLogs requests
func TestInvalidGetLogsRequest(t *testing.T) {
t.Parallel()

View File

@@ -729,7 +729,7 @@ func (h *handler) Start(maxPeers int, maxPeersPerIP int) {
// broadcast mined blocks
h.wg.Add(1)
h.minedBlockSub = h.eventMux.Subscribe(core.NewMinedBlockEvent{}, core.NewSealedBlockEvent{})
h.minedBlockSub = h.eventMux.Subscribe(core.NewMinedBlockEvent{})
go h.minedBroadcastLoop()
// start sync handlers
@@ -946,9 +946,8 @@ func (h *handler) minedBroadcastLoop() {
if obj == nil {
continue
}
if ev, ok := obj.Data.(core.NewSealedBlockEvent); ok {
h.BroadcastBlock(ev.Block, true) // Propagate block to peers
} else if ev, ok := obj.Data.(core.NewMinedBlockEvent); ok {
if ev, ok := obj.Data.(core.NewMinedBlockEvent); ok {
h.BroadcastBlock(ev.Block, true) // First propagate block to peers
h.BroadcastBlock(ev.Block, false) // Only then announce to the rest
}
case <-h.stopCh:

View File

@@ -136,7 +136,7 @@ func (p *Peer) dispatchRequest(req *Request) error {
}
}
// dispatchRequest fulfils a pending request and delivers it to the requested
// dispatchResponse fulfils a pending request and delivers it to the requested
// sink.
func (p *Peer) dispatchResponse(res *Response, metadata func() interface{}) error {
resOp := &response{

View File

@@ -361,7 +361,7 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
return json.tx, err
}
// TransactionInBlock returns a single transaction at index in the given block.
// TransactionsInBlock returns a single transaction at index in the given block.
func (ec *Client) TransactionsInBlock(ctx context.Context, number *big.Int) ([]*types.Transaction, error) {
var rpcTxs []*rpcTransaction
err := ec.c.CallContext(ctx, &rpcTxs, "eth_getTransactionsByBlockNumber", toBlockNumArg(number))
@@ -376,7 +376,7 @@ func (ec *Client) TransactionsInBlock(ctx context.Context, number *big.Int) ([]*
return txs, err
}
// TransactionInBlock returns a single transaction at index in the given block.
// TransactionRecipientsInBlock returns a single transaction at index in the given block.
func (ec *Client) TransactionRecipientsInBlock(ctx context.Context, number *big.Int) ([]*types.Receipt, error) {
var rs []*types.Receipt
err := ec.c.CallContext(ctx, &rs, "eth_getTransactionReceiptsByBlockNumber", toBlockNumArg(number))

6
go.mod
View File

@@ -24,7 +24,7 @@ require (
github.com/deckarep/golang-set/v2 v2.5.0
github.com/dop251/goja v0.0.0-20230806174421-c933cf95e127
github.com/ethereum/c-kzg-4844 v0.4.0
github.com/fatih/color v1.14.1
github.com/fatih/color v1.16.0
github.com/fatih/structs v1.1.0
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
github.com/fjl/memsize v0.0.2
@@ -82,7 +82,7 @@ require (
golang.org/x/crypto v0.21.0
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
golang.org/x/sync v0.6.0
golang.org/x/sys v0.18.0
golang.org/x/sys v0.20.0
golang.org/x/text v0.14.0
golang.org/x/time v0.5.0
golang.org/x/tools v0.18.0
@@ -159,7 +159,7 @@ require (
github.com/grpc-ecosystem/grpc-gateway/v2 v2.0.1 // indirect
github.com/gtank/merlin v0.1.1 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.4 // indirect
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.5 // indirect
github.com/herumi/bls-eth-go-binary v0.0.0-20210917013441-d37c07cfda4e // indirect
github.com/influxdata/line-protocol v0.0.0-20210311194329-9aa0e372d097 // indirect

18
go.sum
View File

@@ -326,8 +326,9 @@ github.com/ethereum/c-kzg-4844 v0.4.0 h1:3MS1s4JtA868KpJxroZoepdV0ZKBp3u/O5HcZ7R
github.com/ethereum/c-kzg-4844 v0.4.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w=
github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/ferranbt/fastssz v0.0.0-20210120143747-11b9eff30ea9/go.mod h1:DyEu2iuLBnb/T51BlsiO3yLYdJC6UbGMrIkqK1KmQxM=
@@ -580,14 +581,13 @@ github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
github.com/hashicorp/go-hclog v1.2.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-retryablehttp v0.7.4 h1:ZQgVdpTdAL7WpMIwLzCfbalOcSUdkDZnpUv3/+BxzFA=
github.com/hashicorp/go-retryablehttp v0.7.4/go.mod h1:Jy/gPYAdjqffZ/yFGCFV2doI5wjtH1ewM9u8iYVjtX8=
github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
@@ -1503,8 +1503,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=

View File

@@ -870,7 +870,10 @@ func (s *BlockChainAPI) GetFinalizedHeader(ctx context.Context, probabilisticFin
return nil, fmt.Errorf("%d out of range [2,21]", probabilisticFinalized)
}
var err error
currentTurnLength, err := s.b.CurrentTurnLength()
if err != nil { // impossible
return nil, err
}
fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
if err != nil { // impossible
return nil, err
@@ -879,7 +882,7 @@ func (s *BlockChainAPI) GetFinalizedHeader(ctx context.Context, probabilisticFin
if err != nil { // impossible
return nil, err
}
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), latestHeader.Number.Int64()-probabilisticFinalized)
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), latestHeader.Number.Int64()-probabilisticFinalized*int64(currentTurnLength))
return s.GetHeaderByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber))
}
@@ -894,7 +897,10 @@ func (s *BlockChainAPI) GetFinalizedBlock(ctx context.Context, probabilisticFina
return nil, fmt.Errorf("%d out of range [2,21]", probabilisticFinalized)
}
var err error
currentTurnLength, err := s.b.CurrentTurnLength()
if err != nil { // impossible
return nil, err
}
fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
if err != nil { // impossible
return nil, err
@@ -903,7 +909,7 @@ func (s *BlockChainAPI) GetFinalizedBlock(ctx context.Context, probabilisticFina
if err != nil { // impossible
return nil, err
}
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), latestHeader.Number.Int64()-probabilisticFinalized)
finalizedBlockNumber := max(fastFinalizedHeader.Number.Int64(), latestHeader.Number.Int64()-probabilisticFinalized*int64(currentTurnLength))
return s.GetBlockByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber), fullTx)
}

View File

@@ -631,8 +631,9 @@ func (b testBackend) TxPoolContentFrom(addr common.Address) ([]*types.Transactio
func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.Subscription {
panic("implement me")
}
func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() }
func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() }
func (b testBackend) CurrentTurnLength() (uint8, error) { return 1, nil }
func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) {
panic("implement me")
}

View File

@@ -89,6 +89,8 @@ type Backend interface {
ChainConfig() *params.ChainConfig
Engine() consensus.Engine
// CurrentTurnLength return the turnLength at the latest block
CurrentTurnLength() (uint8, error)
// This is copied from filters.Backend
// eth/filters needs to be initialized from this backend type, so methods needed by

View File

@@ -416,6 +416,8 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent)
func (b *backendMock) Engine() consensus.Engine { return nil }
func (b *backendMock) CurrentTurnLength() (uint8, error) { return 1, nil }
func (b *backendMock) MevRunning() bool { return false }
func (b *backendMock) HasBuilder(builder common.Address) bool { return false }
func (b *backendMock) MevParams() *types.MevParams {

View File

@@ -18,6 +18,7 @@ import (
"github.com/ethereum/go-ethereum/common/bidutil"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
@@ -82,6 +83,7 @@ type bidSimulator struct {
delayLeftOver time.Duration
minGasPrice *big.Int
chain *core.BlockChain
txpool *txpool.TxPool
chainConfig *params.ChainConfig
engine consensus.Engine
bidWorker bidWorker
@@ -118,7 +120,7 @@ func newBidSimulator(
config *MevConfig,
delayLeftOver time.Duration,
minGasPrice *big.Int,
chain *core.BlockChain,
eth Backend,
chainConfig *params.ChainConfig,
engine consensus.Engine,
bidWorker bidWorker,
@@ -127,7 +129,8 @@ func newBidSimulator(
config: config,
delayLeftOver: delayLeftOver,
minGasPrice: minGasPrice,
chain: chain,
chain: eth.BlockChain(),
txpool: eth.TxPool(),
chainConfig: chainConfig,
engine: engine,
bidWorker: bidWorker,
@@ -141,7 +144,7 @@ func newBidSimulator(
simulatingBid: make(map[common.Hash]*BidRuntime),
}
b.chainHeadSub = chain.SubscribeChainHeadEvent(b.chainHeadCh)
b.chainHeadSub = b.chain.SubscribeChainHeadEvent(b.chainHeadCh)
if config.Enabled {
b.bidReceiving.Store(true)
@@ -409,7 +412,7 @@ func (b *bidSimulator) clearLoop() {
}
delete(b.bestBid, parentHash)
for k, v := range b.bestBid {
if v.bid.BlockNumber <= blockNumber-core.TriesInMemory {
if v.bid.BlockNumber <= blockNumber-b.chain.TriesInMemory() {
v.env.discard()
delete(b.bestBid, k)
}
@@ -418,7 +421,7 @@ func (b *bidSimulator) clearLoop() {
b.simBidMu.Lock()
for k, v := range b.simulatingBid {
if v.bid.BlockNumber <= blockNumber-core.TriesInMemory {
if v.bid.BlockNumber <= blockNumber-b.chain.TriesInMemory() {
v.env.discard()
delete(b.simulatingBid, k)
}
@@ -625,16 +628,39 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) {
// check if bid gas price is lower than min gas price
{
bidGasUsed := uint64(0)
bidGasFee := bidRuntime.env.state.GetBalance(consensus.SystemAddress)
bidGasFee := big.NewInt(0)
for _, receipt := range bidRuntime.env.receipts {
bidGasUsed += receipt.GasUsed
for i, receipt := range bidRuntime.env.receipts {
tx := bidRuntime.env.txs[i]
if !b.txpool.Has(tx.Hash()) {
bidGasUsed += receipt.GasUsed
effectiveTip, er := tx.EffectiveGasTip(bidRuntime.env.header.BaseFee)
if er != nil {
err = errors.New("failed to calculate effective tip")
return
}
if bidRuntime.env.header.BaseFee != nil {
effectiveTip.Add(effectiveTip, bidRuntime.env.header.BaseFee)
}
gasFee := new(big.Int).Mul(effectiveTip, new(big.Int).SetUint64(receipt.GasUsed))
bidGasFee.Add(bidGasFee, gasFee)
if tx.Type() == types.BlobTxType {
blobFee := new(big.Int).Mul(receipt.BlobGasPrice, new(big.Int).SetUint64(receipt.BlobGasUsed))
bidGasFee.Add(bidGasFee, blobFee)
}
}
}
bidGasPrice := new(big.Int).Div(bidGasFee.ToBig(), new(big.Int).SetUint64(bidGasUsed))
if bidGasPrice.Cmp(b.minGasPrice) < 0 {
err = errors.New("bid gas price is lower than min gas price")
return
// if bid txs are all from mempool, do not check gas price
if bidGasUsed != 0 {
bidGasPrice := new(big.Int).Div(bidGasFee, new(big.Int).SetUint64(bidGasUsed))
if bidGasPrice.Cmp(b.minGasPrice) < 0 {
err = fmt.Errorf("bid gas price is lower than min gas price, bid:%v, min:%v", bidGasPrice, b.minGasPrice)
return
}
}
}

View File

@@ -102,7 +102,7 @@ func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *even
worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, false),
}
miner.bidSimulator = newBidSimulator(&config.Mev, config.DelayLeftOver, config.GasPrice, eth.BlockChain(), chainConfig, engine, miner.worker)
miner.bidSimulator = newBidSimulator(&config.Mev, config.DelayLeftOver, config.GasPrice, eth, chainConfig, engine, miner.worker)
miner.worker.setBestBidFetcher(miner.bidSimulator)
miner.wg.Add(1)

View File

@@ -665,7 +665,7 @@ func (w *worker) resultLoop() {
// Commit block and state to database.
task.state.SetExpectedStateRoot(block.Root())
start := time.Now()
status, err := w.chain.WriteBlockAndSetHead(block, receipts, logs, task.state, true, w.mux)
status, err := w.chain.WriteBlockAndSetHead(block, receipts, logs, task.state, true)
if status != core.CanonStatTy {
if err != nil {
log.Error("Failed writing block to chain", "err", err, "status", status)

View File

@@ -192,6 +192,11 @@ var (
MinBlocksForBlobRequests uint64 = 524288 // it keeps blob data available for ~18.2 days in local, ref: https://github.com/bnb-chain/BEPs/blob/master/BEPs/BEP-336.md#51-parameters.
DefaultExtraReserveForBlobRequests uint64 = 1 * (24 * 3600) / 3 // it adds more time for expired blobs for some request cases, like expiry blob when remote peer is syncing, default 1 day.
BreatheBlockInterval uint64 = 86400 // Controls the interval for updateValidatorSetV2
// used for testing:
// [1,9] except 2 --> used as turn length directly
// 2 --> use random values to test switching turn length
// 0 and other values --> get turn length from contract
FixedTurnLength uint64 = 0
)
// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations

View File

@@ -1,8 +1,19 @@
From 32329440626abd6e9668c2d5bd2e7b719e951e01 Mon Sep 17 00:00:00 2001
From: NathanBSC <Nathan.l@nodereal.io>
Date: Wed, 31 Jul 2024 15:01:28 +0800
Subject: [PATCH] diff go ethereum
---
core/vm/contracts.go | 10 ----------
core/vm/jump_table.go | 2 +-
params/protocol_params.go | 2 +-
3 files changed, 2 insertions(+), 12 deletions(-)
diff --git a/core/vm/contracts.go b/core/vm/contracts.go
index 5988bb15f..c92cbf542 100644
index 38a6cac24..7eb29c3ed 100644
--- a/core/vm/contracts.go
+++ b/core/vm/contracts.go
@@ -83,9 +83,6 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
@@ -84,9 +84,6 @@ var PrecompiledContractsIstanbul = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{7}): &bn256ScalarMulIstanbul{},
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
@@ -12,7 +23,7 @@ index 5988bb15f..c92cbf542 100644
}
var PrecompiledContractsNano = map[common.Address]PrecompiledContract{
@@ -238,13 +235,6 @@ var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{
@@ -239,13 +236,6 @@ var PrecompiledContractsCancun = map[common.Address]PrecompiledContract{
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
common.BytesToAddress([]byte{9}): &blake2F{},
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
@@ -25,7 +36,7 @@ index 5988bb15f..c92cbf542 100644
- common.BytesToAddress([]byte{105}): &secp256k1SignatureRecover{},
}
// PrecompiledContractsBLS contains the set of pre-compiled Ethereum
// PrecompiledContractsHaber contains the default set of pre-compiled Ethereum
diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go
index 70c543f14..65716f944 100644
--- a/core/vm/jump_table.go
@@ -40,7 +51,7 @@ index 70c543f14..65716f944 100644
enable3860(&instructionSet) // Limit and meter initcode
diff --git a/params/protocol_params.go b/params/protocol_params.go
index b84fa148f..97bf6c4d2 100644
index 65b2d942c..bb085512f 100644
--- a/params/protocol_params.go
+++ b/params/protocol_params.go
@@ -23,7 +23,7 @@ import (
@@ -52,3 +63,6 @@ index b84fa148f..97bf6c4d2 100644
MinGasLimit uint64 = 5000 // Minimum the gas limit may ever be.
MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1).
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
--
2.41.0

View File

@@ -11,4 +11,5 @@ echo "PASS",$PASS,"FAIL",$FAIL
if [ $FAIL -ne 0 ]
then
cat fail.log
exit 1
fi

View File

@@ -23,6 +23,7 @@ type ID struct {
StateRoot common.Hash // The root of the corresponding state(block.root)
Owner common.Hash // The contract address hash which the trie belongs to
Root common.Hash // The root hash of trie
Version uint64 // The version of a Versa tree
}
// StateTrieID constructs an identifier for state trie with the provided state root.

119
trie/version_trie.go Normal file
View File

@@ -0,0 +1,119 @@
package trie
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/triedb/database"
)
// VersionTrie is a wrapper around version state that implements the trie.Trie
// interface so that version trees can be reused verbatim.
type VersionTrie struct {
db database.Database
reader *trieReader
//tree TreeHandler
}
// NewVersionTrie constructs a version state tree based on the specified root hash.
func NewVersionTrie(root common.Hash, db database.Database) (*VersionTrie, error) {
reader, err := newTrieReader(root, common.Hash{}, db)
if err != nil {
return nil, err
}
// TODO
// Open a tree
// tree, err := OpenTree(state StateHandler, version int64, owner common.Hash, root common.Hash)
if err != nil {
return nil, err
}
return &VersionTrie{
db: db,
reader: reader,
// tree: tree,
}, nil
}
// GetKey returns the sha3 preimage of a hashed key that was previously used
// to store a value.
func (t *VersionTrie) GetKey(key []byte) []byte {
return key
}
// GetAccount implements state.Trie, retrieving the account with the specified
// account address. If the specified account is not in the tree, nil will
// be returned. If the tree is corrupted, an error will be returned.
func (t *VersionTrie) GetAccount(address common.Address) (*types.StateAccount, error) {
// TODO
}
// GetStorage returns the value for key stored in the trie. The value bytes
// must not be modified by the caller. If a node was not found in the database,
// a trie.MissingNodeError is returned.
func (t *VersionTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) {
// TODO
}
// UpdateAccount abstracts an account write to the trie. It encodes the
// provided account object with associated algorithm and then updates it
// in the trie with provided address.
func (t *VersionTrie) UpdateAccount(address common.Address, account *types.StateAccount) error {
// TODO
}
// UpdateStorage associates key with value in the trie. If value has length zero,
// any existing value is deleted from the trie. The value bytes must not be modified
// by the caller while they are stored in the trie. If a node was not found in the
// database, a trie.MissingNodeError is returned.
func (t *VersionTrie) UpdateStorage(addr common.Address, key, value []byte) error {
// TODO
}
// DeleteAccount abstracts an account deletion from the trie.
func (t *VersionTrie) DeleteAccount(address common.Address) error {
// TODO
}
// DeleteStorage removes any existing value for key from the trie. If a node
// was not found in the database, a trie.MissingNodeError is returned.
func (t *VersionTrie) DeleteStorage(addr common.Address, key []byte) error {
// TODO
}
// UpdateContractCode abstracts code write to the trie. It is expected
// to be moved to the stateWriter interface when the latter is ready.
func (t *VersionTrie) UpdateContractCode(address common.Address, codeHash common.Hash, code []byte) error {
// TODO
}
// Hash returns the root hash of the trie. It does not write to the database and
// can be used even if the trie doesn't have one.
func (t *VersionTrie) Hash() common.Hash {
// TODO
}
// Commit collects all dirty nodes in the trie and replace them with the
// corresponding node hash.
func (t *VersionTrie) Commit(collectLeaf bool) (common.Hash, error) {
// TODO
}
// NodeIterator returns an iterator that returns nodes of the trie. Iteration
// starts at the key after the given start key. And error will be returned
// if fails to create node iterator.
func (t *VersionTrie) NodeIterator(startKey []byte) (trie.NodeIterator, error) {
// TODO
}
// Prove constructs a Merkle proof for key. The result contains all encoded nodes
// on the path to the value at key. The value itself is also included in the last
// node and can be retrieved by verifying the proof.
//
// If the trie does not contain a value for key, the returned proof contains all
// nodes of the longest existing prefix of the key (at least the root), ending
// with the node that proves the absence of the key.
func (t *VersionTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
// TODO
}

View File

@@ -18,6 +18,7 @@ package triedb
import (
"errors"
"github.com/ethereum/go-ethereum/triedb/versadb"
"strings"
"github.com/ethereum/go-ethereum/common"
@@ -37,9 +38,11 @@ type Config struct {
Preimages bool // Flag whether the preimage of node key is recorded
Cache int
NoTries bool
IsVerkle bool // Flag whether the db is holding a verkle tree
HashDB *hashdb.Config // Configs for hash-based scheme
PathDB *pathdb.Config // Configs for experimental path-based scheme
IsVerkle bool // Flag whether the db is holding a verkle tree
IsVersa bool
HashDB *hashdb.Config // Configs for hash-based scheme
PathDB *pathdb.Config // Configs for experimental path-based scheme
VersaDB *versadb.Config // TODO, Richard
}
// HashDefaults represents a config for using hash-based scheme with
@@ -148,6 +151,11 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
config.PathDB = pathdb.Defaults
}
db.backend = pathdb.New(triediskdb, config.PathDB)
} else if strings.Compare(dbScheme, rawdb.VersaScheme) == 0 {
if config.VersaDB == nil {
config.VersaDB = versadb.Defaults
}
db.backend = versadb.New(triediskdb, config.VersaDB)
} else {
var resolver hashdb.ChildResolver
if config.IsVerkle {
@@ -409,3 +417,8 @@ func (db *Database) GetAllRooHash() [][]string {
func (db *Database) IsVerkle() bool {
return db.config.IsVerkle
}
// IsVersionedState returns the indicator if the database is holding a versioned state.
func (db *Database) IsVersionedState() bool {
return db.config.IsVersa
}

View File

@@ -0,0 +1,82 @@
package versadb
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/trie/trienode"
"github.com/ethereum/go-ethereum/trie/triestate"
"sync"
)
const (
// maxDiffLayers is the maximum diff layers allowed in the layer tree.
maxDiffLayers = 128
)
// Config contains the settings for database.
type Config struct {
CleanCacheSize int // Maximum memory allowance (in bytes) for caching clean nodes
}
// Defaults is the default setting for database if it's not specified. ,
var Defaults = &Config{
CleanCacheSize: 0,
}
type Database struct {
// readOnly is the flag whether the mutation is allowed to be applied.
// It will be set automatically when the database is journaled during
// the shutdown to reject all following unexpected mutations.
readOnly bool // Flag if database is opened in read only mode
config *Config // Configuration for database
lock sync.RWMutex // Lock to prevent mutations from happening at the same time
}
// New initializes the version state database.
func New(diskdb ethdb.Database, config *Config) *Database {
if config == nil {
config = Defaults
}
// TODO
db := VersaDB.NewVersaDB(nil)
return db
}
// Scheme returns the identifier of used storage scheme.
func (db *Database) Scheme() string {
return rawdb.VersaScheme
}
// Initialized returns an indicator if the state data is already initialized
// according to the state scheme.
func (db *Database) Initialized(genesisRoot common.Hash) bool {
// TODO
}
// Size returns the current storage size of the memory cache in front of the
// persistent database layer.
func (db *Database) Size() (common.StorageSize, common.StorageSize, common.StorageSize) {
// TODO
}
// Update performs a state transition by committing dirty nodes contained
// in the given set in order to update state from the specified parent to
// the specified root.
//
// The passed in maps(nodes, states) will be retained to avoid copying
// everything. Therefore, these maps must not be changed afterwards.
func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error {
// TODO
}
// Commit writes all relevant trie nodes belonging to the specified state
// to disk. Report specifies whether logs will be displayed in info level.
func (db *Database) Commit(root common.Hash, report bool) error {
// TODO
}
// Close closes the trie database backend and releases all held resources.
func (db *Database) Close() error {
// TODO
}