Compare commits
23 Commits
versa_perf
...
integratio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d33ca4f108 | ||
|
|
b61128bd7b | ||
|
|
df16ab95ab | ||
|
|
9e343669b5 | ||
|
|
987b8c1504 | ||
|
|
7d907016ff | ||
|
|
00cac12542 | ||
|
|
27f618f434 | ||
|
|
46b88d11f9 | ||
|
|
f532da6ca0 | ||
|
|
c94fc290e7 | ||
|
|
7f3c5ce4cd | ||
|
|
313449404f | ||
|
|
99e4e950f8 | ||
|
|
cabd0f8a21 | ||
|
|
17e0e45a09 | ||
|
|
6260a26971 | ||
|
|
a44b6d8067 | ||
|
|
b844958a96 | ||
|
|
3cade73e40 | ||
|
|
4f38c78c6e | ||
|
|
7b8d28b425 | ||
|
|
74078e1dc4 |
8
Makefile
8
Makefile
@@ -29,11 +29,11 @@ truffle-test:
|
|||||||
docker build . -f ./docker/Dockerfile --target bsc-genesis -t bsc-genesis
|
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 --target bsc -t bsc
|
||||||
docker build . -f ./docker/Dockerfile.truffle -t truffle-test
|
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 genesis
|
||||||
docker-compose -f ./tests/truffle/docker-compose.yml up -d bsc-rpc bsc-validator1
|
docker compose -f ./tests/truffle/docker-compose.yml up -d bsc-rpc bsc-validator1
|
||||||
sleep 30
|
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 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 down
|
||||||
|
|
||||||
#? lint: Run certain pre-selected linters
|
#? lint: Run certain pre-selected linters
|
||||||
lint: ## Run linters.
|
lint: ## Run linters.
|
||||||
|
|||||||
@@ -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"
|
extraData := "0xd883010205846765746888676f312e32302e35856c696e75780000002995c52af8b5830563efb86089cf168dcf4c5d3cb057926628ad1bf0f03ea67eef1458485578a4f8489afa8a853ecc7af45e2d145c21b70641c4b29f0febd2dd2c61fa1ba174be3fd47f1f5fa2ab9b5c318563d8b70ca58d0d51e79ee32b2fb721649e2cb9d36538361fba11f84c8401d14bb7a0fa67ddb3ba654d6006bf788710032247aa4d1be0707273e696b422b3ff72e9798401d14bbaa01225f505f5a0e1aefadcd2913b7aac9009fe4fb3d1bf57399e0b9dce5947f94280fe6d3647276c4127f437af59eb7c7985b2ae1ebe432619860695cb6106b80cc66c735bc1709afd11f233a2c97409d38ebaf7178aa53e895aea2fe0a229f71ec601"
|
||||||
extra, err := parseExtra(extraData)
|
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)
|
extra, err := parseExtra(extraData)
|
||||||
assert.NoError(t, err)
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const (
|
|||||||
BLSPublicKeyLength = 48
|
BLSPublicKeyLength = 48
|
||||||
|
|
||||||
// follow order in extra field
|
// 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
|
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
|
validatorNumberSize = 1 // Fixed number of extra prefix bytes reserved for validator number after Luban
|
||||||
validatorBytesLength = common.AddressLength + types.BLSPublicKeyLength
|
validatorBytesLength = common.AddressLength + types.BLSPublicKeyLength
|
||||||
@@ -35,6 +35,7 @@ type Extra struct {
|
|||||||
ExtraVanity string
|
ExtraVanity string
|
||||||
ValidatorSize uint8
|
ValidatorSize uint8
|
||||||
Validators validatorsAscending
|
Validators validatorsAscending
|
||||||
|
TurnLength *uint8
|
||||||
*types.VoteAttestation
|
*types.VoteAttestation
|
||||||
ExtraSeal []byte
|
ExtraSeal []byte
|
||||||
}
|
}
|
||||||
@@ -113,6 +114,15 @@ func parseExtra(hexData string) (*Extra, error) {
|
|||||||
sort.Sort(extra.Validators)
|
sort.Sort(extra.Validators)
|
||||||
data = data[validatorBytesTotalLength-validatorNumberSize:]
|
data = data[validatorBytesTotalLength-validatorNumberSize:]
|
||||||
dataLength = len(data)
|
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
|
// 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 {
|
if extra.VoteAttestation != nil {
|
||||||
fmt.Printf("Attestation :\n")
|
fmt.Printf("Attestation :\n")
|
||||||
fmt.Printf("\tVoteAddressSet : %b, %d\n", extra.VoteAddressSet, bitset.From([]uint64{uint64(extra.VoteAddressSet)}).Count())
|
fmt.Printf("\tVoteAddressSet : %b, %d\n", extra.VoteAddressSet, bitset.From([]uint64{uint64(extra.VoteAddressSet)}).Count())
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
"golang.org/x/time/rate"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -216,6 +217,8 @@ type faucet struct {
|
|||||||
|
|
||||||
bep2eInfos map[string]bep2eInfo
|
bep2eInfos map[string]bep2eInfo
|
||||||
bep2eAbi abi.ABI
|
bep2eAbi abi.ABI
|
||||||
|
|
||||||
|
limiter *IPRateLimiter
|
||||||
}
|
}
|
||||||
|
|
||||||
// wsConn wraps a websocket connection with a write mutex as the underlying
|
// wsConn wraps a websocket connection with a write mutex as the underlying
|
||||||
@@ -235,6 +238,12 @@ func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index [
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow 1 request per minute with burst of 5, and cache up to 1000 IPs
|
||||||
|
limiter, err := NewIPRateLimiter(rate.Limit(1.0), 5, 1000)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
return &faucet{
|
return &faucet{
|
||||||
config: genesis.Config,
|
config: genesis.Config,
|
||||||
client: client,
|
client: client,
|
||||||
@@ -245,6 +254,7 @@ func newFaucet(genesis *core.Genesis, url string, ks *keystore.KeyStore, index [
|
|||||||
update: make(chan struct{}, 1),
|
update: make(chan struct{}, 1),
|
||||||
bep2eInfos: bep2eInfos,
|
bep2eInfos: bep2eInfos,
|
||||||
bep2eAbi: bep2eAbi,
|
bep2eAbi: bep2eAbi,
|
||||||
|
limiter: limiter,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,6 +282,20 @@ func (f *faucet) webHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// apiHandler handles requests for Ether grants and transaction statuses.
|
// apiHandler handles requests for Ether grants and transaction statuses.
|
||||||
func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
|
func (f *faucet) apiHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ip := r.RemoteAddr
|
||||||
|
if len(r.Header.Get("X-Forwarded-For")) > 0 {
|
||||||
|
ips := strings.Split(r.Header.Get("X-Forwarded-For"), ",")
|
||||||
|
if len(ips) > 0 {
|
||||||
|
ip = strings.TrimSpace(ips[len(ips)-1])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !f.limiter.GetLimiter(ip).Allow() {
|
||||||
|
log.Warn("Too many requests from client: ", "client", ip)
|
||||||
|
http.Error(w, "Too many requests", http.StatusTooManyRequests)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
upgrader := websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
|
upgrader := websocket.Upgrader{CheckOrigin: func(r *http.Request) bool { return true }}
|
||||||
conn, err := upgrader.Upgrade(w, r, nil)
|
conn, err := upgrader.Upgrade(w, r, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -625,19 +649,22 @@ func (f *faucet) loop() {
|
|||||||
balance := new(big.Int).Div(f.balance, ether)
|
balance := new(big.Int).Div(f.balance, ether)
|
||||||
|
|
||||||
for _, conn := range f.conns {
|
for _, conn := range f.conns {
|
||||||
if err := send(conn, map[string]interface{}{
|
go func(conn *wsConn) {
|
||||||
"funds": balance,
|
if err := send(conn, map[string]interface{}{
|
||||||
"funded": f.nonce,
|
"funds": balance,
|
||||||
"requests": f.reqs,
|
"funded": f.nonce,
|
||||||
}, time.Second); err != nil {
|
"requests": f.reqs,
|
||||||
log.Warn("Failed to send stats to client", "err", err)
|
}, time.Second); err != nil {
|
||||||
conn.conn.Close()
|
log.Warn("Failed to send stats to client", "err", err)
|
||||||
continue
|
conn.conn.Close()
|
||||||
}
|
return // Exit the goroutine if the first send fails
|
||||||
if err := send(conn, head, time.Second); err != nil {
|
}
|
||||||
log.Warn("Failed to send header to client", "err", err)
|
|
||||||
conn.conn.Close()
|
if err := send(conn, head, time.Second); err != nil {
|
||||||
}
|
log.Warn("Failed to send header to client", "err", err)
|
||||||
|
conn.conn.Close()
|
||||||
|
}
|
||||||
|
}(conn)
|
||||||
}
|
}
|
||||||
f.lock.RUnlock()
|
f.lock.RUnlock()
|
||||||
}
|
}
|
||||||
@@ -656,10 +683,12 @@ func (f *faucet) loop() {
|
|||||||
// Pending requests updated, stream to clients
|
// Pending requests updated, stream to clients
|
||||||
f.lock.RLock()
|
f.lock.RLock()
|
||||||
for _, conn := range f.conns {
|
for _, conn := range f.conns {
|
||||||
if err := send(conn, map[string]interface{}{"requests": f.reqs}, time.Second); err != nil {
|
go func(conn *wsConn) {
|
||||||
log.Warn("Failed to send requests to client", "err", err)
|
if err := send(conn, map[string]interface{}{"requests": f.reqs}, time.Second); err != nil {
|
||||||
conn.conn.Close()
|
log.Warn("Failed to send requests to client", "err", err)
|
||||||
}
|
conn.conn.Close()
|
||||||
|
}
|
||||||
|
}(conn)
|
||||||
}
|
}
|
||||||
f.lock.RUnlock()
|
f.lock.RUnlock()
|
||||||
}
|
}
|
||||||
|
|||||||
44
cmd/faucet/rate_limiter.go
Normal file
44
cmd/faucet/rate_limiter.go
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
lru "github.com/hashicorp/golang-lru"
|
||||||
|
"golang.org/x/time/rate"
|
||||||
|
)
|
||||||
|
|
||||||
|
type IPRateLimiter struct {
|
||||||
|
ips *lru.Cache // LRU cache to store IP addresses and their associated rate limiters
|
||||||
|
r rate.Limit // the rate limit, e.g., 5 requests per second
|
||||||
|
b int // the burst size, e.g., allowing a burst of 10 requests at once. The rate limiter gets into action
|
||||||
|
// only after this number exceeds
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewIPRateLimiter(r rate.Limit, b int, size int) (*IPRateLimiter, error) {
|
||||||
|
cache, err := lru.New(size)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
i := &IPRateLimiter{
|
||||||
|
ips: cache,
|
||||||
|
r: r,
|
||||||
|
b: b,
|
||||||
|
}
|
||||||
|
|
||||||
|
return i, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IPRateLimiter) addIP(ip string) *rate.Limiter {
|
||||||
|
limiter := rate.NewLimiter(i.r, i.b)
|
||||||
|
|
||||||
|
i.ips.Add(ip, limiter)
|
||||||
|
|
||||||
|
return limiter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *IPRateLimiter) GetLimiter(ip string) *rate.Limiter {
|
||||||
|
if limiter, exists := i.ips.Get(ip); exists {
|
||||||
|
return limiter.(*rate.Limiter)
|
||||||
|
}
|
||||||
|
|
||||||
|
return i.addIP(ip)
|
||||||
|
}
|
||||||
@@ -62,6 +62,7 @@ var (
|
|||||||
ArgsUsage: "<genesisPath>",
|
ArgsUsage: "<genesisPath>",
|
||||||
Flags: flags.Merge([]cli.Flag{
|
Flags: flags.Merge([]cli.Flag{
|
||||||
utils.CachePreimagesFlag,
|
utils.CachePreimagesFlag,
|
||||||
|
utils.OverridePassedForkTime,
|
||||||
utils.OverrideBohr,
|
utils.OverrideBohr,
|
||||||
utils.OverrideVerkle,
|
utils.OverrideVerkle,
|
||||||
utils.MultiDataBaseFlag,
|
utils.MultiDataBaseFlag,
|
||||||
@@ -253,6 +254,10 @@ func initGenesis(ctx *cli.Context) error {
|
|||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
var overrides core.ChainOverrides
|
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) {
|
if ctx.IsSet(utils.OverrideBohr.Name) {
|
||||||
v := ctx.Uint64(utils.OverrideBohr.Name)
|
v := ctx.Uint64(utils.OverrideBohr.Name)
|
||||||
overrides.OverrideBohr = &v
|
overrides.OverrideBohr = &v
|
||||||
@@ -833,7 +838,7 @@ func dump(ctx *cli.Context) error {
|
|||||||
triedb := utils.MakeTrieDatabase(ctx, stack, db, true, true, false) // always enable preimage lookup
|
triedb := utils.MakeTrieDatabase(ctx, stack, db, true, true, false) // always enable preimage lookup
|
||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
|
|
||||||
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb, false), nil)
|
state, err := state.New(root, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -185,6 +185,10 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
|||||||
params.RialtoGenesisHash = common.HexToHash(v)
|
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) {
|
if ctx.IsSet(utils.OverrideBohr.Name) {
|
||||||
v := ctx.Uint64(utils.OverrideBohr.Name)
|
v := ctx.Uint64(utils.OverrideBohr.Name)
|
||||||
cfg.Eth.OverrideBohr = &v
|
cfg.Eth.OverrideBohr = &v
|
||||||
@@ -206,6 +210,9 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
|||||||
if ctx.IsSet(utils.OverrideBreatheBlockInterval.Name) {
|
if ctx.IsSet(utils.OverrideBreatheBlockInterval.Name) {
|
||||||
params.BreatheBlockInterval = ctx.Uint64(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)
|
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
@@ -35,7 +34,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/console/prompt"
|
"github.com/ethereum/go-ethereum/console/prompt"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
|
||||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
@@ -93,9 +91,6 @@ Remove blockchain and state databases`,
|
|||||||
dbHbss2PbssCmd,
|
dbHbss2PbssCmd,
|
||||||
dbTrieGetCmd,
|
dbTrieGetCmd,
|
||||||
dbTrieDeleteCmd,
|
dbTrieDeleteCmd,
|
||||||
getVersionDBState,
|
|
||||||
getHashDBState,
|
|
||||||
diffDebugStateDB,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
dbInspectCmd = &cli.Command{
|
dbInspectCmd = &cli.Command{
|
||||||
@@ -291,141 +286,8 @@ WARNING: This is a low-level operation which may cause database corruption!`,
|
|||||||
Description: `This commands will read current offset from kvdb, which is the current offset and starting BlockNumber
|
Description: `This commands will read current offset from kvdb, which is the current offset and starting BlockNumber
|
||||||
of ancientStore, will also displays the reserved number of blocks in ancientStore `,
|
of ancientStore, will also displays the reserved number of blocks in ancientStore `,
|
||||||
}
|
}
|
||||||
getVersionDBState = &cli.Command{
|
|
||||||
Action: getDebugVersionState,
|
|
||||||
Name: "get-debug-version-state",
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
utils.VersionStateDirFlag,
|
|
||||||
utils.BlockNumber,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
getHashDBState = &cli.Command{
|
|
||||||
Action: getDebugHashState,
|
|
||||||
Name: "get-debug-hash-state",
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
utils.HashStateDirFlag,
|
|
||||||
utils.BlockNumber,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
diffDebugStateDB = &cli.Command{
|
|
||||||
Action: diffDebugState,
|
|
||||||
Name: "diff-debug-state",
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
utils.VersionStateDirFlag,
|
|
||||||
utils.HashStateDirFlag,
|
|
||||||
utils.BlockNumber,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func diffDebugState(ctx *cli.Context) error {
|
|
||||||
if !ctx.IsSet(utils.VersionStateDirFlag.Name) {
|
|
||||||
return fmt.Errorf("please set `--versionstatedir` flag")
|
|
||||||
}
|
|
||||||
if !ctx.IsSet(utils.BlockNumber.Name) {
|
|
||||||
return fmt.Errorf("please set `--block` flag")
|
|
||||||
}
|
|
||||||
if !ctx.IsSet(utils.HashStateDirFlag.Name) {
|
|
||||||
return fmt.Errorf("please set `--hashstatedir` flag")
|
|
||||||
}
|
|
||||||
verDir := ctx.String(utils.VersionStateDirFlag.Name)
|
|
||||||
hasDir := ctx.String(utils.HashStateDirFlag.Name)
|
|
||||||
block := ctx.Int64(utils.BlockNumber.Name)
|
|
||||||
|
|
||||||
vdb, err := rawdb.Open(rawdb.OpenOptions{
|
|
||||||
ReadOnly: true,
|
|
||||||
Type: "pebble",
|
|
||||||
Directory: verDir,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
verData, err := vdb.Get(state.DebugVersionStateKey(block))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
verDebugState := &state.DebugVersionState{}
|
|
||||||
err = json.Unmarshal(verData, verDebugState)
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
hdb, err := rawdb.Open(rawdb.OpenOptions{
|
|
||||||
ReadOnly: true,
|
|
||||||
Type: "pebble",
|
|
||||||
Directory: hasDir,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hashData, err := hdb.Get(state.DebugHashStateKey(block))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
hasDebugState := &state.DebugHashState{}
|
|
||||||
err = json.Unmarshal(hashData, hasDebugState)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
res := state.GenerateDebugStateDiff(verDebugState, hasDebugState)
|
|
||||||
fmt.Println(res)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDebugVersionState(ctx *cli.Context) error {
|
|
||||||
if !ctx.IsSet(utils.VersionStateDirFlag.Name) {
|
|
||||||
return fmt.Errorf("please set `--versionstatedir` flag")
|
|
||||||
}
|
|
||||||
if !ctx.IsSet(utils.BlockNumber.Name) {
|
|
||||||
return fmt.Errorf("please set `--block` flag")
|
|
||||||
}
|
|
||||||
dir := ctx.String(utils.VersionStateDirFlag.Name)
|
|
||||||
block := ctx.Int64(utils.BlockNumber.Name)
|
|
||||||
db, err := rawdb.Open(rawdb.OpenOptions{
|
|
||||||
ReadOnly: true,
|
|
||||||
Type: "pebble",
|
|
||||||
Directory: dir,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data, err := db.Get(state.DebugVersionStateKey(block))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println(string(data))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDebugHashState(ctx *cli.Context) error {
|
|
||||||
if !ctx.IsSet(utils.HashStateDirFlag.Name) {
|
|
||||||
return fmt.Errorf("please set `--hashstatedir` flag")
|
|
||||||
}
|
|
||||||
if !ctx.IsSet(utils.BlockNumber.Name) {
|
|
||||||
return fmt.Errorf("please set `--block` flag")
|
|
||||||
}
|
|
||||||
dir := ctx.String(utils.HashStateDirFlag.Name)
|
|
||||||
block := ctx.Int64(utils.BlockNumber.Name)
|
|
||||||
db, err := rawdb.Open(rawdb.OpenOptions{
|
|
||||||
ReadOnly: true,
|
|
||||||
Type: "pebble",
|
|
||||||
Directory: dir,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data, err := db.Get(state.DebugHashStateKey(block))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println(string(data))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeDB(ctx *cli.Context) error {
|
func removeDB(ctx *cli.Context) error {
|
||||||
stack, config := makeConfigNode(ctx)
|
stack, config := makeConfigNode(ctx)
|
||||||
|
|
||||||
|
|||||||
@@ -72,12 +72,14 @@ var (
|
|||||||
utils.USBFlag,
|
utils.USBFlag,
|
||||||
utils.SmartCardDaemonPathFlag,
|
utils.SmartCardDaemonPathFlag,
|
||||||
utils.RialtoHash,
|
utils.RialtoHash,
|
||||||
|
utils.OverridePassedForkTime,
|
||||||
utils.OverrideBohr,
|
utils.OverrideBohr,
|
||||||
utils.OverrideVerkle,
|
utils.OverrideVerkle,
|
||||||
utils.OverrideFullImmutabilityThreshold,
|
utils.OverrideFullImmutabilityThreshold,
|
||||||
utils.OverrideMinBlocksForBlobRequests,
|
utils.OverrideMinBlocksForBlobRequests,
|
||||||
utils.OverrideDefaultExtraReserveForBlobRequests,
|
utils.OverrideDefaultExtraReserveForBlobRequests,
|
||||||
utils.OverrideBreatheBlockInterval,
|
utils.OverrideBreatheBlockInterval,
|
||||||
|
utils.OverrideFixedTurnLength,
|
||||||
utils.EnablePersonal,
|
utils.EnablePersonal,
|
||||||
utils.TxPoolLocalsFlag,
|
utils.TxPoolLocalsFlag,
|
||||||
utils.TxPoolNoLocalsFlag,
|
utils.TxPoolNoLocalsFlag,
|
||||||
@@ -361,8 +363,6 @@ func geth(ctx *cli.Context) error {
|
|||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
startNode(ctx, stack, backend, false)
|
startNode(ctx, stack, backend, false)
|
||||||
// TODO:: debug code , will be deleted in the future
|
|
||||||
debug.StartPProf("127.0.0.1:7060", !ctx.IsSet("metrics.addr"))
|
|
||||||
stack.Wait()
|
stack.Wait()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ node get_perf.js --rpc ${url} --startNum ${start} --endNum ${end}
|
|||||||
output as following
|
output as following
|
||||||
```bash
|
```bash
|
||||||
Get the performance between [ 19470 , 19670 )
|
Get the performance between [ 19470 , 19670 )
|
||||||
txCountPerBlock = 3142.81 txCountTotal = 628562 BlockCount = 200 avgBlockTime = 3.005 inturnBlocksRatio = 0.975
|
txCountPerBlock = 3142.81 txCountTotal = 628562 BlockCount = 200 avgBlockTime = 3.005 inturnBlocksRatio = 0.975 justifiedBlocksRatio = 0.98
|
||||||
txCountPerSecond = 1045.8602329450914 avgGasUsedPerBlock = 250.02062627 avgGasUsedPerSecond = 83.20153952412646
|
txCountPerSecond = 1045.8602329450914 avgGasUsedPerBlock = 250.02062627 avgGasUsedPerSecond = 83.20153952412646
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ const main = async () => {
|
|||||||
let txCountTotal = 0;
|
let txCountTotal = 0;
|
||||||
let gasUsedTotal = 0;
|
let gasUsedTotal = 0;
|
||||||
let inturnBlocks = 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++) {
|
for (let i = program.startNum; i < program.endNum; i++) {
|
||||||
let txCount = await provider.send("eth_getBlockTransactionCountByNumber", [
|
let txCount = await provider.send("eth_getBlockTransactionCountByNumber", [
|
||||||
ethers.toQuantity(i)]);
|
ethers.toQuantity(i)]);
|
||||||
@@ -26,7 +29,15 @@ const main = async () => {
|
|||||||
inturnBlocks += 1
|
inturnBlocks += 1
|
||||||
}
|
}
|
||||||
let timestamp = eval(eval(header.timestamp).toString(10))
|
let timestamp = eval(eval(header.timestamp).toString(10))
|
||||||
console.log("BlockNumber =", i, "mod =", i%4, "miner =", header.miner , "difficulty =", difficulty, "txCount =", ethers.toNumber(txCount), "gasUsed", gasUsed, "timestamp", timestamp)
|
|
||||||
|
let justifiedNumber = await provider.send("parlia_getJustifiedNumber", [
|
||||||
|
ethers.toQuantity(i)]);
|
||||||
|
if (justifiedNumber + 1 == i) {
|
||||||
|
justifiedBlocks += 1
|
||||||
|
} else {
|
||||||
|
console.log("justified unexpected", "BlockNumber =", i,"justifiedNumber",justifiedNumber)
|
||||||
|
}
|
||||||
|
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
|
let blockCount = program.endNum - program.startNum
|
||||||
@@ -41,13 +52,14 @@ const main = async () => {
|
|||||||
let timeCost = endTime - startTime
|
let timeCost = endTime - startTime
|
||||||
let avgBlockTime = timeCost/blockCount
|
let avgBlockTime = timeCost/blockCount
|
||||||
let inturnBlocksRatio = inturnBlocks/blockCount
|
let inturnBlocksRatio = inturnBlocks/blockCount
|
||||||
|
let justifiedBlocksRatio = justifiedBlocks/blockCount
|
||||||
let tps = txCountTotal/timeCost
|
let tps = txCountTotal/timeCost
|
||||||
let M = 1000000
|
let M = 1000000
|
||||||
let avgGasUsedPerBlock = gasUsedTotal/blockCount/M
|
let avgGasUsedPerBlock = gasUsedTotal/blockCount/M
|
||||||
let avgGasUsedPerSecond = gasUsedTotal/timeCost/M
|
let avgGasUsedPerSecond = gasUsedTotal/timeCost/M
|
||||||
|
|
||||||
console.log("Get the performance between [", program.startNum, ",", program.endNum, ")");
|
console.log("Get the performance between [", program.startNum, ",", program.endNum, ")");
|
||||||
console.log("txCountPerBlock =", txCountPerBlock, "txCountTotal =", txCountTotal, "BlockCount =", blockCount, "avgBlockTime =", avgBlockTime, "inturnBlocksRatio =", inturnBlocksRatio);
|
console.log("txCountPerBlock =", txCountPerBlock, "txCountTotal =", txCountTotal, "BlockCount =", blockCount, "avgBlockTime =", avgBlockTime, "inturnBlocksRatio =", inturnBlocksRatio, "justifiedBlocksRatio =", justifiedBlocksRatio);
|
||||||
console.log("txCountPerSecond =", tps, "avgGasUsedPerBlock =", avgGasUsedPerBlock, "avgGasUsedPerSecond =", avgGasUsedPerSecond);
|
console.log("txCountPerSecond =", tps, "avgGasUsedPerBlock =", avgGasUsedPerBlock, "avgGasUsedPerSecond =", avgGasUsedPerSecond);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
164
cmd/jsutils/getchainstatus.js
Normal file
164
cmd/jsutils/getchainstatus.js
Normal 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);
|
||||||
|
});
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
@@ -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);
|
|
||||||
});
|
|
||||||
@@ -343,7 +343,7 @@ func missingBlocks(chain *core.BlockChain, blocks []*types.Block) []*types.Block
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// If we're above the chain head, state availability is a must
|
// If we're above the chain head, state availability is a must
|
||||||
if !chain.HasBlockAndState(block.Hash(), block.Number().Int64()) {
|
if !chain.HasBlockAndState(block.Hash(), block.NumberU64()) {
|
||||||
return blocks[i:]
|
return blocks[i:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -305,6 +305,11 @@ var (
|
|||||||
Usage: "Manually specify the Rialto Genesis Hash, to trigger builtin network logic",
|
Usage: "Manually specify the Rialto Genesis Hash, to trigger builtin network logic",
|
||||||
Category: flags.EthCategory,
|
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{
|
OverrideBohr = &cli.Uint64Flag{
|
||||||
Name: "override.bohr",
|
Name: "override.bohr",
|
||||||
Usage: "Manually specify the Bohr fork timestamp, overriding the bundled setting",
|
Usage: "Manually specify the Bohr fork timestamp, overriding the bundled setting",
|
||||||
@@ -339,6 +344,12 @@ var (
|
|||||||
Value: params.BreatheBlockInterval,
|
Value: params.BreatheBlockInterval,
|
||||||
Category: flags.EthCategory,
|
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{
|
SyncModeFlag = &flags.TextMarshalerFlag{
|
||||||
Name: "syncmode",
|
Name: "syncmode",
|
||||||
Usage: `Blockchain sync mode ("snap" or "full")`,
|
Usage: `Blockchain sync mode ("snap" or "full")`,
|
||||||
@@ -353,7 +364,7 @@ var (
|
|||||||
}
|
}
|
||||||
StateSchemeFlag = &cli.StringFlag{
|
StateSchemeFlag = &cli.StringFlag{
|
||||||
Name: "state.scheme",
|
Name: "state.scheme",
|
||||||
Usage: "Scheme to use for storing ethereum state ('hash', 'path', 'version')",
|
Usage: "Scheme to use for storing ethereum state ('hash' or 'path')",
|
||||||
Category: flags.StateCategory,
|
Category: flags.StateCategory,
|
||||||
}
|
}
|
||||||
PathDBSyncFlag = &cli.BoolFlag{
|
PathDBSyncFlag = &cli.BoolFlag{
|
||||||
@@ -1135,25 +1146,6 @@ Please note that --` + MetricsHTTPFlag.Name + ` must be set to start the server.
|
|||||||
Value: params.DefaultExtraReserveForBlobRequests,
|
Value: params.DefaultExtraReserveForBlobRequests,
|
||||||
Category: flags.MiscCategory,
|
Category: flags.MiscCategory,
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockNumber = &cli.Int64Flag{
|
|
||||||
Name: "block",
|
|
||||||
Value: int64(0),
|
|
||||||
}
|
|
||||||
|
|
||||||
VersionStateDirFlag = &flags.DirectoryFlag{
|
|
||||||
Name: "versionstatedir",
|
|
||||||
Usage: "Data directory for the version databases and keystore",
|
|
||||||
Value: flags.DirectoryString(node.DefaultDataDir()),
|
|
||||||
Category: flags.EthCategory,
|
|
||||||
}
|
|
||||||
|
|
||||||
HashStateDirFlag = &flags.DirectoryFlag{
|
|
||||||
Name: "hashstatedir",
|
|
||||||
Usage: "Data directory for the version databases and keystore",
|
|
||||||
Value: flags.DirectoryString(node.DefaultDataDir()),
|
|
||||||
Category: flags.EthCategory,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -1972,17 +1964,11 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
|||||||
if ctx.IsSet(StateHistoryFlag.Name) {
|
if ctx.IsSet(StateHistoryFlag.Name) {
|
||||||
cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name)
|
cfg.StateHistory = ctx.Uint64(StateHistoryFlag.Name)
|
||||||
}
|
}
|
||||||
if ctx.String(StateSchemeFlag.Name) != rawdb.VersionScheme {
|
scheme, err := ParseCLIAndConfigStateScheme(ctx.String(StateSchemeFlag.Name), cfg.StateScheme)
|
||||||
scheme, err := ParseCLIAndConfigStateScheme(ctx.String(StateSchemeFlag.Name), cfg.StateScheme)
|
if err != nil {
|
||||||
if err != nil {
|
Fatalf("%v", err)
|
||||||
Fatalf("%v", err)
|
|
||||||
}
|
|
||||||
cfg.StateScheme = scheme
|
|
||||||
} else {
|
|
||||||
// TODO:: compatible with cli line and configuration file, currently only supports cli.
|
|
||||||
cfg.StateScheme = rawdb.VersionScheme
|
|
||||||
}
|
}
|
||||||
|
cfg.StateScheme = scheme
|
||||||
// Parse transaction history flag, if user is still using legacy config
|
// Parse transaction history flag, if user is still using legacy config
|
||||||
// file with 'TxLookupLimit' configured, copy the value to 'TransactionHistory'.
|
// file with 'TxLookupLimit' configured, copy the value to 'TransactionHistory'.
|
||||||
if cfg.TransactionHistory == ethconfig.Defaults.TransactionHistory && cfg.TxLookupLimit != ethconfig.Defaults.TxLookupLimit {
|
if cfg.TransactionHistory == ethconfig.Defaults.TransactionHistory && cfg.TxLookupLimit != ethconfig.Defaults.TxLookupLimit {
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ type ChainHeaderReader interface {
|
|||||||
// GetHighestVerifiedHeader retrieves the highest header verified.
|
// GetHighestVerifiedHeader retrieves the highest header verified.
|
||||||
GetHighestVerifiedHeader() *types.Header
|
GetHighestVerifiedHeader() *types.Header
|
||||||
|
|
||||||
|
// GetVerifiedBlockByHash retrieves the highest verified block.
|
||||||
|
GetVerifiedBlockByHash(hash common.Hash) *types.Header
|
||||||
|
|
||||||
// ChasingHead return the best chain head of peers.
|
// ChasingHead return the best chain head of peers.
|
||||||
ChasingHead() *types.Header
|
ChasingHead() *types.Header
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2306,6 +2306,19 @@ const validatorSetABI = `
|
|||||||
],
|
],
|
||||||
"stateMutability": "view"
|
"stateMutability": "view"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"inputs": [],
|
||||||
|
"name": "getTurnLength",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"name": "getValidators",
|
"name": "getValidators",
|
||||||
|
|||||||
@@ -31,13 +31,7 @@ type API struct {
|
|||||||
|
|
||||||
// GetSnapshot retrieves the state snapshot at a given block.
|
// GetSnapshot retrieves the state snapshot at a given block.
|
||||||
func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
|
func (api *API) GetSnapshot(number *rpc.BlockNumber) (*Snapshot, error) {
|
||||||
// Retrieve the requested block number (or current if none requested)
|
header := api.getHeader(number)
|
||||||
var header *types.Header
|
|
||||||
if number == nil || *number == rpc.LatestBlockNumber {
|
|
||||||
header = api.chain.CurrentHeader()
|
|
||||||
} else {
|
|
||||||
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
|
|
||||||
}
|
|
||||||
// Ensure we have an actually valid block and return its snapshot
|
// Ensure we have an actually valid block and return its snapshot
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errUnknownBlock
|
return nil, errUnknownBlock
|
||||||
@@ -56,13 +50,7 @@ func (api *API) GetSnapshotAtHash(hash common.Hash) (*Snapshot, error) {
|
|||||||
|
|
||||||
// GetValidators retrieves the list of validators at the specified block.
|
// GetValidators retrieves the list of validators at the specified block.
|
||||||
func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error) {
|
func (api *API) GetValidators(number *rpc.BlockNumber) ([]common.Address, error) {
|
||||||
// Retrieve the requested block number (or current if none requested)
|
header := api.getHeader(number)
|
||||||
var header *types.Header
|
|
||||||
if number == nil || *number == rpc.LatestBlockNumber {
|
|
||||||
header = api.chain.CurrentHeader()
|
|
||||||
} else {
|
|
||||||
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
|
|
||||||
}
|
|
||||||
// Ensure we have an actually valid block and return the validators from its snapshot
|
// Ensure we have an actually valid block and return the validators from its snapshot
|
||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, errUnknownBlock
|
return nil, errUnknownBlock
|
||||||
@@ -86,3 +74,65 @@ func (api *API) GetValidatorsAtHash(hash common.Hash) ([]common.Address, error)
|
|||||||
}
|
}
|
||||||
return snap.validators(), nil
|
return snap.validators(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (api *API) GetJustifiedNumber(number *rpc.BlockNumber) (uint64, 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.Attestation == nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
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
|
||||||
|
if header == nil {
|
||||||
|
return 0, errUnknownBlock
|
||||||
|
}
|
||||||
|
snap, err := api.parlia.snapshot(api.chain, header.Number.Uint64(), header.Hash(), nil)
|
||||||
|
if err != nil || snap.Attestation == nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return snap.Attestation.SourceNumber, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *API) getHeader(number *rpc.BlockNumber) (header *types.Header) {
|
||||||
|
currentHeader := api.chain.CurrentHeader()
|
||||||
|
|
||||||
|
if number == nil || *number == rpc.LatestBlockNumber {
|
||||||
|
header = currentHeader // current if none requested
|
||||||
|
} else if *number == rpc.SafeBlockNumber {
|
||||||
|
justifiedNumber, _, err := api.parlia.GetJustifiedNumberAndHash(api.chain, []*types.Header{currentHeader})
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
header = api.chain.GetHeaderByNumber(justifiedNumber)
|
||||||
|
} else if *number == rpc.FinalizedBlockNumber {
|
||||||
|
header = api.parlia.GetFinalizedHeader(api.chain, currentHeader)
|
||||||
|
} else if *number == rpc.PendingBlockNumber {
|
||||||
|
return nil // no pending blocks on bsc
|
||||||
|
} else if *number == rpc.EarliestBlockNumber {
|
||||||
|
header = api.chain.GetHeaderByNumber(0)
|
||||||
|
} else {
|
||||||
|
header = api.chain.GetHeaderByNumber(uint64(number.Int64()))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
91
consensus/parlia/bohrFork.go
Normal file
91
consensus/parlia/bohrFork.go
Normal 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
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
@@ -54,10 +55,12 @@ const (
|
|||||||
|
|
||||||
checkpointInterval = 1024 // Number of blocks after which to save the snapshot to the database
|
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
|
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
|
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
|
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.
|
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
|
validatorBytesLengthBeforeLuban = common.AddressLength
|
||||||
validatorBytesLength = common.AddressLength + types.BLSPublicKeyLength
|
validatorBytesLength = common.AddressLength + types.BLSPublicKeyLength
|
||||||
@@ -126,6 +129,10 @@ var (
|
|||||||
// invalid list of validators (i.e. non divisible by 20 bytes).
|
// invalid list of validators (i.e. non divisible by 20 bytes).
|
||||||
errInvalidSpanValidators = errors.New("invalid validator list on sprint end block")
|
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 is returned if a block's mix digest is non-zero.
|
||||||
errInvalidMixDigest = errors.New("non-zero mix digest")
|
errInvalidMixDigest = errors.New("non-zero mix digest")
|
||||||
|
|
||||||
@@ -136,6 +143,10 @@ var (
|
|||||||
// list of validators different than the one the local node calculated.
|
// list of validators different than the one the local node calculated.
|
||||||
errMismatchingEpochValidators = errors.New("mismatching validator list on epoch block")
|
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 is returned if the difficulty of a block is missing.
|
||||||
errInvalidDifficulty = errors.New("invalid difficulty")
|
errInvalidDifficulty = errors.New("invalid difficulty")
|
||||||
|
|
||||||
@@ -369,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.
|
// 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---|
|
// 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 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 {
|
func getValidatorBytesFromHeader(header *types.Header, chainConfig *params.ChainConfig, parliaConfig *params.ParliaConfig) []byte {
|
||||||
if len(header.Extra) <= extraVanity+extraSeal {
|
if len(header.Extra) <= extraVanity+extraSeal {
|
||||||
return nil
|
return nil
|
||||||
@@ -385,11 +397,15 @@ func getValidatorBytesFromHeader(header *types.Header, chainConfig *params.Chain
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
num := int(header.Extra[extraVanity])
|
num := int(header.Extra[extraVanity])
|
||||||
if num == 0 || len(header.Extra) <= extraVanity+extraSeal+num*validatorBytesLength {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
start := extraVanity + validatorNumberSize
|
start := extraVanity + validatorNumberSize
|
||||||
end := start + num*validatorBytesLength
|
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]
|
return header.Extra[start:end]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,11 +424,14 @@ func getVoteAttestationFromHeader(header *types.Header, chainConfig *params.Chai
|
|||||||
attestationBytes = header.Extra[extraVanity : len(header.Extra)-extraSeal]
|
attestationBytes = header.Extra[extraVanity : len(header.Extra)-extraSeal]
|
||||||
} else {
|
} else {
|
||||||
num := int(header.Extra[extraVanity])
|
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
|
return nil, nil
|
||||||
}
|
}
|
||||||
start := extraVanity + validatorNumberSize + num*validatorBytesLength
|
|
||||||
end := len(header.Extra) - extraSeal
|
|
||||||
attestationBytes = header.Extra[start:end]
|
attestationBytes = header.Extra[start:end]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -604,15 +623,11 @@ func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
|
|||||||
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
|
return fmt.Errorf("invalid excessBlobGas: have %d, expected nil", header.ExcessBlobGas)
|
||||||
case header.BlobGasUsed != nil:
|
case header.BlobGasUsed != nil:
|
||||||
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
|
return fmt.Errorf("invalid blobGasUsed: have %d, expected nil", header.BlobGasUsed)
|
||||||
case header.ParentBeaconRoot != nil:
|
|
||||||
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
|
|
||||||
case header.WithdrawalsHash != nil:
|
case header.WithdrawalsHash != nil:
|
||||||
return fmt.Errorf("invalid WithdrawalsHash, have %#x, expected nil", header.WithdrawalsHash)
|
return fmt.Errorf("invalid WithdrawalsHash, have %#x, expected nil", header.WithdrawalsHash)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch {
|
switch {
|
||||||
case header.ParentBeaconRoot != nil:
|
|
||||||
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
|
|
||||||
case !header.EmptyWithdrawalsHash():
|
case !header.EmptyWithdrawalsHash():
|
||||||
return errors.New("header has wrong WithdrawalsHash")
|
return errors.New("header has wrong WithdrawalsHash")
|
||||||
}
|
}
|
||||||
@@ -621,6 +636,17 @@ func (p *Parlia) verifyHeader(chain consensus.ChainHeaderReader, header *types.H
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bohr := chain.Config().IsBohr(header.Number, header.Time)
|
||||||
|
if !bohr {
|
||||||
|
if header.ParentBeaconRoot != nil {
|
||||||
|
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected nil", header.ParentBeaconRoot)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if header.ParentBeaconRoot == nil || *header.ParentBeaconRoot != (common.Hash{}) {
|
||||||
|
return fmt.Errorf("invalid parentBeaconRoot, have %#x, expected zero hash", header.ParentBeaconRoot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// All basic checks passed, verify cascading fields
|
// All basic checks passed, verify cascading fields
|
||||||
return p.verifyCascadingFields(chain, header, parents)
|
return p.verifyCascadingFields(chain, header, parents)
|
||||||
}
|
}
|
||||||
@@ -888,6 +914,24 @@ func (p *Parlia) prepareValidators(header *types.Header) error {
|
|||||||
return nil
|
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 {
|
func (p *Parlia) assembleVoteAttestation(chain consensus.ChainHeaderReader, header *types.Header) error {
|
||||||
if !p.chainConfig.IsLuban(header.Number) || header.Number.Uint64() < 2 {
|
if !p.chainConfig.IsLuban(header.Number) || header.Number.Uint64() < 2 {
|
||||||
return nil
|
return nil
|
||||||
@@ -1019,6 +1063,9 @@ func (p *Parlia) Prepare(chain consensus.ChainHeaderReader, header *types.Header
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := p.prepareTurnLength(chain, header); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// add extra seal space
|
// add extra seal space
|
||||||
header.Extra = append(header.Extra, make([]byte, extraSeal)...)
|
header.Extra = append(header.Extra, make([]byte, extraSeal)...)
|
||||||
|
|
||||||
@@ -1069,6 +1116,30 @@ func (p *Parlia) verifyValidators(header *types.Header) error {
|
|||||||
return nil
|
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,
|
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,
|
cx core.ChainContext, txs *[]*types.Transaction, receipts *[]*types.Receipt, systemTxs *[]*types.Transaction,
|
||||||
usedGas *uint64, mining bool) error {
|
usedGas *uint64, mining bool) error {
|
||||||
@@ -1163,6 +1234,10 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := p.verifyTurnLength(chain, header); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
cx := chainContext{Chain: chain, parlia: p}
|
cx := chainContext{Chain: chain, parlia: p}
|
||||||
|
|
||||||
parent := chain.GetHeaderByHash(header.ParentHash)
|
parent := chain.GetHeaderByHash(header.ParentHash)
|
||||||
@@ -1189,7 +1264,7 @@ func (p *Parlia) Finalize(chain consensus.ChainHeaderReader, header *types.Heade
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if header.Difficulty.Cmp(diffInTurn) != 0 {
|
if header.Difficulty.Cmp(diffInTurn) != 0 {
|
||||||
spoiledVal := snap.supposeValidator()
|
spoiledVal := snap.inturnValidator()
|
||||||
signedRecently := false
|
signedRecently := false
|
||||||
if p.chainConfig.IsPlato(header.Number) {
|
if p.chainConfig.IsPlato(header.Number) {
|
||||||
signedRecently = snap.SignRecently(spoiledVal)
|
signedRecently = snap.SignRecently(spoiledVal)
|
||||||
@@ -1280,7 +1355,7 @@ func (p *Parlia) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
spoiledVal := snap.supposeValidator()
|
spoiledVal := snap.inturnValidator()
|
||||||
signedRecently := false
|
signedRecently := false
|
||||||
if p.chainConfig.IsPlato(header.Number) {
|
if p.chainConfig.IsPlato(header.Number) {
|
||||||
signedRecently = snap.SignRecently(spoiledVal)
|
signedRecently = snap.SignRecently(spoiledVal)
|
||||||
@@ -1362,7 +1437,7 @@ func (p *Parlia) IsActiveValidatorAt(chain consensus.ChainHeaderReader, header *
|
|||||||
func (p *Parlia) VerifyVote(chain consensus.ChainHeaderReader, vote *types.VoteEnvelope) error {
|
func (p *Parlia) VerifyVote(chain consensus.ChainHeaderReader, vote *types.VoteEnvelope) error {
|
||||||
targetNumber := vote.Data.TargetNumber
|
targetNumber := vote.Data.TargetNumber
|
||||||
targetHash := vote.Data.TargetHash
|
targetHash := vote.Data.TargetHash
|
||||||
header := chain.GetHeaderByHash(targetHash)
|
header := chain.GetVerifiedBlockByHash(targetHash)
|
||||||
if header == nil {
|
if header == nil {
|
||||||
log.Warn("BlockHeader at current voteBlockNumber is nil", "targetNumber", targetNumber, "targetHash", targetHash)
|
log.Warn("BlockHeader at current voteBlockNumber is nil", "targetNumber", targetNumber, "targetHash", targetHash)
|
||||||
return errors.New("BlockHeader at current voteBlockNumber is nil")
|
return errors.New("BlockHeader at current voteBlockNumber is nil")
|
||||||
@@ -1433,10 +1508,13 @@ func (p *Parlia) Delay(chain consensus.ChainReader, header *types.Header, leftOv
|
|||||||
delay = delay - *leftOver
|
delay = delay - *leftOver
|
||||||
}
|
}
|
||||||
|
|
||||||
// The blocking time should be no more than half of period
|
// The blocking time should be no more than half of period when snap.TurnLength == 1
|
||||||
half := time.Duration(p.config.Period) * time.Second / 2
|
timeForMining := time.Duration(p.config.Period) * time.Second / 2
|
||||||
if delay > half {
|
if !snap.lastBlockInOneTurn(header.Number.Uint64()) {
|
||||||
delay = half
|
timeForMining = time.Duration(p.config.Period) * time.Second * 2 / 3
|
||||||
|
}
|
||||||
|
if delay > timeForMining {
|
||||||
|
delay = timeForMining
|
||||||
}
|
}
|
||||||
return &delay
|
return &delay
|
||||||
}
|
}
|
||||||
@@ -1594,11 +1672,35 @@ func CalcDifficulty(snap *Snapshot, signer common.Address) *big.Int {
|
|||||||
return new(big.Int).Set(diffNoTurn)
|
return new(big.Int).Set(diffNoTurn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func encodeSigHeaderWithoutVoteAttestation(w io.Writer, header *types.Header, chainId *big.Int) {
|
||||||
|
err := rlp.Encode(w, []interface{}{
|
||||||
|
chainId,
|
||||||
|
header.ParentHash,
|
||||||
|
header.UncleHash,
|
||||||
|
header.Coinbase,
|
||||||
|
header.Root,
|
||||||
|
header.TxHash,
|
||||||
|
header.ReceiptHash,
|
||||||
|
header.Bloom,
|
||||||
|
header.Difficulty,
|
||||||
|
header.Number,
|
||||||
|
header.GasLimit,
|
||||||
|
header.GasUsed,
|
||||||
|
header.Time,
|
||||||
|
header.Extra[:extraVanity], // this will panic if extra is too short, should check before calling encodeSigHeaderWithoutVoteAttestation
|
||||||
|
header.MixDigest,
|
||||||
|
header.Nonce,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
panic("can't encode: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SealHash returns the hash of a block without vote attestation prior to it being sealed.
|
// SealHash returns the hash of a block without vote attestation prior to it being sealed.
|
||||||
// So it's not the real hash of a block, just used as unique id to distinguish task
|
// So it's not the real hash of a block, just used as unique id to distinguish task
|
||||||
func (p *Parlia) SealHash(header *types.Header) (hash common.Hash) {
|
func (p *Parlia) SealHash(header *types.Header) (hash common.Hash) {
|
||||||
hasher := sha3.NewLegacyKeccak256()
|
hasher := sha3.NewLegacyKeccak256()
|
||||||
types.EncodeSigHeaderWithoutVoteAttestation(hasher, header, p.chainConfig.ChainID)
|
encodeSigHeaderWithoutVoteAttestation(hasher, header, p.chainConfig.ChainID)
|
||||||
hasher.Sum(hash[:0])
|
hasher.Sum(hash[:0])
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
@@ -1904,42 +2006,40 @@ func (p *Parlia) GetFinalizedHeader(chain consensus.ChainHeaderReader, header *t
|
|||||||
// =========================== utility function ==========================
|
// =========================== utility function ==========================
|
||||||
func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Address) uint64 {
|
func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Address) uint64 {
|
||||||
if snap.inturn(val) {
|
if snap.inturn(val) {
|
||||||
|
log.Debug("backOffTime", "blockNumber", header.Number, "in turn validator", val)
|
||||||
return 0
|
return 0
|
||||||
} else {
|
} else {
|
||||||
delay := initialBackOffTime
|
delay := initialBackOffTime
|
||||||
validators := snap.validators()
|
validators := snap.validators()
|
||||||
if p.chainConfig.IsPlanck(header.Number) {
|
if p.chainConfig.IsPlanck(header.Number) {
|
||||||
// reverse the key/value of snap.Recents to get recentsMap
|
counts := snap.countRecents()
|
||||||
recentsMap := make(map[common.Address]uint64, len(snap.Recents))
|
for addr, seenTimes := range counts {
|
||||||
bound := uint64(0)
|
log.Debug("backOffTime", "blockNumber", header.Number, "validator", addr, "seenTimes", seenTimes)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The backOffTime does not matter when a validator has signed recently.
|
// The backOffTime does not matter when a validator has signed recently.
|
||||||
if _, ok := recentsMap[val]; ok {
|
if snap.signRecentlyByCounts(val, counts) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
inTurnAddr := validators[(snap.Number+1)%uint64(len(validators))]
|
inTurnAddr := snap.inturnValidator()
|
||||||
if _, ok := recentsMap[inTurnAddr]; ok {
|
if snap.signRecentlyByCounts(inTurnAddr, counts) {
|
||||||
log.Debug("in turn validator has recently signed, skip initialBackOffTime",
|
log.Debug("in turn validator has recently signed, skip initialBackOffTime",
|
||||||
"inTurnAddr", inTurnAddr)
|
"inTurnAddr", inTurnAddr)
|
||||||
delay = 0
|
delay = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exclude the recently signed validators
|
// Exclude the recently signed validators and the in turn validator
|
||||||
temp := make([]common.Address, 0, len(validators))
|
temp := make([]common.Address, 0, len(validators))
|
||||||
for _, addr := range validators {
|
for _, addr := range validators {
|
||||||
if _, ok := recentsMap[addr]; ok {
|
if snap.signRecentlyByCounts(addr, counts) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if p.chainConfig.IsBohr(header.Number, header.Time) {
|
||||||
|
if addr == inTurnAddr {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
temp = append(temp, addr)
|
temp = append(temp, addr)
|
||||||
}
|
}
|
||||||
validators = temp
|
validators = temp
|
||||||
@@ -1957,7 +2057,11 @@ func (p *Parlia) backOffTime(snap *Snapshot, header *types.Header, val common.Ad
|
|||||||
return 0
|
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)
|
r := rand.New(s)
|
||||||
n := len(validators)
|
n := len(validators)
|
||||||
backOffSteps := make([]uint64, 0, n)
|
backOffSteps := make([]uint64, 0, n)
|
||||||
|
|||||||
@@ -22,22 +22,44 @@ func TestImpactOfValidatorOutOfService(t *testing.T) {
|
|||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
totalValidators int
|
totalValidators int
|
||||||
downValidators int
|
downValidators int
|
||||||
|
turnLength int
|
||||||
}{
|
}{
|
||||||
{3, 1},
|
{3, 1, 1},
|
||||||
{5, 2},
|
{5, 2, 1},
|
||||||
{10, 1},
|
{10, 1, 2},
|
||||||
{10, 4},
|
{10, 4, 2},
|
||||||
{21, 1},
|
{21, 1, 3},
|
||||||
{21, 3},
|
{21, 3, 3},
|
||||||
{21, 5},
|
{21, 5, 4},
|
||||||
{21, 10},
|
{21, 10, 5},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
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
|
downBlocks := 10000
|
||||||
recoverBlocks := 10000
|
recoverBlocks := 10000
|
||||||
recents := make(map[uint64]int)
|
recents := make(map[uint64]int)
|
||||||
@@ -55,12 +77,7 @@ func simulateValidatorOutOfService(totalValidators int, downValidators int) {
|
|||||||
delete(validators, down[i])
|
delete(validators, down[i])
|
||||||
}
|
}
|
||||||
isRecentSign := func(idx int) bool {
|
isRecentSign := func(idx int) bool {
|
||||||
for _, signIdx := range recents {
|
return signRecently(idx, recents, turnLength)
|
||||||
if signIdx == idx {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
isInService := func(idx int) bool {
|
isInService := func(idx int) bool {
|
||||||
return validators[idx]
|
return validators[idx]
|
||||||
@@ -68,10 +85,10 @@ func simulateValidatorOutOfService(totalValidators int, downValidators int) {
|
|||||||
|
|
||||||
downDelay := uint64(0)
|
downDelay := uint64(0)
|
||||||
for h := 1; h <= downBlocks; h++ {
|
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)
|
delete(recents, uint64(h)-limit)
|
||||||
}
|
}
|
||||||
proposer := h % totalValidators
|
proposer := inturnValidator(totalValidators, turnLength, h)
|
||||||
if !isInService(proposer) || isRecentSign(proposer) {
|
if !isInService(proposer) || isRecentSign(proposer) {
|
||||||
candidates := make(map[int]bool, totalValidators/2)
|
candidates := make(map[int]bool, totalValidators/2)
|
||||||
for v := range validators {
|
for v := range validators {
|
||||||
@@ -99,10 +116,10 @@ func simulateValidatorOutOfService(totalValidators int, downValidators int) {
|
|||||||
recoverDelay := uint64(0)
|
recoverDelay := uint64(0)
|
||||||
lastseen := downBlocks
|
lastseen := downBlocks
|
||||||
for h := downBlocks + 1; h <= downBlocks+recoverBlocks; h++ {
|
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)
|
delete(recents, uint64(h)-limit)
|
||||||
}
|
}
|
||||||
proposer := h % totalValidators
|
proposer := inturnValidator(totalValidators, turnLength, h)
|
||||||
if !isInService(proposer) || isRecentSign(proposer) {
|
if !isInService(proposer) || isRecentSign(proposer) {
|
||||||
lastseen = h
|
lastseen = h
|
||||||
candidates := make(map[int]bool, totalValidators/2)
|
candidates := make(map[int]bool, totalValidators/2)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
lru "github.com/hashicorp/golang-lru"
|
lru "github.com/hashicorp/golang-lru"
|
||||||
@@ -43,6 +44,7 @@ type Snapshot struct {
|
|||||||
|
|
||||||
Number uint64 `json:"number"` // Block number where the snapshot was created
|
Number uint64 `json:"number"` // Block number where the snapshot was created
|
||||||
Hash common.Hash `json:"hash"` // Block hash 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
|
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
|
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
|
RecentForkHashes map[uint64]string `json:"recent_fork_hashes"` // Set of recent forkHash
|
||||||
@@ -72,6 +74,7 @@ func newSnapshot(
|
|||||||
sigCache: sigCache,
|
sigCache: sigCache,
|
||||||
Number: number,
|
Number: number,
|
||||||
Hash: hash,
|
Hash: hash,
|
||||||
|
TurnLength: defaultTurnLength,
|
||||||
Recents: make(map[uint64]common.Address),
|
Recents: make(map[uint64]common.Address),
|
||||||
RecentForkHashes: make(map[uint64]string),
|
RecentForkHashes: make(map[uint64]string),
|
||||||
Validators: make(map[common.Address]*ValidatorInfo),
|
Validators: make(map[common.Address]*ValidatorInfo),
|
||||||
@@ -114,6 +117,10 @@ func loadSnapshot(config *params.ParliaConfig, sigCache *lru.ARCCache, db ethdb.
|
|||||||
if err := json.Unmarshal(blob, snap); err != nil {
|
if err := json.Unmarshal(blob, snap); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if snap.TurnLength == 0 { // no TurnLength field in old snapshots
|
||||||
|
snap.TurnLength = defaultTurnLength
|
||||||
|
}
|
||||||
|
|
||||||
snap.config = config
|
snap.config = config
|
||||||
snap.sigCache = sigCache
|
snap.sigCache = sigCache
|
||||||
snap.ethAPI = ethAPI
|
snap.ethAPI = ethAPI
|
||||||
@@ -138,6 +145,7 @@ func (s *Snapshot) copy() *Snapshot {
|
|||||||
sigCache: s.sigCache,
|
sigCache: s.sigCache,
|
||||||
Number: s.Number,
|
Number: s.Number,
|
||||||
Hash: s.Hash,
|
Hash: s.Hash,
|
||||||
|
TurnLength: s.TurnLength,
|
||||||
Validators: make(map[common.Address]*ValidatorInfo),
|
Validators: make(map[common.Address]*ValidatorInfo),
|
||||||
Recents: make(map[uint64]common.Address),
|
Recents: make(map[uint64]common.Address),
|
||||||
RecentForkHashes: make(map[uint64]string),
|
RecentForkHashes: make(map[uint64]string),
|
||||||
@@ -210,17 +218,45 @@ func (s *Snapshot) updateAttestation(header *types.Header, chainConfig *params.C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Snapshot) SignRecently(validator common.Address) bool {
|
func (s *Snapshot) versionHistoryCheckLen() uint64 {
|
||||||
for seen, recent := range s.Recents {
|
return uint64(len(s.Validators)) * uint64(s.TurnLength)
|
||||||
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) 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
|
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) {
|
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
|
// Allow passing in no headers for cleaner code
|
||||||
if len(headers) == 0 {
|
if len(headers) == 0 {
|
||||||
@@ -247,10 +283,10 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
|
|||||||
for _, header := range headers {
|
for _, header := range headers {
|
||||||
number := header.Number.Uint64()
|
number := header.Number.Uint64()
|
||||||
// Delete the oldest validator from the recent list to allow it signing again
|
// 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)
|
delete(snap.Recents, number-limit)
|
||||||
}
|
}
|
||||||
if limit := uint64(len(snap.Validators)); number >= limit {
|
if limit := snap.versionHistoryCheckLen(); number >= limit {
|
||||||
delete(snap.RecentForkHashes, number-limit)
|
delete(snap.RecentForkHashes, number-limit)
|
||||||
}
|
}
|
||||||
// Resolve the authorization key and check against signers
|
// Resolve the authorization key and check against signers
|
||||||
@@ -261,19 +297,47 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
|
|||||||
if _, ok := snap.Validators[validator]; !ok {
|
if _, ok := snap.Validators[validator]; !ok {
|
||||||
return nil, errUnauthorizedValidator(validator.String())
|
return nil, errUnauthorizedValidator(validator.String())
|
||||||
}
|
}
|
||||||
for _, recent := range snap.Recents {
|
if chainConfig.IsBohr(header.Number, header.Time) {
|
||||||
if recent == validator {
|
if snap.SignRecently(validator) {
|
||||||
return nil, errRecentlySigned
|
return nil, errRecentlySigned
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
for _, recent := range snap.Recents {
|
||||||
|
if recent == validator {
|
||||||
|
return nil, errRecentlySigned
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
snap.Recents[number] = validator
|
snap.Recents[number] = validator
|
||||||
|
snap.RecentForkHashes[number] = hex.EncodeToString(header.Extra[extraVanity-nextForkHashSize : extraVanity])
|
||||||
|
snap.updateAttestation(header, chainConfig, s.config)
|
||||||
// change validator set
|
// change validator set
|
||||||
if number > 0 && number%s.config.Epoch == uint64(len(snap.Validators)/2) {
|
if number > 0 && number%s.config.Epoch == snap.minerHistoryCheckLen() {
|
||||||
checkpointHeader := FindAncientHeader(header, uint64(len(snap.Validators)/2), chain, parents)
|
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,
|
||||||
|
// then the unexpected second switch will happen, just skip it.
|
||||||
|
if _, ok := snap.Recents[epochKey]; ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checkpointHeader := FindAncientHeader(header, snap.minerHistoryCheckLen(), chain, parents)
|
||||||
if checkpointHeader == nil {
|
if checkpointHeader == nil {
|
||||||
return nil, consensus.ErrUnknownAncestor
|
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
|
// get validators from headers and use that for new validator set
|
||||||
newValArr, voteAddrs, err := parseValidators(checkpointHeader, chainConfig, s.config)
|
newValArr, voteAddrs, err := parseValidators(checkpointHeader, chainConfig, s.config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -289,18 +353,18 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
oldLimit := len(snap.Validators)/2 + 1
|
if chainConfig.IsBohr(header.Number, header.Time) {
|
||||||
newLimit := len(newVals)/2 + 1
|
// BEP-404: Clear Miner History when Switching Validators Set
|
||||||
if newLimit < oldLimit {
|
snap.Recents = make(map[uint64]common.Address)
|
||||||
for i := 0; i < oldLimit-newLimit; i++ {
|
snap.Recents[epochKey] = common.Address{}
|
||||||
delete(snap.Recents, number-uint64(newLimit)-uint64(i))
|
log.Debug("Recents are cleared up", "blockNumber", number)
|
||||||
}
|
} else {
|
||||||
}
|
oldLimit := len(snap.Validators)/2 + 1
|
||||||
oldLimit = len(snap.Validators)
|
newLimit := len(newVals)/2 + 1
|
||||||
newLimit = len(newVals)
|
if newLimit < oldLimit {
|
||||||
if newLimit < oldLimit {
|
for i := 0; i < oldLimit-newLimit; i++ {
|
||||||
for i := 0; i < oldLimit-newLimit; i++ {
|
delete(snap.Recents, number-uint64(newLimit)-uint64(i))
|
||||||
delete(snap.RecentForkHashes, number-uint64(newLimit)-uint64(i))
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
snap.Validators = newVals
|
snap.Validators = newVals
|
||||||
@@ -310,11 +374,10 @@ func (s *Snapshot) apply(headers []*types.Header, chain consensus.ChainHeaderRea
|
|||||||
snap.Validators[val].Index = idx + 1 // offset by 1
|
snap.Validators[val].Index = idx + 1 // offset by 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for i := snap.versionHistoryCheckLen(); i < oldVersionsLen; i++ {
|
||||||
|
delete(snap.RecentForkHashes, number-i)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
snap.updateAttestation(header, chainConfig, s.config)
|
|
||||||
|
|
||||||
snap.RecentForkHashes[number] = hex.EncodeToString(header.Extra[extraVanity-nextForkHashSize : extraVanity])
|
|
||||||
}
|
}
|
||||||
snap.Number += uint64(len(headers))
|
snap.Number += uint64(len(headers))
|
||||||
snap.Hash = headers[len(headers)-1].Hash()
|
snap.Hash = headers[len(headers)-1].Hash()
|
||||||
@@ -331,17 +394,20 @@ func (s *Snapshot) validators() []common.Address {
|
|||||||
return validators
|
return validators
|
||||||
}
|
}
|
||||||
|
|
||||||
// inturn returns if a validator at a given block height is in-turn or not.
|
// lastBlockInOneTurn returns if the block at height `blockNumber` is the last block in current turn.
|
||||||
func (s *Snapshot) inturn(validator common.Address) bool {
|
func (s *Snapshot) lastBlockInOneTurn(blockNumber uint64) bool {
|
||||||
validators := s.validators()
|
return (blockNumber+1)%uint64(s.TurnLength) == 0
|
||||||
offset := (s.Number + 1) % uint64(len(validators))
|
|
||||||
return validators[offset] == validator
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 {
|
func (s *Snapshot) inturnValidator() common.Address {
|
||||||
validators := s.validators()
|
validators := s.validators()
|
||||||
offset := (s.Number + 1) % uint64(len(validators))
|
offset := (s.Number + 1) / uint64(s.TurnLength) % uint64(len(validators))
|
||||||
return validators[offset]
|
return validators[offset]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,12 +445,6 @@ func (s *Snapshot) indexOfVal(validator common.Address) int {
|
|||||||
return -1
|
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) {
|
func parseValidators(header *types.Header, chainConfig *params.ChainConfig, parliaConfig *params.ParliaConfig) ([]common.Address, []types.BLSPublicKey, error) {
|
||||||
validatorsBytes := getValidatorBytesFromHeader(header, chainConfig, parliaConfig)
|
validatorsBytes := getValidatorBytesFromHeader(header, chainConfig, parliaConfig)
|
||||||
if len(validatorsBytes) == 0 {
|
if len(validatorsBytes) == 0 {
|
||||||
@@ -410,6 +470,24 @@ func parseValidators(header *types.Header, chainConfig *params.ChainConfig, parl
|
|||||||
return cnsAddrs, voteAddrs, nil
|
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 {
|
func FindAncientHeader(header *types.Header, ite uint64, chain consensus.ChainHeaderReader, candidateParents []*types.Header) *types.Header {
|
||||||
ancient := header
|
ancient := header
|
||||||
for i := uint64(1); i <= ite; i++ {
|
for i := uint64(1); i <= ite; i++ {
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
@@ -41,12 +40,6 @@ func EnableRemoteVerifyManager(remoteValidator *remoteVerifyManager) BlockValida
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
validateBloomTimer = metrics.NewRegisteredTimer("validate/bloom/time", nil)
|
|
||||||
validateReceiptTimer = metrics.NewRegisteredTimer("validate/receipt/time", nil)
|
|
||||||
validateRootTimer = metrics.NewRegisteredTimer("validate/root/time", nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
// BlockValidator is responsible for validating block headers, uncles and
|
// BlockValidator is responsible for validating block headers, uncles and
|
||||||
// processed state.
|
// processed state.
|
||||||
//
|
//
|
||||||
@@ -103,7 +96,7 @@ func ValidateListsInBody(block *types.Block) error {
|
|||||||
// validated at this point.
|
// validated at this point.
|
||||||
func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
// Check whether the block is already imported.
|
// Check whether the block is already imported.
|
||||||
if v.bc.HasBlockAndState(block.Hash(), block.Number().Int64()) {
|
if v.bc.HasBlockAndState(block.Hash(), block.NumberU64()) {
|
||||||
return ErrKnownBlock
|
return ErrKnownBlock
|
||||||
}
|
}
|
||||||
if v.bc.isCachedBadBlock(block) {
|
if v.bc.isCachedBadBlock(block) {
|
||||||
@@ -149,7 +142,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
func() error {
|
func() error {
|
||||||
if !v.bc.HasBlockAndState(block.ParentHash(), block.Number().Int64()-1) {
|
if !v.bc.HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
|
||||||
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
|
if !v.bc.HasBlock(block.ParentHash(), block.NumberU64()-1) {
|
||||||
return consensus.ErrUnknownAncestor
|
return consensus.ErrUnknownAncestor
|
||||||
}
|
}
|
||||||
@@ -191,10 +184,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||||||
// For valid blocks this should always validate to true.
|
// For valid blocks this should always validate to true.
|
||||||
validateFuns := []func() error{
|
validateFuns := []func() error{
|
||||||
func() error {
|
func() error {
|
||||||
defer func(start time.Time) {
|
|
||||||
validateBloomTimer.UpdateSince(start)
|
|
||||||
}(time.Now())
|
|
||||||
|
|
||||||
rbloom := types.CreateBloom(receipts)
|
rbloom := types.CreateBloom(receipts)
|
||||||
if rbloom != header.Bloom {
|
if rbloom != header.Bloom {
|
||||||
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
return fmt.Errorf("invalid bloom (remote: %x local: %x)", header.Bloom, rbloom)
|
||||||
@@ -202,9 +191,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
func() error {
|
func() error {
|
||||||
defer func(start time.Time) {
|
|
||||||
validateReceiptTimer.UpdateSince(start)
|
|
||||||
}(time.Now())
|
|
||||||
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
|
receiptSha := types.DeriveSha(receipts, trie.NewStackTrie(nil))
|
||||||
if receiptSha != header.ReceiptHash {
|
if receiptSha != header.ReceiptHash {
|
||||||
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
|
return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha)
|
||||||
@@ -223,9 +209,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
validateFuns = append(validateFuns, func() error {
|
validateFuns = append(validateFuns, func() error {
|
||||||
defer func(start time.Time) {
|
|
||||||
validateRootTimer.UpdateSince(start)
|
|
||||||
}(time.Now())
|
|
||||||
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
||||||
return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error())
|
return fmt.Errorf("invalid merkle root (remote: %x local: %x) dberr: %w", header.Root, root, statedb.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package core
|
|||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/ethereum/go-ethereum/triedb/versadb"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"runtime"
|
"runtime"
|
||||||
@@ -74,7 +75,6 @@ var (
|
|||||||
blockInsertMgaspsGauge = metrics.NewRegisteredGauge("chain/insert/mgasps", nil)
|
blockInsertMgaspsGauge = metrics.NewRegisteredGauge("chain/insert/mgasps", nil)
|
||||||
|
|
||||||
chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)
|
chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)
|
||||||
mGasPsGauge = metrics.NewRegisteredGauge("chain/process/gas", nil)
|
|
||||||
|
|
||||||
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
|
accountReadTimer = metrics.NewRegisteredTimer("chain/account/reads", nil)
|
||||||
accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
|
accountHashTimer = metrics.NewRegisteredTimer("chain/account/hashes", nil)
|
||||||
@@ -92,13 +92,10 @@ var (
|
|||||||
|
|
||||||
triedbCommitTimer = metrics.NewRegisteredTimer("chain/triedb/commits", nil)
|
triedbCommitTimer = metrics.NewRegisteredTimer("chain/triedb/commits", nil)
|
||||||
|
|
||||||
blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil)
|
blockInsertTimer = metrics.NewRegisteredTimer("chain/inserts", nil)
|
||||||
blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil)
|
blockValidationTimer = metrics.NewRegisteredTimer("chain/validation", nil)
|
||||||
blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil)
|
blockExecutionTimer = metrics.NewRegisteredTimer("chain/execution", nil)
|
||||||
blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil)
|
blockWriteTimer = metrics.NewRegisteredTimer("chain/write", nil)
|
||||||
blockValidationTotalTimer = metrics.NewRegisteredTimer("chain/total/validation", nil)
|
|
||||||
blockExecutionTotalTimer = metrics.NewRegisteredTimer("chain/total/execution", nil)
|
|
||||||
blockWriteTotalTimer = metrics.NewRegisteredTimer("chain/total/write", nil)
|
|
||||||
|
|
||||||
blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil)
|
blockReorgMeter = metrics.NewRegisteredMeter("chain/reorg/executes", nil)
|
||||||
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
|
blockReorgAddMeter = metrics.NewRegisteredMeter("chain/reorg/add", nil)
|
||||||
@@ -200,9 +197,10 @@ func (c *CacheConfig) triedbConfig() *triedb.Config {
|
|||||||
JournalFile: c.JournalFile,
|
JournalFile: c.JournalFile,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO:: support other versa db config items, currently use the default config
|
if c.StateScheme == rawdb.VersaScheme {
|
||||||
if c.StateScheme == rawdb.VersionScheme {
|
config.VersaDB = &versadb.Config{
|
||||||
config.IsVersion = true
|
CleanCacheSize: c.TrieCleanLimit * 1024 * 1024,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
@@ -267,23 +265,25 @@ type BlockChain struct {
|
|||||||
triesInMemory uint64
|
triesInMemory uint64
|
||||||
txIndexer *txIndexer // Transaction indexer, might be nil if not enabled
|
txIndexer *txIndexer // Transaction indexer, might be nil if not enabled
|
||||||
|
|
||||||
hc *HeaderChain
|
hc *HeaderChain
|
||||||
rmLogsFeed event.Feed
|
rmLogsFeed event.Feed
|
||||||
chainFeed event.Feed
|
chainFeed event.Feed
|
||||||
chainSideFeed event.Feed
|
chainSideFeed event.Feed
|
||||||
chainHeadFeed event.Feed
|
chainHeadFeed event.Feed
|
||||||
chainBlockFeed event.Feed
|
chainBlockFeed event.Feed
|
||||||
logsFeed event.Feed
|
logsFeed event.Feed
|
||||||
blockProcFeed event.Feed
|
blockProcFeed event.Feed
|
||||||
finalizedHeaderFeed event.Feed
|
finalizedHeaderFeed event.Feed
|
||||||
scope event.SubscriptionScope
|
highestVerifiedBlockFeed event.Feed
|
||||||
genesisBlock *types.Block
|
scope event.SubscriptionScope
|
||||||
|
genesisBlock *types.Block
|
||||||
|
|
||||||
// This mutex synchronizes chain write operations.
|
// This mutex synchronizes chain write operations.
|
||||||
// Readers don't need to take it, they can just read the database.
|
// Readers don't need to take it, they can just read the database.
|
||||||
chainmu *syncx.ClosableMutex
|
chainmu *syncx.ClosableMutex
|
||||||
|
|
||||||
highestVerifiedHeader atomic.Pointer[types.Header]
|
highestVerifiedHeader atomic.Pointer[types.Header]
|
||||||
|
highestVerifiedBlock atomic.Pointer[types.Header]
|
||||||
currentBlock atomic.Pointer[types.Header] // Current head of the chain
|
currentBlock atomic.Pointer[types.Header] // Current head of the chain
|
||||||
currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync
|
currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync
|
||||||
currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block
|
currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block
|
||||||
@@ -346,15 +346,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||||||
// Open trie database with provided config
|
// Open trie database with provided config
|
||||||
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig())
|
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig())
|
||||||
|
|
||||||
if triedb.Scheme() == rawdb.VersionScheme {
|
|
||||||
vdb := triedb.VersaDB()
|
|
||||||
ver, root := vdb.LatestStoreDiskVersionInfo()
|
|
||||||
if ver == -1 {
|
|
||||||
rawdb.WriteCanonicalHash(db, common.Hash{}, 0)
|
|
||||||
}
|
|
||||||
log.Info("version db latest version info", "version", ver, "root", root.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup the genesis block, commit the provided genesis specification
|
// Setup the genesis block, commit the provided genesis specification
|
||||||
// to database if the genesis block is not present yet, or load the
|
// to database if the genesis block is not present yet, or load the
|
||||||
// stored one from database.
|
// stored one from database.
|
||||||
@@ -401,7 +392,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||||||
}
|
}
|
||||||
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
|
bc.flushInterval.Store(int64(cacheConfig.TrieTimeLimit))
|
||||||
bc.forker = NewForkChoice(bc, shouldPreserve)
|
bc.forker = NewForkChoice(bc, shouldPreserve)
|
||||||
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb, true)
|
bc.stateCache = state.NewDatabaseWithNodeDB(bc.db, bc.triedb)
|
||||||
bc.validator = NewBlockValidator(chainConfig, bc, engine)
|
bc.validator = NewBlockValidator(chainConfig, bc, engine)
|
||||||
bc.prefetcher = NewStatePrefetcher(chainConfig, bc, engine)
|
bc.prefetcher = NewStatePrefetcher(chainConfig, bc, engine)
|
||||||
bc.processor = NewStateProcessor(chainConfig, bc, engine)
|
bc.processor = NewStateProcessor(chainConfig, bc, engine)
|
||||||
@@ -417,6 +408,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||||||
}
|
}
|
||||||
|
|
||||||
bc.highestVerifiedHeader.Store(nil)
|
bc.highestVerifiedHeader.Store(nil)
|
||||||
|
bc.highestVerifiedBlock.Store(nil)
|
||||||
bc.currentBlock.Store(nil)
|
bc.currentBlock.Store(nil)
|
||||||
bc.currentSnapBlock.Store(nil)
|
bc.currentSnapBlock.Store(nil)
|
||||||
bc.chasingHead.Store(nil)
|
bc.chasingHead.Store(nil)
|
||||||
@@ -437,138 +429,78 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
|
|||||||
// Make sure the state associated with the block is available, or log out
|
// Make sure the state associated with the block is available, or log out
|
||||||
// if there is no available state, waiting for state sync.
|
// if there is no available state, waiting for state sync.
|
||||||
head := bc.CurrentBlock()
|
head := bc.CurrentBlock()
|
||||||
if bc.triedb.Scheme() != rawdb.VersionScheme {
|
if !bc.HasState(head.Root) {
|
||||||
if !bc.HasState(head.Number.Int64(), head.Root) {
|
if head.Number.Uint64() == 0 {
|
||||||
if head.Number.Uint64() == 0 {
|
// The genesis state is missing, which is only possible in the path-based
|
||||||
// The genesis state is missing, which is only possible in the path-based
|
// scheme. This situation occurs when the initial state sync is not finished
|
||||||
// scheme. This situation occurs when the initial state sync is not finished
|
// yet, or the chain head is rewound below the pivot point. In both scenarios,
|
||||||
// yet, or the chain head is rewound below the pivot point. In both scenarios,
|
// there is no possible recovery approach except for rerunning a snap sync.
|
||||||
// there is no possible recovery approach except for rerunning a snap sync.
|
// Do nothing here until the state syncer picks it up.
|
||||||
// Do nothing here until the state syncer picks it up.
|
log.Info("Genesis state is missing, wait state sync")
|
||||||
log.Info("Genesis state is missing, wait state sync")
|
} else {
|
||||||
} else {
|
// Head state is missing, before the state recovery, find out the
|
||||||
// Head state is missing, before the state recovery, find out the
|
// disk layer point of snapshot(if it's enabled). Make sure the
|
||||||
// disk layer point of snapshot(if it's enabled). Make sure the
|
// rewound point is lower than disk layer.
|
||||||
// rewound point is lower than disk layer.
|
var diskRoot common.Hash
|
||||||
var diskRoot common.Hash
|
if bc.cacheConfig.SnapshotLimit > 0 {
|
||||||
if bc.cacheConfig.SnapshotLimit > 0 {
|
diskRoot = rawdb.ReadSnapshotRoot(bc.db)
|
||||||
diskRoot = rawdb.ReadSnapshotRoot(bc.db)
|
}
|
||||||
|
if bc.triedb.Scheme() == rawdb.PathScheme && !bc.NoTries() {
|
||||||
|
recoverable, _ := bc.triedb.Recoverable(diskRoot)
|
||||||
|
if !bc.HasState(diskRoot) && !recoverable {
|
||||||
|
diskRoot = bc.triedb.Head()
|
||||||
}
|
}
|
||||||
if bc.triedb.Scheme() == rawdb.PathScheme && !bc.NoTries() {
|
}
|
||||||
recoverable, _ := bc.triedb.Recoverable(diskRoot)
|
if diskRoot != (common.Hash{}) {
|
||||||
if !bc.HasState(0, diskRoot) && !recoverable {
|
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "diskRoot", diskRoot)
|
||||||
diskRoot = bc.triedb.Head()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if diskRoot != (common.Hash{}) {
|
|
||||||
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "diskRoot", diskRoot)
|
|
||||||
|
|
||||||
snapDisk, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, diskRoot, true)
|
snapDisk, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, diskRoot, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
|
||||||
// Chain rewound, persist old snapshot number to indicate recovery procedure
|
|
||||||
if snapDisk != 0 {
|
|
||||||
rawdb.WriteSnapshotRecoveryNumber(bc.db, snapDisk)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash())
|
|
||||||
if _, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, common.Hash{}, true); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
// Chain rewound, persist old snapshot number to indicate recovery procedure
|
||||||
}
|
if snapDisk != 0 {
|
||||||
} else {
|
rawdb.WriteSnapshotRecoveryNumber(bc.db, snapDisk)
|
||||||
log.Warn("versa db no recovery, rewind in load state")
|
|
||||||
}
|
|
||||||
// Ensure that a previous crash in SetHead doesn't leave extra ancients
|
|
||||||
if bc.triedb.Scheme() != rawdb.VersionScheme {
|
|
||||||
if frozen, err := bc.db.BlockStore().ItemAmountInAncient(); err == nil && frozen > 0 {
|
|
||||||
frozen, err = bc.db.BlockStore().Ancients()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
needRewind bool
|
|
||||||
low uint64
|
|
||||||
)
|
|
||||||
// The head full block may be rolled back to a very low height due to
|
|
||||||
// blockchain repair. If the head full block is even lower than the ancient
|
|
||||||
// chain, truncate the ancient store.
|
|
||||||
fullBlock := bc.CurrentBlock()
|
|
||||||
if fullBlock != nil && fullBlock.Hash() != bc.genesisBlock.Hash() && fullBlock.Number.Uint64() < frozen-1 {
|
|
||||||
needRewind = true
|
|
||||||
low = fullBlock.Number.Uint64()
|
|
||||||
}
|
|
||||||
// In snap sync, it may happen that ancient data has been written to the
|
|
||||||
// ancient store, but the LastFastBlock has not been updated, truncate the
|
|
||||||
// extra data here.
|
|
||||||
snapBlock := bc.CurrentSnapBlock()
|
|
||||||
if snapBlock != nil && snapBlock.Number.Uint64() < frozen-1 {
|
|
||||||
needRewind = true
|
|
||||||
if snapBlock.Number.Uint64() < low || low == 0 {
|
|
||||||
low = snapBlock.Number.Uint64()
|
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if needRewind {
|
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash())
|
||||||
log.Error("Truncating ancient chain", "from", bc.CurrentHeader().Number.Uint64(), "to", low)
|
if _, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, common.Hash{}, true); err != nil {
|
||||||
if err := bc.SetHead(low); err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Ensure that a previous crash in SetHead doesn't leave extra ancients
|
// Ensure that a previous crash in SetHead doesn't leave extra ancients
|
||||||
if bc.triedb.Scheme() != rawdb.VersionScheme {
|
if frozen, err := bc.db.BlockStore().ItemAmountInAncient(); err == nil && frozen > 0 {
|
||||||
if frozen, err := bc.db.BlockStore().ItemAmountInAncient(); err == nil && frozen > 0 {
|
frozen, err = bc.db.BlockStore().Ancients()
|
||||||
frozen, err = bc.db.BlockStore().Ancients()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var (
|
|
||||||
needRewind bool
|
|
||||||
low uint64
|
|
||||||
)
|
|
||||||
// The head full block may be rolled back to a very low height due to
|
|
||||||
// blockchain repair. If the head full block is even lower than the ancient
|
|
||||||
// chain, truncate the ancient store.
|
|
||||||
fullBlock := bc.CurrentBlock()
|
|
||||||
if fullBlock != nil && fullBlock.Hash() != bc.genesisBlock.Hash() && fullBlock.Number.Uint64() < frozen-1 {
|
|
||||||
needRewind = true
|
|
||||||
low = fullBlock.Number.Uint64()
|
|
||||||
}
|
|
||||||
// In snap sync, it may happen that ancient data has been written to the
|
|
||||||
// ancient store, but the LastFastBlock has not been updated, truncate the
|
|
||||||
// extra data here.
|
|
||||||
snapBlock := bc.CurrentSnapBlock()
|
|
||||||
if snapBlock != nil && snapBlock.Number.Uint64() < frozen-1 {
|
|
||||||
needRewind = true
|
|
||||||
if snapBlock.Number.Uint64() < low || low == 0 {
|
|
||||||
low = snapBlock.Number.Uint64()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if needRewind {
|
|
||||||
log.Error("Truncating ancient chain", "from", bc.CurrentHeader().Number.Uint64(), "to", low)
|
|
||||||
if err := bc.SetHead(low); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//TODO:: need consider the offline and inline prune block
|
|
||||||
frozen, err := bc.db.BlockStore().Ancients()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
items, err := bc.db.BlockStore().ItemAmountInAncient()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
var (
|
||||||
|
needRewind bool
|
||||||
|
low uint64
|
||||||
|
)
|
||||||
|
// The head full block may be rolled back to a very low height due to
|
||||||
|
// blockchain repair. If the head full block is even lower than the ancient
|
||||||
|
// chain, truncate the ancient store.
|
||||||
fullBlock := bc.CurrentBlock()
|
fullBlock := bc.CurrentBlock()
|
||||||
log.Info("version mode rewind ancient store", "target", fullBlock.Number.Uint64(), "old head", frozen, "items", items, "offset", bc.db.BlockStore().AncientOffSet())
|
if fullBlock != nil && fullBlock.Hash() != bc.genesisBlock.Hash() && fullBlock.Number.Uint64() < frozen-1 {
|
||||||
if frozen >= fullBlock.Number.Uint64() {
|
needRewind = true
|
||||||
if _, err = bc.db.BlockStore().TruncateTail(fullBlock.Number.Uint64()); err != nil {
|
low = fullBlock.Number.Uint64()
|
||||||
|
}
|
||||||
|
// In snap sync, it may happen that ancient data has been written to the
|
||||||
|
// ancient store, but the LastFastBlock has not been updated, truncate the
|
||||||
|
// extra data here.
|
||||||
|
snapBlock := bc.CurrentSnapBlock()
|
||||||
|
if snapBlock != nil && snapBlock.Number.Uint64() < frozen-1 {
|
||||||
|
needRewind = true
|
||||||
|
if snapBlock.Number.Uint64() < low || low == 0 {
|
||||||
|
low = snapBlock.Number.Uint64()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if needRewind {
|
||||||
|
log.Error("Truncating ancient chain", "from", bc.CurrentHeader().Number.Uint64(), "to", low)
|
||||||
|
if err := bc.SetHead(low); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -775,61 +707,20 @@ func (bc *BlockChain) getFinalizedNumber(header *types.Header) uint64 {
|
|||||||
// loadLastState loads the last known chain state from the database. This method
|
// loadLastState loads the last known chain state from the database. This method
|
||||||
// assumes that the chain manager mutex is held.
|
// assumes that the chain manager mutex is held.
|
||||||
func (bc *BlockChain) loadLastState() error {
|
func (bc *BlockChain) loadLastState() error {
|
||||||
// TODO:: before versa db support recovery, only rewind
|
// Restore the last known head block
|
||||||
var headBlock *types.Block
|
head := rawdb.ReadHeadBlockHash(bc.db)
|
||||||
if bc.triedb.Scheme() == rawdb.VersionScheme {
|
if head == (common.Hash{}) {
|
||||||
head := rawdb.ReadHeadBlockHash(bc.db)
|
// Corrupt or empty database, init from scratch
|
||||||
headBlock = bc.GetBlockByHash(head)
|
log.Warn("Empty database, resetting chain")
|
||||||
|
return bc.Reset()
|
||||||
versa := bc.triedb.VersaDB()
|
}
|
||||||
archiveVersion, archiveRoot := versa.LatestStoreDiskVersionInfo()
|
// Make sure the entire head block is available
|
||||||
// first start
|
headBlock := bc.GetBlockByHash(head)
|
||||||
if archiveVersion == -1 {
|
if headBlock == nil {
|
||||||
archiveVersion = 0
|
// Corrupt or empty database, init from scratch
|
||||||
archiveRoot = bc.genesisBlock.Root()
|
log.Warn("Head block missing, resetting chain", "hash", head)
|
||||||
}
|
return bc.Reset()
|
||||||
|
|
||||||
if int64(headBlock.NumberU64()) < archiveVersion {
|
|
||||||
log.Crit("versa db disk version large than header block", "head number", headBlock.NumberU64(), "versa archive number", archiveVersion)
|
|
||||||
}
|
|
||||||
log.Info("begin rewind versa db head", "target_number", archiveVersion, "target_root", archiveRoot.String(), "head_number", headBlock.NumberU64(), "head_root", headBlock.Root().String())
|
|
||||||
for {
|
|
||||||
if int64(headBlock.NumberU64()) == archiveVersion && archiveRoot.Cmp(headBlock.Root()) == 0 {
|
|
||||||
rawdb.WriteCanonicalHash(bc.db, headBlock.Hash(), headBlock.NumberU64())
|
|
||||||
rawdb.WriteHeadHeaderHash(bc.db, headBlock.Hash())
|
|
||||||
rawdb.WriteHeadBlockHash(bc.db, headBlock.Hash())
|
|
||||||
rawdb.WriteHeadFastBlockHash(bc.db, headBlock.Hash())
|
|
||||||
log.Info("reset versa db head block", "number", headBlock.NumberU64(), "hash", headBlock.Hash())
|
|
||||||
break
|
|
||||||
} else if int64(headBlock.NumberU64()) == archiveVersion {
|
|
||||||
log.Crit("rewinding meet same number", "target_number", archiveVersion, "target_root", archiveRoot.String(), "head_number", headBlock.NumberU64(), "head_root", headBlock.Root().String())
|
|
||||||
} else if archiveRoot.Cmp(headBlock.Root()) == 0 {
|
|
||||||
log.Info("rewinding meet same root", "target_number", archiveVersion, "target_root", archiveRoot.String(), "head_number", headBlock.NumberU64(), "head_root", headBlock.Root().String())
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Info("rewinding", "target_number", archiveVersion, "target_root", archiveRoot.String(), "head_number", headBlock.NumberU64(), "head_root", headBlock.Root().String())
|
|
||||||
headBlock = rawdb.ReadBlock(bc.db, headBlock.ParentHash(), headBlock.NumberU64()-1)
|
|
||||||
if headBlock == nil {
|
|
||||||
panic("versa db rewind head is nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Restore the last known head block
|
|
||||||
head := rawdb.ReadHeadBlockHash(bc.db)
|
|
||||||
if head == (common.Hash{}) {
|
|
||||||
// Corrupt or empty database, init from scratch
|
|
||||||
log.Warn("Empty database, resetting chain")
|
|
||||||
return bc.Reset()
|
|
||||||
}
|
|
||||||
// Make sure the entire head block is available
|
|
||||||
headBlock = bc.GetBlockByHash(head)
|
|
||||||
if headBlock == nil {
|
|
||||||
// Corrupt or empty database, init from scratch
|
|
||||||
log.Warn("Head block missing, resetting chain", "hash", head)
|
|
||||||
return bc.Reset()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
log.Info("load state head block", "number", headBlock.NumberU64())
|
|
||||||
|
|
||||||
// Everything seems to be fine, set as the head block
|
// Everything seems to be fine, set as the head block
|
||||||
bc.currentBlock.Store(headBlock.Header())
|
bc.currentBlock.Store(headBlock.Header())
|
||||||
@@ -998,7 +889,7 @@ func (bc *BlockChain) rewindHashHead(head *types.Header, root common.Hash) (*typ
|
|||||||
}
|
}
|
||||||
// If the associated state is not reachable, continue searching
|
// If the associated state is not reachable, continue searching
|
||||||
// backwards until an available state is found.
|
// backwards until an available state is found.
|
||||||
if !bc.HasState(head.Number.Int64(), head.Root) {
|
if !bc.HasState(head.Root) {
|
||||||
// If the chain is gapped in the middle, return the genesis
|
// If the chain is gapped in the middle, return the genesis
|
||||||
// block as the new chain head.
|
// block as the new chain head.
|
||||||
parent := bc.GetHeader(head.ParentHash, head.Number.Uint64()-1)
|
parent := bc.GetHeader(head.ParentHash, head.Number.Uint64()-1)
|
||||||
@@ -1038,7 +929,7 @@ func (bc *BlockChain) rewindPathHead(head *types.Header, root common.Hash) (*typ
|
|||||||
|
|
||||||
// noState represents if the target state requested for search
|
// noState represents if the target state requested for search
|
||||||
// is unavailable and impossible to be recovered.
|
// is unavailable and impossible to be recovered.
|
||||||
noState = !bc.HasState(head.Number.Int64(), root) && !bc.stateRecoverable(root)
|
noState = !bc.HasState(root) && !bc.stateRecoverable(root)
|
||||||
|
|
||||||
start = time.Now() // Timestamp the rewinding is restarted
|
start = time.Now() // Timestamp the rewinding is restarted
|
||||||
logged = time.Now() // Timestamp last progress log was printed
|
logged = time.Now() // Timestamp last progress log was printed
|
||||||
@@ -1059,13 +950,13 @@ func (bc *BlockChain) rewindPathHead(head *types.Header, root common.Hash) (*typ
|
|||||||
// If the root threshold hasn't been crossed but the available
|
// If the root threshold hasn't been crossed but the available
|
||||||
// state is reached, quickly determine if the target state is
|
// state is reached, quickly determine if the target state is
|
||||||
// possible to be reached or not.
|
// possible to be reached or not.
|
||||||
if !beyondRoot && noState && bc.HasState(head.Number.Int64(), head.Root) {
|
if !beyondRoot && noState && bc.HasState(head.Root) {
|
||||||
beyondRoot = true
|
beyondRoot = true
|
||||||
log.Info("Disable the search for unattainable state", "root", root)
|
log.Info("Disable the search for unattainable state", "root", root)
|
||||||
}
|
}
|
||||||
// Check if the associated state is available or recoverable if
|
// Check if the associated state is available or recoverable if
|
||||||
// the requested root has already been crossed.
|
// the requested root has already been crossed.
|
||||||
if beyondRoot && (bc.HasState(head.Number.Int64(), head.Root) || bc.stateRecoverable(head.Root)) {
|
if beyondRoot && (bc.HasState(head.Root) || bc.stateRecoverable(head.Root)) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// If pivot block is reached, return the genesis block as the
|
// If pivot block is reached, return the genesis block as the
|
||||||
@@ -1092,7 +983,7 @@ func (bc *BlockChain) rewindPathHead(head *types.Header, root common.Hash) (*typ
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Recover if the target state if it's not available yet.
|
// Recover if the target state if it's not available yet.
|
||||||
if !bc.HasState(head.Number.Int64(), head.Root) {
|
if !bc.HasState(head.Root) {
|
||||||
if err := bc.triedb.Recover(head.Root); err != nil {
|
if err := bc.triedb.Recover(head.Root); err != nil {
|
||||||
log.Crit("Failed to rollback state", "err", err)
|
log.Crit("Failed to rollback state", "err", err)
|
||||||
}
|
}
|
||||||
@@ -1187,7 +1078,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
|||||||
// the pivot point. In this scenario, there is no possible recovery
|
// the pivot point. In this scenario, there is no possible recovery
|
||||||
// approach except for rerunning a snap sync. Do nothing here until the
|
// approach except for rerunning a snap sync. Do nothing here until the
|
||||||
// state syncer picks it up.
|
// state syncer picks it up.
|
||||||
if !bc.HasState(newHeadBlock.Number.Int64(), newHeadBlock.Root) {
|
if !bc.HasState(newHeadBlock.Root) {
|
||||||
if newHeadBlock.Number.Uint64() != 0 {
|
if newHeadBlock.Number.Uint64() != 0 {
|
||||||
log.Crit("Chain is stateless at a non-genesis block")
|
log.Crit("Chain is stateless at a non-genesis block")
|
||||||
}
|
}
|
||||||
@@ -1283,10 +1174,6 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
|||||||
// SnapSyncCommitHead sets the current head block to the one defined by the hash
|
// SnapSyncCommitHead sets the current head block to the one defined by the hash
|
||||||
// irrelevant what the chain contents were prior.
|
// irrelevant what the chain contents were prior.
|
||||||
func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error {
|
func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error {
|
||||||
// TODO:: temporarily not support for snapsync
|
|
||||||
if bc.triedb.Scheme() == rawdb.VersionScheme {
|
|
||||||
panic("version db not support snap sync")
|
|
||||||
}
|
|
||||||
// Make sure that both the block as well at its state trie exists
|
// Make sure that both the block as well at its state trie exists
|
||||||
block := bc.GetBlockByHash(hash)
|
block := bc.GetBlockByHash(hash)
|
||||||
if block == nil {
|
if block == nil {
|
||||||
@@ -1299,7 +1186,7 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !bc.NoTries() && !bc.HasState(0, root) {
|
if !bc.NoTries() && !bc.HasState(root) {
|
||||||
return fmt.Errorf("non existent state [%x..]", root[:4])
|
return fmt.Errorf("non existent state [%x..]", root[:4])
|
||||||
}
|
}
|
||||||
// If all checks out, manually set the head block.
|
// If all checks out, manually set the head block.
|
||||||
@@ -1498,51 +1385,49 @@ func (bc *BlockChain) Stop() {
|
|||||||
}
|
}
|
||||||
bc.snaps.Release()
|
bc.snaps.Release()
|
||||||
}
|
}
|
||||||
if bc.triedb.Scheme() != rawdb.VersionScheme {
|
if bc.triedb.Scheme() == rawdb.PathScheme {
|
||||||
if bc.triedb.Scheme() == rawdb.PathScheme {
|
// Ensure that the in-memory trie nodes are journaled to disk properly.
|
||||||
// Ensure that the in-memory trie nodes are journaled to disk properly.
|
if err := bc.triedb.Journal(bc.CurrentBlock().Root); err != nil {
|
||||||
if err := bc.triedb.Journal(bc.CurrentBlock().Root); err != nil {
|
log.Info("Failed to journal in-memory trie nodes", "err", err)
|
||||||
log.Info("Failed to journal in-memory trie nodes", "err", err)
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
// Ensure the state of a recent block is also stored to disk before exiting.
|
||||||
// Ensure the state of a recent block is also stored to disk before exiting.
|
// We're writing three different states to catch different restart scenarios:
|
||||||
// We're writing three different states to catch different restart scenarios:
|
// - HEAD: So we don't need to reprocess any blocks in the general case
|
||||||
// - HEAD: So we don't need to reprocess any blocks in the general case
|
// - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle
|
||||||
// - HEAD-1: So we don't do large reorgs if our HEAD becomes an uncle
|
// - HEAD-127: So we have a hard limit on the number of blocks reexecuted
|
||||||
// - HEAD-127: So we have a hard limit on the number of blocks reexecuted
|
if !bc.cacheConfig.TrieDirtyDisabled {
|
||||||
if !bc.cacheConfig.TrieDirtyDisabled {
|
triedb := bc.triedb
|
||||||
triedb := bc.triedb
|
var once sync.Once
|
||||||
var once sync.Once
|
for _, offset := range []uint64{0, 1, bc.TriesInMemory() - 1} {
|
||||||
for _, offset := range []uint64{0, 1, TriesInMemory - 1} {
|
if number := bc.CurrentBlock().Number.Uint64(); number > offset {
|
||||||
if number := bc.CurrentBlock().Number.Uint64(); number > offset {
|
recent := bc.GetBlockByNumber(number - offset)
|
||||||
recent := bc.GetBlockByNumber(number - offset)
|
log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root())
|
||||||
log.Info("Writing cached state to disk", "block", recent.Number(), "hash", recent.Hash(), "root", recent.Root())
|
if err := triedb.Commit(recent.Root(), true); err != nil {
|
||||||
if err := triedb.Commit(recent.Root(), true); err != nil {
|
|
||||||
log.Error("Failed to commit recent state trie", "err", err)
|
|
||||||
} else {
|
|
||||||
rawdb.WriteSafePointBlockNumber(bc.db, recent.NumberU64())
|
|
||||||
once.Do(func() {
|
|
||||||
rawdb.WriteHeadBlockHash(bc.db.BlockStore(), recent.Hash())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if snapBase != (common.Hash{}) {
|
|
||||||
log.Info("Writing snapshot state to disk", "root", snapBase)
|
|
||||||
if err := triedb.Commit(snapBase, true); err != nil {
|
|
||||||
log.Error("Failed to commit recent state trie", "err", err)
|
log.Error("Failed to commit recent state trie", "err", err)
|
||||||
} else {
|
} else {
|
||||||
rawdb.WriteSafePointBlockNumber(bc.db, bc.CurrentBlock().Number.Uint64())
|
rawdb.WriteSafePointBlockNumber(bc.db, recent.NumberU64())
|
||||||
|
once.Do(func() {
|
||||||
|
rawdb.WriteHeadBlockHash(bc.db.BlockStore(), recent.Hash())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for !bc.triegc.Empty() {
|
}
|
||||||
triedb.Dereference(bc.triegc.PopItem())
|
|
||||||
}
|
if snapBase != (common.Hash{}) {
|
||||||
if _, size, _, _ := triedb.Size(); size != 0 {
|
log.Info("Writing snapshot state to disk", "root", snapBase)
|
||||||
log.Error("Dangling trie nodes after full cleanup")
|
if err := triedb.Commit(snapBase, true); err != nil {
|
||||||
|
log.Error("Failed to commit recent state trie", "err", err)
|
||||||
|
} else {
|
||||||
|
rawdb.WriteSafePointBlockNumber(bc.db, bc.CurrentBlock().Number.Uint64())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for !bc.triegc.Empty() {
|
||||||
|
triedb.Dereference(bc.triegc.PopItem())
|
||||||
|
}
|
||||||
|
if _, size, _, _ := triedb.Size(); size != 0 {
|
||||||
|
log.Error("Dangling trie nodes after full cleanup")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Close the trie database, release all the held resources as the last step.
|
// Close the trie database, release all the held resources as the last step.
|
||||||
@@ -1937,7 +1822,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
|||||||
|
|
||||||
// If node is running in path mode, skip explicit gc operation
|
// If node is running in path mode, skip explicit gc operation
|
||||||
// which is unnecessary in this mode.
|
// which is unnecessary in this mode.
|
||||||
if bc.triedb.Scheme() != rawdb.HashScheme {
|
if bc.triedb.Scheme() == rawdb.PathScheme {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1952,7 +1837,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
|
|||||||
|
|
||||||
// Flush limits are not considered for the first TriesInMemory blocks.
|
// Flush limits are not considered for the first TriesInMemory blocks.
|
||||||
current := block.NumberU64()
|
current := block.NumberU64()
|
||||||
if current <= TriesInMemory {
|
if current <= bc.TriesInMemory() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// If we exceeded our memory allowance, flush matured singleton nodes to disk
|
// If we exceeded our memory allowance, flush matured singleton nodes to disk
|
||||||
@@ -2050,14 +1935,19 @@ func (bc *BlockChain) WriteBlockAndSetHead(block *types.Block, receipts []*types
|
|||||||
// writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead.
|
// writeBlockAndSetHead is the internal implementation of WriteBlockAndSetHead.
|
||||||
// This function expects the chain mutex to be held.
|
// 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) (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 err := bc.writeBlockWithState(block, receipts, state); err != nil {
|
|
||||||
return NonStatTy, err
|
|
||||||
}
|
|
||||||
currentBlock := bc.CurrentBlock()
|
currentBlock := bc.CurrentBlock()
|
||||||
reorg, err := bc.forker.ReorgNeededWithFastFinality(currentBlock, block.Header())
|
reorg, err := bc.forker.ReorgNeededWithFastFinality(currentBlock, block.Header())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return NonStatTy, err
|
return NonStatTy, err
|
||||||
}
|
}
|
||||||
|
if reorg {
|
||||||
|
bc.highestVerifiedBlock.Store(types.CopyHeader(block.Header()))
|
||||||
|
bc.highestVerifiedBlockFeed.Send(HighestVerifiedBlockEvent{Header: block.Header()})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := bc.writeBlockWithState(block, receipts, state); err != nil {
|
||||||
|
return NonStatTy, err
|
||||||
|
}
|
||||||
if reorg {
|
if reorg {
|
||||||
// Reorganise the chain if the parent is not the head block
|
// Reorganise the chain if the parent is not the head block
|
||||||
if block.ParentHash() != currentBlock.Hash() {
|
if block.ParentHash() != currentBlock.Hash() {
|
||||||
@@ -2356,29 +2246,27 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||||||
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
bc.stateCache.SetVersion(int64(block.NumberU64()) - 1)
|
|
||||||
statedb, err := state.NewWithSharedPool(parent.Root, bc.stateCache, bc.snaps)
|
statedb, err := state.NewWithSharedPool(parent.Root, bc.stateCache, bc.snaps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bc.stateCache.Release()
|
|
||||||
return it.index, err
|
return it.index, err
|
||||||
}
|
}
|
||||||
bc.updateHighestVerifiedHeader(block.Header())
|
bc.updateHighestVerifiedHeader(block.Header())
|
||||||
|
|
||||||
// Enable prefetching to pull in trie node paths while processing transactions
|
// Enable prefetching to pull in trie node paths while processing transactions
|
||||||
//statedb.StartPrefetcher("chain")
|
statedb.StartPrefetcher("chain")
|
||||||
interruptCh := make(chan struct{})
|
interruptCh := make(chan struct{})
|
||||||
// For diff sync, it may fallback to full sync, so we still do prefetch
|
// For diff sync, it may fallback to full sync, so we still do prefetch
|
||||||
if len(block.Transactions()) >= prefetchTxNumber {
|
if len(block.Transactions()) >= prefetchTxNumber {
|
||||||
// do Prefetch in a separate goroutine to avoid blocking the critical path
|
// do Prefetch in a separate goroutine to avoid blocking the critical path
|
||||||
|
|
||||||
//1.do state prefetch for snapshot cache
|
// 1.do state prefetch for snapshot cache
|
||||||
throwaway := statedb.CopyDoPrefetch()
|
throwaway := statedb.CopyDoPrefetch()
|
||||||
go bc.prefetcher.Prefetch(block, throwaway, &bc.vmConfig, interruptCh)
|
go bc.prefetcher.Prefetch(block, throwaway, &bc.vmConfig, interruptCh)
|
||||||
|
|
||||||
// // 2.do trie prefetch for MPT trie node cache
|
// 2.do trie prefetch for MPT trie node cache
|
||||||
// // it is for the big state trie tree, prefetch based on transaction's From/To address.
|
// it is for the big state trie tree, prefetch based on transaction's From/To address.
|
||||||
// // trie prefetcher is thread safe now, ok to prefetch in a separate routine
|
// trie prefetcher is thread safe now, ok to prefetch in a separate routine
|
||||||
// go throwaway.TriePrefetchInAdvance(block, signer)
|
go throwaway.TriePrefetchInAdvance(block, signer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process block using the parent state as reference point
|
// Process block using the parent state as reference point
|
||||||
@@ -2390,25 +2278,20 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||||||
statedb, receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
|
statedb, receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig)
|
||||||
close(interruptCh) // state prefetch can be stopped
|
close(interruptCh) // state prefetch can be stopped
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bc.stateCache.Release()
|
|
||||||
bc.reportBlock(block, receipts, err)
|
bc.reportBlock(block, receipts, err)
|
||||||
statedb.StopPrefetcher()
|
statedb.StopPrefetcher()
|
||||||
return it.index, err
|
return it.index, err
|
||||||
}
|
}
|
||||||
blockExecutionTotalTimer.UpdateSince(pstart)
|
|
||||||
|
|
||||||
ptime := time.Since(pstart)
|
ptime := time.Since(pstart)
|
||||||
|
|
||||||
// Validate the state using the default validator
|
// Validate the state using the default validator
|
||||||
vstart := time.Now()
|
vstart := time.Now()
|
||||||
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
|
if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil {
|
||||||
bc.stateCache.Release()
|
log.Error("validate state failed", "error", err)
|
||||||
bc.reportBlock(block, receipts, err)
|
bc.reportBlock(block, receipts, err)
|
||||||
statedb.StopPrefetcher()
|
statedb.StopPrefetcher()
|
||||||
return it.index, err
|
return it.index, err
|
||||||
}
|
}
|
||||||
blockValidationTotalTimer.UpdateSince(vstart)
|
|
||||||
|
|
||||||
vtime := time.Since(vstart)
|
vtime := time.Since(vstart)
|
||||||
proctime := time.Since(start) // processing + validation
|
proctime := time.Since(start) // processing + validation
|
||||||
|
|
||||||
@@ -2440,11 +2323,8 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
|
|||||||
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
|
status, err = bc.writeBlockAndSetHead(block, receipts, logs, statedb, false)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
bc.stateCache.Release()
|
|
||||||
return it.index, err
|
return it.index, err
|
||||||
}
|
}
|
||||||
bc.stateCache.Release()
|
|
||||||
blockWriteTotalTimer.UpdateSince(wstart)
|
|
||||||
|
|
||||||
bc.cacheReceipts(block.Hash(), receipts, block)
|
bc.cacheReceipts(block.Hash(), receipts, block)
|
||||||
|
|
||||||
@@ -2624,7 +2504,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
|
|||||||
numbers []uint64
|
numbers []uint64
|
||||||
)
|
)
|
||||||
parent := it.previous()
|
parent := it.previous()
|
||||||
for parent != nil && !bc.HasState(parent.Number.Int64(), parent.Root) {
|
for parent != nil && !bc.HasState(parent.Root) {
|
||||||
if bc.stateRecoverable(parent.Root) {
|
if bc.stateRecoverable(parent.Root) {
|
||||||
if err := bc.triedb.Recover(parent.Root); err != nil {
|
if err := bc.triedb.Recover(parent.Root); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
@@ -2691,7 +2571,7 @@ func (bc *BlockChain) recoverAncestors(block *types.Block) (common.Hash, error)
|
|||||||
numbers []uint64
|
numbers []uint64
|
||||||
parent = block
|
parent = block
|
||||||
)
|
)
|
||||||
for parent != nil && !bc.HasState(parent.Number().Int64(), parent.Root()) {
|
for parent != nil && !bc.HasState(parent.Root()) {
|
||||||
if bc.stateRecoverable(parent.Root()) {
|
if bc.stateRecoverable(parent.Root()) {
|
||||||
if err := bc.triedb.Recover(parent.Root()); err != nil {
|
if err := bc.triedb.Recover(parent.Root()); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
@@ -2962,7 +2842,7 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) {
|
|||||||
defer bc.chainmu.Unlock()
|
defer bc.chainmu.Unlock()
|
||||||
|
|
||||||
// Re-execute the reorged chain in case the head state is missing.
|
// Re-execute the reorged chain in case the head state is missing.
|
||||||
if !bc.HasState(head.Number().Int64(), head.Root()) {
|
if !bc.HasState(head.Root()) {
|
||||||
if latestValidHash, err := bc.recoverAncestors(head); err != nil {
|
if latestValidHash, err := bc.recoverAncestors(head); err != nil {
|
||||||
return latestValidHash, err
|
return latestValidHash, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ func (st *insertStats) report(chain []*types.Block, index int, snapDiffItems, sn
|
|||||||
"blocks", st.processed, "txs", txs, "blobs", blobs, "mgas", float64(st.usedGas) / 1000000,
|
"blocks", st.processed, "txs", txs, "blobs", blobs, "mgas", float64(st.usedGas) / 1000000,
|
||||||
"elapsed", common.PrettyDuration(elapsed), "mgasps", mgasps,
|
"elapsed", common.PrettyDuration(elapsed), "mgasps", mgasps,
|
||||||
}
|
}
|
||||||
mGasPsGauge.Update(int64(mgasps))
|
|
||||||
blockInsertMgaspsGauge.Update(int64(mgasps))
|
blockInsertMgaspsGauge.Update(int64(mgasps))
|
||||||
if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
|
if timestamp := time.Unix(int64(end.Time()), 0); time.Since(timestamp) > time.Minute {
|
||||||
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)
|
context = append(context, []interface{}{"age", common.PrettyAge(timestamp)}...)
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
@@ -99,6 +98,15 @@ func (bc *BlockChain) GetHeaderByHash(hash common.Hash) *types.Header {
|
|||||||
return bc.hc.GetHeaderByHash(hash)
|
return bc.hc.GetHeaderByHash(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetVerifiedBlockByHash retrieves the header of a verified block, it may be only in memory.
|
||||||
|
func (bc *BlockChain) GetVerifiedBlockByHash(hash common.Hash) *types.Header {
|
||||||
|
highestVerifiedBlock := bc.highestVerifiedBlock.Load()
|
||||||
|
if highestVerifiedBlock != nil && highestVerifiedBlock.Hash() == hash {
|
||||||
|
return highestVerifiedBlock
|
||||||
|
}
|
||||||
|
return bc.hc.GetHeaderByHash(hash)
|
||||||
|
}
|
||||||
|
|
||||||
// GetHeaderByNumber retrieves a block header from the database by number,
|
// GetHeaderByNumber retrieves a block header from the database by number,
|
||||||
// caching it (associated with its hash) if found.
|
// caching it (associated with its hash) if found.
|
||||||
func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header {
|
func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header {
|
||||||
@@ -339,7 +347,7 @@ func (bc *BlockChain) GetTd(hash common.Hash, number uint64) *big.Int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// HasState checks if state trie is fully present in the database or not.
|
// HasState checks if state trie is fully present in the database or not.
|
||||||
func (bc *BlockChain) HasState(number int64, hash common.Hash) bool {
|
func (bc *BlockChain) HasState(hash common.Hash) bool {
|
||||||
if bc.NoTries() {
|
if bc.NoTries() {
|
||||||
return bc.snaps != nil && bc.snaps.Snapshot(hash) != nil
|
return bc.snaps != nil && bc.snaps.Snapshot(hash) != nil
|
||||||
}
|
}
|
||||||
@@ -349,24 +357,19 @@ func (bc *BlockChain) HasState(number int64, hash common.Hash) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return bc.stateCache.HasState(number, hash)
|
_, err := bc.stateCache.OpenTrie(hash)
|
||||||
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasBlockAndState checks if a block and associated state trie is fully present
|
// HasBlockAndState checks if a block and associated state trie is fully present
|
||||||
// in the database or not, caching it if present.
|
// in the database or not, caching it if present.
|
||||||
func (bc *BlockChain) HasBlockAndState(hash common.Hash, number int64) bool {
|
func (bc *BlockChain) HasBlockAndState(hash common.Hash, number uint64) bool {
|
||||||
// Check first that the block itself is known
|
// Check first that the block itself is known
|
||||||
var root common.Hash
|
block := bc.GetBlock(hash, number)
|
||||||
if number < 0 {
|
if block == nil {
|
||||||
root = types.EmptyRootHash
|
return false
|
||||||
} else {
|
|
||||||
block := bc.GetBlock(hash, uint64(number))
|
|
||||||
if block == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
root = block.Root()
|
|
||||||
}
|
}
|
||||||
return bc.HasState(number, root)
|
return bc.HasState(block.Root())
|
||||||
}
|
}
|
||||||
|
|
||||||
// stateRecoverable checks if the specified state is recoverable.
|
// stateRecoverable checks if the specified state is recoverable.
|
||||||
@@ -397,19 +400,12 @@ func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
|
|||||||
|
|
||||||
// State returns a new mutable state based on the current HEAD block.
|
// State returns a new mutable state based on the current HEAD block.
|
||||||
func (bc *BlockChain) State() (*state.StateDB, error) {
|
func (bc *BlockChain) State() (*state.StateDB, error) {
|
||||||
return bc.StateAt(bc.CurrentBlock().Number.Int64(), bc.CurrentBlock().Root)
|
return bc.StateAt(bc.CurrentBlock().Root)
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateAt returns a new mutable state based on a particular point in time.
|
// StateAt returns a new mutable state based on a particular point in time.
|
||||||
func (bc *BlockChain) StateAt(number int64, root common.Hash) (*state.StateDB, error) {
|
func (bc *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) {
|
||||||
// new state db with no need commit mode
|
stateDb, err := state.New(root, bc.stateCache, bc.snaps)
|
||||||
has := bc.HasState(number, root)
|
|
||||||
if !has {
|
|
||||||
return nil, fmt.Errorf(fmt.Sprintf("do not has state, verison: %d, root: %s", number, root.String()))
|
|
||||||
}
|
|
||||||
sdb := state.NewDatabaseWithNodeDB(bc.db, bc.triedb, false)
|
|
||||||
sdb.SetVersion(number)
|
|
||||||
stateDb, err := state.New(root, sdb, bc.snaps)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -499,6 +495,11 @@ func (bc *BlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Su
|
|||||||
return bc.scope.Track(bc.chainHeadFeed.Subscribe(ch))
|
return bc.scope.Track(bc.chainHeadFeed.Subscribe(ch))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SubscribeHighestVerifiedBlockEvent registers a subscription of HighestVerifiedBlockEvent.
|
||||||
|
func (bc *BlockChain) SubscribeHighestVerifiedHeaderEvent(ch chan<- HighestVerifiedBlockEvent) event.Subscription {
|
||||||
|
return bc.scope.Track(bc.highestVerifiedBlockFeed.Subscribe(ch))
|
||||||
|
}
|
||||||
|
|
||||||
// SubscribeChainBlockEvent registers a subscription of ChainBlockEvent.
|
// SubscribeChainBlockEvent registers a subscription of ChainBlockEvent.
|
||||||
func (bc *BlockChain) SubscribeChainBlockEvent(ch chan<- ChainHeadEvent) event.Subscription {
|
func (bc *BlockChain) SubscribeChainBlockEvent(ch chan<- ChainHeadEvent) event.Subscription {
|
||||||
return bc.scope.Track(bc.chainBlockFeed.Subscribe(ch))
|
return bc.scope.Track(bc.chainBlockFeed.Subscribe(ch))
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
|||||||
defer triedb.Close()
|
defer triedb.Close()
|
||||||
|
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb, true), nil)
|
statedb, err := state.New(parent.Root(), state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -486,7 +486,7 @@ func (cm *chainMaker) makeHeader(parent *types.Block, state *state.StateDB, engi
|
|||||||
if cm.config.Parlia != nil {
|
if cm.config.Parlia != nil {
|
||||||
header.WithdrawalsHash = &types.EmptyWithdrawalsHash
|
header.WithdrawalsHash = &types.EmptyWithdrawalsHash
|
||||||
}
|
}
|
||||||
if cm.config.Parlia == nil {
|
if cm.config.Parlia == nil || cm.config.IsBohr(header.Number, header.Time) {
|
||||||
header.ParentBeaconRoot = new(common.Hash)
|
header.ParentBeaconRoot = new(common.Hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -621,6 +621,10 @@ func (cm *chainMaker) GetHighestVerifiedHeader() *types.Header {
|
|||||||
panic("not supported")
|
panic("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cm *chainMaker) GetVerifiedBlockByHash(hash common.Hash) *types.Header {
|
||||||
|
return cm.GetHeaderByHash(hash)
|
||||||
|
}
|
||||||
|
|
||||||
func (cm *chainMaker) ChasingHead() *types.Header {
|
func (cm *chainMaker) ChasingHead() *types.Header {
|
||||||
panic("not supported")
|
panic("not supported")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -365,6 +365,10 @@ func (r *mockDAHeaderReader) GetHighestVerifiedHeader() *types.Header {
|
|||||||
panic("not supported")
|
panic("not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *mockDAHeaderReader) GetVerifiedBlockByHash(hash common.Hash) *types.Header {
|
||||||
|
panic("not supported")
|
||||||
|
}
|
||||||
|
|
||||||
func createMockDATx(config *params.ChainConfig, sidecar *types.BlobTxSidecar) *types.Transaction {
|
func createMockDATx(config *params.ChainConfig, sidecar *types.BlobTxSidecar) *types.Transaction {
|
||||||
if sidecar == nil {
|
if sidecar == nil {
|
||||||
tx := &types.DynamicFeeTx{
|
tx := &types.DynamicFeeTx{
|
||||||
|
|||||||
@@ -50,3 +50,5 @@ type ChainSideEvent struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ChainHeadEvent struct{ Block *types.Block }
|
type ChainHeadEvent struct{ Block *types.Block }
|
||||||
|
|
||||||
|
type HighestVerifiedBlockEvent struct{ Header *types.Header }
|
||||||
|
|||||||
@@ -121,9 +121,12 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (b
|
|||||||
if f.preserve != nil {
|
if f.preserve != nil {
|
||||||
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
|
currentPreserve, externPreserve = f.preserve(current), f.preserve(extern)
|
||||||
}
|
}
|
||||||
|
doubleSign := (extern.Coinbase == current.Coinbase)
|
||||||
reorg = !currentPreserve && (externPreserve ||
|
reorg = !currentPreserve && (externPreserve ||
|
||||||
extern.Time < current.Time ||
|
extern.Time < current.Time ||
|
||||||
extern.Time == current.Time && f.rand.Float64() < 0.5)
|
extern.Time == current.Time &&
|
||||||
|
((doubleSign && extern.Hash().Cmp(current.Hash()) < 0) ||
|
||||||
|
(!doubleSign && f.rand.Float64() < 0.5)))
|
||||||
}
|
}
|
||||||
return reorg, nil
|
return reorg, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,10 +126,7 @@ func hashAlloc(ga *types.GenesisAlloc, isVerkle bool) (common.Hash, error) {
|
|||||||
}
|
}
|
||||||
// Create an ephemeral in-memory database for computing hash,
|
// Create an ephemeral in-memory database for computing hash,
|
||||||
// all the derived states will be discarded to not pollute disk.
|
// all the derived states will be discarded to not pollute disk.
|
||||||
db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config, true)
|
db := state.NewDatabaseWithConfig(rawdb.NewMemoryDatabase(), config)
|
||||||
log.Info("genesis calc root hash use hash mode triedb")
|
|
||||||
db.SetVersion(0)
|
|
||||||
defer db.Release()
|
|
||||||
statedb, err := state.New(types.EmptyRootHash, db, nil)
|
statedb, err := state.New(types.EmptyRootHash, db, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
@@ -157,10 +154,7 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa
|
|||||||
if triedbConfig != nil {
|
if triedbConfig != nil {
|
||||||
triedbConfig.NoTries = false
|
triedbConfig.NoTries = false
|
||||||
}
|
}
|
||||||
cachingdb := state.NewDatabaseWithNodeDB(db, triedb, true)
|
statedb, err := state.New(types.EmptyRootHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||||
cachingdb.SetVersion(-1)
|
|
||||||
defer cachingdb.Release()
|
|
||||||
statedb, err := state.New(types.EmptyRootHash, cachingdb, nil)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -180,7 +174,7 @@ func flushAlloc(ga *types.GenesisAlloc, db ethdb.Database, triedb *triedb.Databa
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Commit newly generated states into disk if it's not empty.
|
// Commit newly generated states into disk if it's not empty.
|
||||||
if root != types.EmptyRootHash && triedb.Scheme() != rawdb.VersionScheme {
|
if root != types.EmptyRootHash {
|
||||||
if err := triedb.Commit(root, true); err != nil {
|
if err := triedb.Commit(root, true); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -222,8 +216,9 @@ func (e *GenesisMismatchError) Error() string {
|
|||||||
// ChainOverrides contains the changes to chain config
|
// ChainOverrides contains the changes to chain config
|
||||||
// Typically, these modifications involve hardforks that are not enabled on the BSC mainnet, intended for testing purposes.
|
// Typically, these modifications involve hardforks that are not enabled on the BSC mainnet, intended for testing purposes.
|
||||||
type ChainOverrides struct {
|
type ChainOverrides struct {
|
||||||
OverrideBohr *uint64
|
OverridePassedForkTime *uint64
|
||||||
OverrideVerkle *uint64
|
OverrideBohr *uint64
|
||||||
|
OverrideVerkle *uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetupGenesisBlock writes or updates the genesis block in db.
|
// SetupGenesisBlock writes or updates the genesis block in db.
|
||||||
@@ -249,6 +244,15 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
|
|||||||
}
|
}
|
||||||
applyOverrides := func(config *params.ChainConfig) {
|
applyOverrides := func(config *params.ChainConfig) {
|
||||||
if config != nil {
|
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 {
|
if overrides != nil && overrides.OverrideBohr != nil {
|
||||||
config.BohrTime = overrides.OverrideBohr
|
config.BohrTime = overrides.OverrideBohr
|
||||||
}
|
}
|
||||||
@@ -274,8 +278,6 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
|
|||||||
log.Info("genesis block hash", "hash", block.Hash())
|
log.Info("genesis block hash", "hash", block.Hash())
|
||||||
return genesis.Config, block.Hash(), nil
|
return genesis.Config, block.Hash(), nil
|
||||||
}
|
}
|
||||||
log.Info("init genesis", "stored root", stored.String())
|
|
||||||
|
|
||||||
// The genesis block is present(perhaps in ancient database) while the
|
// The genesis block is present(perhaps in ancient database) while the
|
||||||
// state database is not initialized yet. It can happen that the node
|
// state database is not initialized yet. It can happen that the node
|
||||||
// is initialized with an external ancient store. Commit genesis state
|
// is initialized with an external ancient store. Commit genesis state
|
||||||
@@ -452,7 +454,7 @@ func (g *Genesis) ToBlock() *types.Block {
|
|||||||
// EIP-4788: The parentBeaconBlockRoot of the genesis block is always
|
// EIP-4788: The parentBeaconBlockRoot of the genesis block is always
|
||||||
// the zero hash. This is because the genesis block does not have a parent
|
// the zero hash. This is because the genesis block does not have a parent
|
||||||
// by definition.
|
// by definition.
|
||||||
if conf.Parlia == nil {
|
if conf.Parlia == nil || conf.IsBohr(num, g.Timestamp) {
|
||||||
head.ParentBeaconRoot = new(common.Hash)
|
head.ParentBeaconRoot = new(common.Hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -436,6 +436,10 @@ func (hc *HeaderChain) GetHighestVerifiedHeader() *types.Header {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (hc *HeaderChain) GetVerifiedBlockByHash(hash common.Hash) *types.Header {
|
||||||
|
return hc.GetHeaderByHash(hash)
|
||||||
|
}
|
||||||
|
|
||||||
func (hc *HeaderChain) ChasingHead() *types.Header {
|
func (hc *HeaderChain) ChasingHead() *types.Header {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const HashScheme = "hash"
|
|||||||
// on extra state diffs to survive deep reorg.
|
// on extra state diffs to survive deep reorg.
|
||||||
const PathScheme = "path"
|
const PathScheme = "path"
|
||||||
|
|
||||||
const VersionScheme = "version"
|
const VersaScheme = "versa"
|
||||||
|
|
||||||
// hasher is used to compute the sha256 hash of the provided data.
|
// hasher is used to compute the sha256 hash of the provided data.
|
||||||
type hasher struct{ sha crypto.KeccakState }
|
type hasher struct{ sha crypto.KeccakState }
|
||||||
@@ -316,7 +316,7 @@ func ReadStateScheme(db ethdb.Reader) string {
|
|||||||
// ValidateStateScheme used to check state scheme whether is valid.
|
// ValidateStateScheme used to check state scheme whether is valid.
|
||||||
// Valid state scheme: hash and path.
|
// Valid state scheme: hash and path.
|
||||||
func ValidateStateScheme(stateScheme string) bool {
|
func ValidateStateScheme(stateScheme string) bool {
|
||||||
if stateScheme == HashScheme || stateScheme == PathScheme || stateScheme == VersionScheme {
|
if stateScheme == HashScheme || stateScheme == PathScheme {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -1,526 +0,0 @@
|
|||||||
package state
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"sync/atomic"
|
|
||||||
|
|
||||||
versa "github.com/bnb-chain/versioned-state-database"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/common/lru"
|
|
||||||
"github.com/ethereum/go-ethereum/common/math"
|
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
|
||||||
)
|
|
||||||
|
|
||||||
const InvalidSateObjectVersion int64 = math.MinInt64
|
|
||||||
|
|
||||||
type cachingVersaDB struct {
|
|
||||||
version int64
|
|
||||||
triedb *triedb.Database
|
|
||||||
versionDB versa.Database
|
|
||||||
codeDB ethdb.KeyValueStore
|
|
||||||
codeSizeCache *lru.Cache[common.Hash, int]
|
|
||||||
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
|
|
||||||
|
|
||||||
accTree *VersaTree
|
|
||||||
state versa.StateHandler
|
|
||||||
root common.Hash
|
|
||||||
mode versa.StateMode
|
|
||||||
hasState atomic.Bool
|
|
||||||
|
|
||||||
//debug *DebugVersionState
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewVersaDatabase should be call by NewDatabaseWithNodeDB
|
|
||||||
// TODO:: NewDatabaseWithNodeDB should add mode param.
|
|
||||||
func NewVersaDatabase(db ethdb.Database, triedb *triedb.Database, mode versa.StateMode) Database {
|
|
||||||
return &cachingVersaDB{
|
|
||||||
triedb: triedb,
|
|
||||||
versionDB: triedb.VersaDB(),
|
|
||||||
codeDB: db,
|
|
||||||
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
|
||||||
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
|
|
||||||
mode: mode,
|
|
||||||
state: versa.ErrStateHandler,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) Copy() Database {
|
|
||||||
cp := &cachingVersaDB{}
|
|
||||||
cp.codeCache = cv.codeCache
|
|
||||||
cp.codeSizeCache = cv.codeSizeCache
|
|
||||||
cp.triedb = cv.triedb
|
|
||||||
cp.versionDB = cv.versionDB
|
|
||||||
cp.codeDB = cv.codeDB
|
|
||||||
cp.version = cv.version
|
|
||||||
cp.mode = versa.S_RW // it is important
|
|
||||||
|
|
||||||
// TODO:: maybe add lock for cv.root
|
|
||||||
if cv.hasState.Load() {
|
|
||||||
_, err := cp.OpenTrie(cv.root)
|
|
||||||
if err != nil {
|
|
||||||
//if cv.debug != nil {
|
|
||||||
// cv.debug.OnError(fmt.Errorf("failed to open trie in copy caching versa db, error: %s", err.Error()))
|
|
||||||
//}
|
|
||||||
return cp
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cp
|
|
||||||
}
|
|
||||||
|
|
||||||
// CopyTrie is used with Copy()
|
|
||||||
func (cv *cachingVersaDB) CopyTrie(tr Trie) Trie {
|
|
||||||
vtr, ok := tr.(*VersaTree)
|
|
||||||
if !ok {
|
|
||||||
panic("caching versa db copy non versa tree")
|
|
||||||
}
|
|
||||||
if vtr.accountTree {
|
|
||||||
if cv.accTree != nil {
|
|
||||||
if cv.accTree.root.Cmp(vtr.root) != 0 {
|
|
||||||
panic("copy acc trie mismatch")
|
|
||||||
}
|
|
||||||
return cv.accTree
|
|
||||||
}
|
|
||||||
tree, err := cv.OpenTrie(vtr.root)
|
|
||||||
if err != nil {
|
|
||||||
//if cv.debug != nil {
|
|
||||||
// cv.debug.OnError(fmt.Errorf("failed to open trie in copy versa trie, error: %s", err.Error()))
|
|
||||||
//}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return tree
|
|
||||||
} else {
|
|
||||||
tree, err := cv.OpenStorageTrie(vtr.stateRoot, vtr.address, vtr.root, nil)
|
|
||||||
if err != nil {
|
|
||||||
//if cv.debug != nil {
|
|
||||||
// cv.debug.OnError(fmt.Errorf("failed to open storage trie in copy versa trie, error: %s", err.Error()))
|
|
||||||
//}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return tree
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) HasState(version int64, root common.Hash) bool {
|
|
||||||
return cv.versionDB.HasState(version, root)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) OpenTrie(root common.Hash) (Trie, error) {
|
|
||||||
if cv.hasState.Load() {
|
|
||||||
//TODO:: will change to log.Error after stabilization
|
|
||||||
panic("account tree has open")
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:: if root tree, versa db should ignore check version, temp use -1
|
|
||||||
state, err := cv.versionDB.OpenState(cv.version, root, cv.mode)
|
|
||||||
if err != nil {
|
|
||||||
//if cv.debug != nil {
|
|
||||||
// cv.debug.OnError(fmt.Errorf("failed to open state, root:%s, error: %s", root.String(), err.Error()))
|
|
||||||
//}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
//if cv.debug != nil {
|
|
||||||
// cv.debug.OnOpenState(state)
|
|
||||||
//}
|
|
||||||
|
|
||||||
handler, err := cv.versionDB.OpenTree(state, cv.version, common.Hash{}, root)
|
|
||||||
if err != nil {
|
|
||||||
//if cv.debug != nil {
|
|
||||||
// cv.debug.OnError(fmt.Errorf("failed to open account trie, root:%s, error: %s", root.String(), err.Error()))
|
|
||||||
//}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
tree := &VersaTree{
|
|
||||||
db: cv.versionDB,
|
|
||||||
handler: handler,
|
|
||||||
accountTree: true,
|
|
||||||
root: root,
|
|
||||||
mode: cv.mode,
|
|
||||||
//debug: cv.debug,
|
|
||||||
}
|
|
||||||
|
|
||||||
cv.state = state
|
|
||||||
cv.hasState.Store(true) // if set, can't change
|
|
||||||
cv.accTree = tree
|
|
||||||
cv.root = root
|
|
||||||
|
|
||||||
//if cv.debug != nil {
|
|
||||||
// cv.debug.OnOpenTree(handler, common.Hash{}, common.Address{})
|
|
||||||
//}
|
|
||||||
|
|
||||||
return tree, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, _ Trie) (Trie, error) {
|
|
||||||
version, _, err := cv.accTree.getAccountWithVersion(address)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return cv.openStorageTreeWithVersion(version, stateRoot, address, root)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) openStorageTreeWithVersion(version int64, stateRoot common.Hash, address common.Address, root common.Hash) (Trie, error) {
|
|
||||||
if !cv.hasState.Load() {
|
|
||||||
//TODO:: will change to log.Error after stabilization
|
|
||||||
panic("open account tree, before open storage tree")
|
|
||||||
}
|
|
||||||
if cv.root.Cmp(stateRoot) != 0 {
|
|
||||||
panic(fmt.Sprintf("account root mismatch, on open storage tree, actual: %s, expect: %s", root.String(), cv.root.String()))
|
|
||||||
}
|
|
||||||
|
|
||||||
owner := crypto.Keccak256Hash(address.Bytes())
|
|
||||||
handler, err := cv.versionDB.OpenTree(cv.state, version, owner, root)
|
|
||||||
if err != nil {
|
|
||||||
//if cv.debug != nil {
|
|
||||||
// cv.debug.OnError(fmt.Errorf("failed to open storage trie, version: %d,stateRoot:%s, address:%s, root: %s, error: %s",
|
|
||||||
// version, stateRoot.String(), address.String(), root.String(), err.Error()))
|
|
||||||
//}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
//if cv.debug != nil {
|
|
||||||
// cv.debug.OnOpenTree(handler, owner, address)
|
|
||||||
//}
|
|
||||||
tree := &VersaTree{
|
|
||||||
db: cv.versionDB,
|
|
||||||
handler: handler,
|
|
||||||
version: version,
|
|
||||||
root: stateRoot,
|
|
||||||
stateRoot: root,
|
|
||||||
address: address,
|
|
||||||
mode: cv.mode,
|
|
||||||
//debug: cv.debug,
|
|
||||||
}
|
|
||||||
return tree, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Flush unique to versa
|
|
||||||
func (cv *cachingVersaDB) Flush() error {
|
|
||||||
err := cv.versionDB.Flush(cv.state)
|
|
||||||
//if err != nil && cv.debug != nil {
|
|
||||||
// cv.debug.OnError(fmt.Errorf("failed to flush state, version: %d, root:%s, mode:%d, error: %s",
|
|
||||||
// cv.accTree.version, cv.accTree.root.String(), cv.accTree.mode, err.Error()))
|
|
||||||
//}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) SetVersion(version int64) {
|
|
||||||
cv.version = version
|
|
||||||
//cv.debug = NewDebugVersionState(cv.codeDB, cv.versionDB)
|
|
||||||
//cv.debug.Version = version
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) GetVersion() int64 {
|
|
||||||
return cv.version
|
|
||||||
}
|
|
||||||
|
|
||||||
// Release unique to versa
|
|
||||||
func (cv *cachingVersaDB) Release() error {
|
|
||||||
//log.Info("close state", "state info", cv.versionDB.ParseStateHandler(cv.state))
|
|
||||||
if cv.state != versa.ErrStateHandler {
|
|
||||||
//if cv.debug != nil {
|
|
||||||
// cv.debug.OnCloseState(cv.state)
|
|
||||||
//}
|
|
||||||
if err := cv.versionDB.CloseState(cv.state); err != nil {
|
|
||||||
//if cv.debug != nil {
|
|
||||||
// cv.debug.OnError(fmt.Errorf("failed to close state in release, version: %d, root:%s, mode:%d, error: %s",
|
|
||||||
// cv.accTree.version, cv.accTree.root.String(), cv.accTree.mode, err.Error()))
|
|
||||||
//}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cv.hasState.Store(false)
|
|
||||||
cv.accTree = nil
|
|
||||||
cv.state = versa.ErrStateHandler
|
|
||||||
cv.root = common.Hash{}
|
|
||||||
//cv.debug = nil
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) Reset() {
|
|
||||||
if cv.state != versa.ErrStateHandler {
|
|
||||||
_ = cv.versionDB.CloseState(cv.state)
|
|
||||||
panic("close state in reset")
|
|
||||||
}
|
|
||||||
cv.hasState.Store(false)
|
|
||||||
cv.accTree = nil
|
|
||||||
cv.state = versa.ErrStateHandler
|
|
||||||
cv.root = common.Hash{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) HasTreeExpired(tr Trie) bool {
|
|
||||||
vtr, ok := tr.(*VersaTree)
|
|
||||||
if !ok {
|
|
||||||
panic("trie type mismatch")
|
|
||||||
}
|
|
||||||
return cv.versionDB.HasTreeExpired(vtr.handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) Scheme() string {
|
|
||||||
return cv.triedb.Scheme()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error) {
|
|
||||||
//if cv.debug != nil {
|
|
||||||
// cv.debug.OnGetCode(addr, codeHash)
|
|
||||||
//}
|
|
||||||
code, _ := cv.codeCache.Get(codeHash)
|
|
||||||
if len(code) > 0 {
|
|
||||||
return code, nil
|
|
||||||
}
|
|
||||||
code = rawdb.ReadCode(cv.codeDB, codeHash)
|
|
||||||
if len(code) > 0 {
|
|
||||||
cv.codeCache.Add(codeHash, code)
|
|
||||||
cv.codeSizeCache.Add(codeHash, len(code))
|
|
||||||
return code, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) {
|
|
||||||
if cached, ok := cv.codeSizeCache.Get(codeHash); ok {
|
|
||||||
return cached, nil
|
|
||||||
}
|
|
||||||
code, err := cv.ContractCode(addr, codeHash)
|
|
||||||
return len(code), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) {
|
|
||||||
code, _ := cv.codeCache.Get(codeHash)
|
|
||||||
if len(code) > 0 {
|
|
||||||
return code, nil
|
|
||||||
}
|
|
||||||
code = rawdb.ReadCodeWithPrefix(cv.codeDB, codeHash)
|
|
||||||
if len(code) > 0 {
|
|
||||||
cv.codeCache.Add(codeHash, code)
|
|
||||||
cv.codeSizeCache.Add(codeHash, len(code))
|
|
||||||
return code, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) DiskDB() ethdb.KeyValueStore {
|
|
||||||
return cv.codeDB
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) TrieDB() *triedb.Database {
|
|
||||||
return cv.triedb
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cv *cachingVersaDB) NoTries() bool {
|
|
||||||
// TODO:: not support fastnode
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
type VersaTree struct {
|
|
||||||
db versa.Database
|
|
||||||
handler versa.TreeHandler
|
|
||||||
version int64
|
|
||||||
accountTree bool
|
|
||||||
//debug *DebugVersionState
|
|
||||||
|
|
||||||
// TODO:: debugging, used for logging
|
|
||||||
stateRoot common.Hash
|
|
||||||
root common.Hash
|
|
||||||
address common.Address
|
|
||||||
mode versa.StateMode
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) GetKey(key []byte) []byte {
|
|
||||||
_, val, err := vt.db.Get(vt.handler, key)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("failed to get key from version db")
|
|
||||||
}
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) GetAccount(address common.Address) (*types.StateAccount, error) {
|
|
||||||
_, res, err := vt.getAccountWithVersion(address)
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) getAccountWithVersion(address common.Address) (int64, *types.StateAccount, error) {
|
|
||||||
vt.CheckAccountTree()
|
|
||||||
ver, res, err := vt.db.Get(vt.handler, address.Bytes())
|
|
||||||
if res == nil || err != nil {
|
|
||||||
//if err != nil && vt.debug != nil {
|
|
||||||
// vt.debug.OnError(fmt.Errorf("failed to get account, root: %s, address: %s, error: %s",
|
|
||||||
// vt.root.String(), address.String(), err.Error()))
|
|
||||||
//}
|
|
||||||
return ver, nil, err
|
|
||||||
}
|
|
||||||
ret := new(types.StateAccount)
|
|
||||||
err = rlp.DecodeBytes(res, ret)
|
|
||||||
if err != nil {
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnError(fmt.Errorf("failed to rlp decode account, root: %s, address: %s, error: %s",
|
|
||||||
// vt.root.String(), address.String(), err.Error()))
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnGetAccount(address, ret)
|
|
||||||
//}
|
|
||||||
return ver, ret, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) GetStorage(address common.Address, key []byte) ([]byte, error) {
|
|
||||||
if vt.address.Cmp(address) != 0 {
|
|
||||||
panic(fmt.Sprintf("address mismatch in get storage, expect: %s, actul: %s", vt.address.String(), address.String()))
|
|
||||||
}
|
|
||||||
vt.CheckStorageTree()
|
|
||||||
_, enc, err := vt.db.Get(vt.handler, key)
|
|
||||||
if err != nil || len(enc) == 0 {
|
|
||||||
//if err != nil && vt.debug != nil {
|
|
||||||
// vt.debug.OnError(fmt.Errorf("failed to get storage, root: %s, stateRoot: %s, address:%s, key: %s, error: %s",
|
|
||||||
// vt.root.String(), vt.stateRoot.String(), address.String(), common.Bytes2Hex(key), err.Error()))
|
|
||||||
//}
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
_, content, _, err := rlp.Split(enc)
|
|
||||||
if err != nil {
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnError(fmt.Errorf("failed to rlp decode storage, root: %s, stateRoot: %s, address: %s, key: %s,error: %s",
|
|
||||||
// vt.root.String(), vt.stateRoot.String(), address.String(), common.Bytes2Hex(key), err.Error()))
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnGetStorage(vt.handler, address, key, content)
|
|
||||||
//}
|
|
||||||
return content, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) UpdateAccount(address common.Address, account *types.StateAccount) error {
|
|
||||||
vt.CheckAccountTree()
|
|
||||||
data, err := rlp.EncodeToBytes(account)
|
|
||||||
if err != nil {
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnError(fmt.Errorf("failed to update account, root: %s, address: %s, account: %s, error: %s",
|
|
||||||
// vt.root.String(), address.String(), account.String(), err.Error()))
|
|
||||||
//}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnUpdateAccount(address, account)
|
|
||||||
//}
|
|
||||||
return vt.db.Put(vt.handler, address.Bytes(), data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) WriteBatch(values map[string][]byte) error {
|
|
||||||
return vt.db.WriteBatch(vt.handler, values)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) UpdateStorage(address common.Address, key, value []byte) error {
|
|
||||||
if vt.address.Cmp(address) != 0 {
|
|
||||||
panic(fmt.Sprintf("address mismatch in get storage, expect: %s, actul: %s", vt.address.String(), address.String()))
|
|
||||||
}
|
|
||||||
vt.CheckStorageTree()
|
|
||||||
v, _ := rlp.EncodeToBytes(value)
|
|
||||||
err := vt.db.Put(vt.handler, key, v)
|
|
||||||
if err != nil {
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnError(fmt.Errorf("failed to update storage, root: %s, stateRoot: %s, address: %s, key: %s, val: %s, error: %s",
|
|
||||||
// vt.root.String(), vt.stateRoot.String(), address.String(), common.Bytes2Hex(key), common.Bytes2Hex(value), err.Error()))
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnUpdateStorage(vt.handler, address, key, value)
|
|
||||||
//}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) DeleteAccount(address common.Address) error {
|
|
||||||
vt.CheckAccountTree()
|
|
||||||
err := vt.db.Delete(vt.handler, address.Bytes())
|
|
||||||
if err != nil {
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnError(fmt.Errorf("failed to delete account, root: %s, address: %s, error: %s",
|
|
||||||
// vt.root.String(), address.String(), err.Error()))
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnDeleteAccount(address)
|
|
||||||
//}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) DeleteStorage(address common.Address, key []byte) error {
|
|
||||||
vt.CheckStorageTree()
|
|
||||||
err := vt.db.Delete(vt.handler, key)
|
|
||||||
if err != nil {
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnError(fmt.Errorf("failed to delete storage, root: %s, stateRoot: %s, address: %s, key: %s, error: %s",
|
|
||||||
// vt.root.String(), vt.stateRoot.String(), address.String(), common.Bytes2Hex(key), err.Error()))
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnDeleteStorage(vt.handler, address, key)
|
|
||||||
//}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) UpdateContractCode(address common.Address, codeHash common.Hash, code []byte) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) Hash() common.Hash {
|
|
||||||
hash, err := vt.db.CalcRootHash(vt.handler)
|
|
||||||
if err != nil {
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnError(fmt.Errorf("failed to calc root, root: %s, stateRoot%s, error:%s",
|
|
||||||
// vt.root.String(), vt.stateRoot.String(), err.Error()))
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnCalcHash(vt.address, hash)
|
|
||||||
//}
|
|
||||||
return hash
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) Commit(_ bool) (common.Hash, *trienode.NodeSet, error) {
|
|
||||||
hash, err := vt.db.Commit(vt.handler)
|
|
||||||
if err != nil {
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnError(fmt.Errorf("failed to commit versa tree, root: %s, stateRoot: %s, error: %s",
|
|
||||||
// vt.root.String(), vt.stateRoot.String(), err.Error()))
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
//if vt.debug != nil {
|
|
||||||
// vt.debug.OnCalcHash(vt.address, hash)
|
|
||||||
// vt.debug.OnCommitTree(vt.address, vt.handler)
|
|
||||||
//}
|
|
||||||
return hash, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) NodeIterator(startKey []byte) (trie.NodeIterator, error) {
|
|
||||||
panic("versa tree not support iterate")
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (vt *VersaTree) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
|
|
||||||
panic("versa tree not support prove")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:: debug code, will be deleted after stabilization
|
|
||||||
func (vt *VersaTree) CheckAccountTree() {
|
|
||||||
if !vt.accountTree {
|
|
||||||
panic("sub tree can't operate account")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:: debug code, will be deleted after stabilization
|
|
||||||
func (vt *VersaTree) CheckStorageTree() {
|
|
||||||
if vt.accountTree {
|
|
||||||
panic("root tree can't operate storage")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -20,7 +20,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
versa "github.com/bnb-chain/versioned-state-database"
|
|
||||||
"github.com/crate-crypto/go-ipa/banderwagon"
|
"github.com/crate-crypto/go-ipa/banderwagon"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/common/lru"
|
"github.com/ethereum/go-ethereum/common/lru"
|
||||||
@@ -71,33 +70,8 @@ type Database interface {
|
|||||||
// TrieDB returns the underlying trie database for managing trie nodes.
|
// TrieDB returns the underlying trie database for managing trie nodes.
|
||||||
TrieDB() *triedb.Database
|
TrieDB() *triedb.Database
|
||||||
|
|
||||||
// Scheme returns triedb scheme, used to distinguish version triedb.
|
|
||||||
Scheme() string
|
|
||||||
|
|
||||||
// Flush used for version caching versa db to commit block state data.
|
|
||||||
Flush() error
|
|
||||||
|
|
||||||
// Release used for caching versa db to release resource.
|
|
||||||
Release() error
|
|
||||||
|
|
||||||
// Reset used for caching versa db to clean up meta data.
|
|
||||||
Reset()
|
|
||||||
|
|
||||||
// Copy used for caching versa db to copy db, main to transfer triedb with rw mode.
|
|
||||||
Copy() Database
|
|
||||||
|
|
||||||
// HasState returns the state data whether in the triedb.
|
|
||||||
HasState(version int64, root common.Hash) bool
|
|
||||||
|
|
||||||
// HasTreeExpired used for caching versa db, whether the state where the opened tree resides has been closed
|
|
||||||
HasTreeExpired(tr Trie) bool
|
|
||||||
|
|
||||||
// NoTries returns whether the database has tries storage.
|
// NoTries returns whether the database has tries storage.
|
||||||
NoTries() bool
|
NoTries() bool
|
||||||
|
|
||||||
SetVersion(version int64)
|
|
||||||
|
|
||||||
GetVersion() int64
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trie is a Ethereum Merkle Patricia trie.
|
// Trie is a Ethereum Merkle Patricia trie.
|
||||||
@@ -143,8 +117,6 @@ type Trie interface {
|
|||||||
// to be moved to the stateWriter interface when the latter is ready.
|
// to be moved to the stateWriter interface when the latter is ready.
|
||||||
UpdateContractCode(address common.Address, codeHash common.Hash, code []byte) error
|
UpdateContractCode(address common.Address, codeHash common.Hash, code []byte) error
|
||||||
|
|
||||||
WriteBatch(values map[string][]byte) error
|
|
||||||
|
|
||||||
// Hash returns the root hash of the trie. It does not write to the database and
|
// 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.
|
// can be used even if the trie doesn't have one.
|
||||||
Hash() common.Hash
|
Hash() common.Hash
|
||||||
@@ -176,43 +148,28 @@ type Trie interface {
|
|||||||
// concurrent use, but does not retain any recent trie nodes in memory. To keep some
|
// concurrent use, but does not retain any recent trie nodes in memory. To keep some
|
||||||
// historical state in memory, use the NewDatabaseWithConfig constructor.
|
// historical state in memory, use the NewDatabaseWithConfig constructor.
|
||||||
func NewDatabase(db ethdb.Database) Database {
|
func NewDatabase(db ethdb.Database) Database {
|
||||||
return NewDatabaseWithConfig(db, nil, false)
|
return NewDatabaseWithConfig(db, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDatabaseWithConfig creates a backing store for state. The returned database
|
// NewDatabaseWithConfig creates a backing store for state. The returned database
|
||||||
// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a
|
// is safe for concurrent use and retains a lot of collapsed RLP trie nodes in a
|
||||||
// large memory cache.
|
// large memory cache.
|
||||||
func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config, needCommit bool) Database {
|
func NewDatabaseWithConfig(db ethdb.Database, config *triedb.Config) Database {
|
||||||
noTries := config != nil && config.NoTries
|
noTries := config != nil && config.NoTries
|
||||||
|
|
||||||
triedb := triedb.NewDatabase(db, config)
|
|
||||||
if triedb.Scheme() == rawdb.VersionScheme {
|
|
||||||
if needCommit {
|
|
||||||
return NewVersaDatabase(db, triedb, versa.S_COMMIT)
|
|
||||||
}
|
|
||||||
return NewVersaDatabase(db, triedb, versa.S_RW)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cachingDB{
|
return &cachingDB{
|
||||||
disk: db,
|
disk: db,
|
||||||
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
||||||
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
|
codeCache: lru.NewSizeConstrainedCache[common.Hash, []byte](codeCacheSize),
|
||||||
triedb: triedb,
|
triedb: triedb.NewDatabase(db, config),
|
||||||
noTries: noTries,
|
noTries: noTries,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDatabaseWithNodeDB creates a state database with an already initialized node database.
|
// NewDatabaseWithNodeDB creates a state database with an already initialized node database.
|
||||||
func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database, needCommit bool) Database {
|
func NewDatabaseWithNodeDB(db ethdb.Database, triedb *triedb.Database) Database {
|
||||||
noTries := triedb != nil && triedb.Config() != nil && triedb.Config().NoTries
|
noTries := triedb != nil && triedb.Config() != nil && triedb.Config().NoTries
|
||||||
|
|
||||||
if triedb.Scheme() == rawdb.VersionScheme {
|
|
||||||
if needCommit {
|
|
||||||
return NewVersaDatabase(db, triedb, versa.S_COMMIT)
|
|
||||||
}
|
|
||||||
return NewVersaDatabase(db, triedb, versa.S_RW)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cachingDB{
|
return &cachingDB{
|
||||||
disk: db,
|
disk: db,
|
||||||
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
codeSizeCache: lru.NewCache[common.Hash, int](codeSizeCacheSize),
|
||||||
@@ -228,8 +185,6 @@ type cachingDB struct {
|
|||||||
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
|
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
|
||||||
triedb *triedb.Database
|
triedb *triedb.Database
|
||||||
noTries bool
|
noTries bool
|
||||||
|
|
||||||
//debug *DebugHashState
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenTrie opens the main account trie at a specific root hash.
|
// OpenTrie opens the main account trie at a specific root hash.
|
||||||
@@ -240,24 +195,14 @@ func (db *cachingDB) OpenTrie(root common.Hash) (Trie, error) {
|
|||||||
if db.triedb.IsVerkle() {
|
if db.triedb.IsVerkle() {
|
||||||
return trie.NewVerkleTrie(root, db.triedb, utils.NewPointCache(commitmentCacheItems))
|
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)
|
tr, err := trie.NewStateTrie(trie.StateTrieID(root), db.triedb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
//if db.debug != nil {
|
|
||||||
// db.debug.OnError(fmt.Errorf("failed to open tree, root: %s, error: %s", root.String(), err.Error()))
|
|
||||||
//}
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
//ht := &HashTrie{
|
|
||||||
// trie: tr,
|
|
||||||
// root: root,
|
|
||||||
// address: common.Address{},
|
|
||||||
// owner: common.Hash{},
|
|
||||||
// debug: db.debug,
|
|
||||||
//}
|
|
||||||
//if db.debug != nil {
|
|
||||||
// db.debug.OnOpenTree(root, common.Hash{}, common.Address{})
|
|
||||||
//}
|
|
||||||
//return ht, nil
|
|
||||||
return tr, nil
|
return tr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,27 +218,14 @@ func (db *cachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre
|
|||||||
if db.triedb.IsVerkle() {
|
if db.triedb.IsVerkle() {
|
||||||
return self, nil
|
return self, nil
|
||||||
}
|
}
|
||||||
owner := crypto.Keccak256Hash(address.Bytes())
|
// TODO
|
||||||
tr, err := trie.NewStateTrie(trie.StorageTrieID(stateRoot, owner, root), db.triedb)
|
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 {
|
if err != nil {
|
||||||
//if db.debug != nil {
|
|
||||||
// db.debug.OnError(fmt.Errorf("failed to storage open tree, stateRoot: %s, address: %s, root: %s, error: %s",
|
|
||||||
// stateRoot.String(), address.String(), root.String(), err.Error()))
|
|
||||||
//}
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
//ht := &HashTrie{
|
|
||||||
// trie: tr,
|
|
||||||
// root: stateRoot,
|
|
||||||
// statRoot: root,
|
|
||||||
// address: address,
|
|
||||||
// owner: owner,
|
|
||||||
// debug: db.debug,
|
|
||||||
//}
|
|
||||||
//if db.debug != nil {
|
|
||||||
// db.debug.OnOpenTree(root, owner, address)
|
|
||||||
//}
|
|
||||||
//return ht, nil
|
|
||||||
return tr, nil
|
return tr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,8 +243,6 @@ func (db *cachingDB) CopyTrie(t Trie) Trie {
|
|||||||
return t.Copy()
|
return t.Copy()
|
||||||
case *trie.EmptyTrie:
|
case *trie.EmptyTrie:
|
||||||
return t.Copy()
|
return t.Copy()
|
||||||
//case *HashTrie:
|
|
||||||
// return db.CopyTrie(t.trie)
|
|
||||||
default:
|
default:
|
||||||
panic(fmt.Errorf("unknown trie type %T", t))
|
panic(fmt.Errorf("unknown trie type %T", t))
|
||||||
}
|
}
|
||||||
@@ -320,9 +250,6 @@ func (db *cachingDB) CopyTrie(t Trie) Trie {
|
|||||||
|
|
||||||
// ContractCode retrieves a particular contract's code.
|
// ContractCode retrieves a particular contract's code.
|
||||||
func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) {
|
func (db *cachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) {
|
||||||
//if db.debug != nil {
|
|
||||||
// db.debug.OnGetCode(address, codeHash)
|
|
||||||
//}
|
|
||||||
code, _ := db.codeCache.Get(codeHash)
|
code, _ := db.codeCache.Get(codeHash)
|
||||||
if len(code) > 0 {
|
if len(code) > 0 {
|
||||||
return code, nil
|
return code, nil
|
||||||
@@ -371,179 +298,3 @@ func (db *cachingDB) DiskDB() ethdb.KeyValueStore {
|
|||||||
func (db *cachingDB) TrieDB() *triedb.Database {
|
func (db *cachingDB) TrieDB() *triedb.Database {
|
||||||
return db.triedb
|
return db.triedb
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *cachingDB) Reset() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *cachingDB) Scheme() string {
|
|
||||||
return db.triedb.Scheme()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *cachingDB) Flush() error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *cachingDB) Release() error {
|
|
||||||
//db.debug.flush()
|
|
||||||
//db.debug = nil
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *cachingDB) SetVersion(version int64) {
|
|
||||||
//db.debug = NewDebugHashState(db.disk)
|
|
||||||
//db.debug.Version = version
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *cachingDB) GetVersion() int64 {
|
|
||||||
//return db.debug.Version
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *cachingDB) Copy() Database {
|
|
||||||
return db
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *cachingDB) HasState(_ int64, root common.Hash) bool {
|
|
||||||
_, err := db.OpenTrie(root)
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *cachingDB) HasTreeExpired(_ Trie) bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
//type HashTrie struct {
|
|
||||||
// trie Trie
|
|
||||||
// root common.Hash
|
|
||||||
// statRoot common.Hash
|
|
||||||
// address common.Address
|
|
||||||
// owner common.Hash
|
|
||||||
//
|
|
||||||
// debug *DebugHashState
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (ht *HashTrie) GetKey(key []byte) []byte {
|
|
||||||
// return ht.trie.GetKey(key)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (ht *HashTrie) GetAccount(address common.Address) (*types.StateAccount, error) {
|
|
||||||
// acc, err := ht.trie.GetAccount(address)
|
|
||||||
// if err != nil {
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnError(fmt.Errorf("failed to get account, address: %s, error: %s", address.String(), err.Error()))
|
|
||||||
// }
|
|
||||||
// return nil, err
|
|
||||||
// }
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnGetAccount(address, acc)
|
|
||||||
// }
|
|
||||||
// return acc, nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (ht *HashTrie) GetStorage(addr common.Address, key []byte) ([]byte, error) {
|
|
||||||
// val, err := ht.trie.GetStorage(addr, key)
|
|
||||||
// if err != nil {
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnError(fmt.Errorf("failed to get storage, address: %s, error: %s", addr.String(), err.Error()))
|
|
||||||
// }
|
|
||||||
// return val, err
|
|
||||||
// }
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnGetStorage(addr, key, val)
|
|
||||||
// }
|
|
||||||
// return val, err
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (ht *HashTrie) UpdateAccount(address common.Address, account *types.StateAccount) error {
|
|
||||||
// err := ht.trie.UpdateAccount(address, account)
|
|
||||||
// if err != nil {
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnError(fmt.Errorf("failed to update account, address: %s, account: %s, error: %s",
|
|
||||||
// address.String(), account.String(), err.Error()))
|
|
||||||
// }
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnUpdateAccount(address, account)
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (ht *HashTrie) UpdateStorage(addr common.Address, key, value []byte) error {
|
|
||||||
// err := ht.trie.UpdateStorage(addr, key, value)
|
|
||||||
// if err != nil {
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnError(fmt.Errorf("failed to update storage, address: %s, key: %s, val: %s, error: %s",
|
|
||||||
// addr.String(), common.Bytes2Hex(key), common.Bytes2Hex(value), err.Error()))
|
|
||||||
// }
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnUpdateStorage(addr, key, value)
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (ht *HashTrie) DeleteAccount(address common.Address) error {
|
|
||||||
// err := ht.trie.DeleteAccount(address)
|
|
||||||
// if err != nil {
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnError(fmt.Errorf("failed to delete account, address: %s, error: %s", address.String(), err.Error()))
|
|
||||||
// }
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnDeleteAccount(address)
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (ht *HashTrie) DeleteStorage(addr common.Address, key []byte) error {
|
|
||||||
// err := ht.trie.DeleteStorage(addr, key)
|
|
||||||
// if err != nil {
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnError(fmt.Errorf("failed to update storage, address: %s, key: %s, error: %s",
|
|
||||||
// addr.String(), common.Bytes2Hex(key), err.Error()))
|
|
||||||
// }
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnDeleteStorage(addr, key)
|
|
||||||
// }
|
|
||||||
// return nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (ht *HashTrie) UpdateContractCode(address common.Address, codeHash common.Hash, code []byte) error {
|
|
||||||
// return ht.trie.UpdateContractCode(address, codeHash, code)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (ht *HashTrie) Hash() common.Hash {
|
|
||||||
// root := ht.trie.Hash()
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnCalcHash(ht.address, root)
|
|
||||||
// }
|
|
||||||
// return root
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (ht *HashTrie) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) {
|
|
||||||
// hash, set, err := ht.trie.Commit(collectLeaf)
|
|
||||||
// if err != nil {
|
|
||||||
// ht.debug.OnError(fmt.Errorf("failed to commit tree, address: %s, error: %s",
|
|
||||||
// ht.address.String(), err.Error()))
|
|
||||||
// return hash, set, err
|
|
||||||
// }
|
|
||||||
// if ht.debug != nil {
|
|
||||||
// ht.debug.OnCalcHash(ht.address, hash)
|
|
||||||
// ht.debug.OnCommitTree(ht.address, hash)
|
|
||||||
// }
|
|
||||||
// return hash, set, nil
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (ht *HashTrie) NodeIterator(startKey []byte) (trie.NodeIterator, error) {
|
|
||||||
// return ht.trie.NodeIterator(startKey)
|
|
||||||
//}
|
|
||||||
//
|
|
||||||
//func (ht *HashTrie) Prove(key []byte, proofDb ethdb.KeyValueWriter) error {
|
|
||||||
// return ht.trie.Prove(key, proofDb)
|
|
||||||
//}
|
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ func (s *StateDB) DumpToCollector(c DumpCollector, conf *DumpConfig) (nextKey []
|
|||||||
address = &addr
|
address = &addr
|
||||||
account.Address = address
|
account.Address = address
|
||||||
}
|
}
|
||||||
obj := newObject(s, addr, &data, InvalidSateObjectVersion)
|
obj := newObject(s, addr, &data)
|
||||||
if !conf.SkipCode {
|
if !conf.SkipCode {
|
||||||
account.Code = obj.Code()
|
account.Code = obj.Code()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,4 @@ var (
|
|||||||
slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil)
|
slotDeletionCount = metrics.NewRegisteredMeter("state/delete/storage/slot", nil)
|
||||||
slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil)
|
slotDeletionSize = metrics.NewRegisteredMeter("state/delete/storage/size", nil)
|
||||||
slotDeletionSkip = metrics.NewRegisteredGauge("state/delete/storage/skip", nil)
|
slotDeletionSkip = metrics.NewRegisteredGauge("state/delete/storage/skip", nil)
|
||||||
|
|
||||||
accountIntermediateRootTimer = metrics.NewRegisteredTimer("state/account/intermediate/root/time", nil)
|
|
||||||
storageIntermediateRootTimer = metrics.NewRegisteredTimer("state/storage/intermediate/root/time", nil)
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -232,7 +232,6 @@ func pruneAll(maindb ethdb.Database, g *core.Genesis) error {
|
|||||||
}
|
}
|
||||||
log.Info("Database compaction finished", "elapsed", common.PrettyDuration(time.Since(cstart)))
|
log.Info("Database compaction finished", "elapsed", common.PrettyDuration(time.Since(cstart)))
|
||||||
}
|
}
|
||||||
// pruner should be not used to version db
|
|
||||||
statedb, _ := state.New(common.Hash{}, state.NewDatabase(maindb), nil)
|
statedb, _ := state.New(common.Hash{}, state.NewDatabase(maindb), nil)
|
||||||
for addr, account := range g.Alloc {
|
for addr, account := range g.Alloc {
|
||||||
statedb.AddBalance(addr, uint256.MustFromBig(account.Balance))
|
statedb.AddBalance(addr, uint256.MustFromBig(account.Balance))
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
@@ -64,7 +63,6 @@ func (s Storage) Copy() Storage {
|
|||||||
// - Finally, call commit to return the changes of storage trie and update account data.
|
// - Finally, call commit to return the changes of storage trie and update account data.
|
||||||
type stateObject struct {
|
type stateObject struct {
|
||||||
db *StateDB
|
db *StateDB
|
||||||
version int64
|
|
||||||
address common.Address // address of ethereum account
|
address common.Address // address of ethereum account
|
||||||
addrHash common.Hash // hash of ethereum address of the account
|
addrHash common.Hash // hash of ethereum address of the account
|
||||||
origin *types.StateAccount // Account original data without any change applied, nil means it was not existent
|
origin *types.StateAccount // Account original data without any change applied, nil means it was not existent
|
||||||
@@ -101,7 +99,7 @@ func (s *stateObject) empty() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newObject creates a state object.
|
// newObject creates a state object.
|
||||||
func newObject(db *StateDB, address common.Address, acct *types.StateAccount, version int64) *stateObject {
|
func newObject(db *StateDB, address common.Address, acct *types.StateAccount) *stateObject {
|
||||||
var (
|
var (
|
||||||
origin = acct
|
origin = acct
|
||||||
created = acct == nil // true if the account was not existent
|
created = acct == nil // true if the account was not existent
|
||||||
@@ -114,9 +112,9 @@ func newObject(db *StateDB, address common.Address, acct *types.StateAccount, ve
|
|||||||
if db != nil && db.storagePool != nil {
|
if db != nil && db.storagePool != nil {
|
||||||
storageMap = db.GetStorage(address)
|
storageMap = db.GetStorage(address)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &stateObject{
|
return &stateObject{
|
||||||
db: db,
|
db: db,
|
||||||
version: version,
|
|
||||||
address: address,
|
address: address,
|
||||||
addrHash: crypto.Keccak256Hash(address[:]),
|
addrHash: crypto.Keccak256Hash(address[:]),
|
||||||
origin: origin,
|
origin: origin,
|
||||||
@@ -160,18 +158,8 @@ func (s *stateObject) getTrie() (Trie, error) {
|
|||||||
// s.trie = s.db.prefetcher.trie(s.addrHash, s.data.Root)
|
// s.trie = s.db.prefetcher.trie(s.addrHash, s.data.Root)
|
||||||
// }
|
// }
|
||||||
// if s.trie == nil {
|
// if s.trie == nil {
|
||||||
var (
|
tr, err := s.db.db.OpenStorageTrie(s.db.originalRoot, s.address, s.data.Root, s.db.trie)
|
||||||
tr Trie
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if s.version == InvalidSateObjectVersion {
|
|
||||||
tr, err = s.db.db.OpenStorageTrie(s.db.originalRoot, s.address, s.data.Root, s.db.trie)
|
|
||||||
} else {
|
|
||||||
tr, err = s.db.db.(*cachingVersaDB).openStorageTreeWithVersion(s.version, s.db.originalRoot, s.address, s.data.Root)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("open storage storage failed, root version: %d, storage version: %d, addrss: %s, storage root: %s, error: %s", s.db.db.GetVersion(), s.version, s.address.String(), s.data.Root.String(), err.Error()))
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s.trie = tr
|
s.trie = tr
|
||||||
@@ -235,21 +223,12 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
|
|||||||
return common.Hash{}
|
return common.Hash{}
|
||||||
}
|
}
|
||||||
// If no live objects are available, attempt to use snapshots
|
// If no live objects are available, attempt to use snapshots
|
||||||
|
|
||||||
defer func(start time.Time) {
|
|
||||||
stateDBGetTimer.UpdateSince(start)
|
|
||||||
stateDBGetQPS.Mark(1)
|
|
||||||
stateDBGetStorageTimer.UpdateSince(start)
|
|
||||||
stateDBGetStorageQPS.Mark(1)
|
|
||||||
}(time.Now())
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
enc []byte
|
enc []byte
|
||||||
err error
|
err error
|
||||||
value common.Hash
|
value common.Hash
|
||||||
)
|
)
|
||||||
if s.db.snap != nil {
|
if s.db.snap != nil {
|
||||||
panic("snap is not nil")
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes()))
|
enc, err = s.db.snap.Storage(s.addrHash, crypto.Keccak256Hash(key.Bytes()))
|
||||||
if metrics.EnabledExpensive {
|
if metrics.EnabledExpensive {
|
||||||
@@ -323,30 +302,6 @@ func (s *stateObject) finalise(prefetch bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateObject) IsContractAccount() bool {
|
|
||||||
return s.data.Root.Cmp(types.EmptyRootHash) != 0 ||
|
|
||||||
bytes.Compare(s.data.CodeHash, types.EmptyCodeHash.Bytes()) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stateObject) IsAccountChanged() bool {
|
|
||||||
if s.origin == nil {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if s.data.Nonce != s.origin.Nonce {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if s.data.Balance.Cmp(s.origin.Balance) != 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if s.data.Root.Cmp(s.origin.Root) != 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if bytes.Compare(s.data.CodeHash, s.origin.CodeHash) != 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// updateTrie is responsible for persisting cached storage changes into the
|
// updateTrie is responsible for persisting cached storage changes into the
|
||||||
// object's storage trie. In case the storage trie is not yet loaded, this
|
// object's storage trie. In case the storage trie is not yet loaded, this
|
||||||
// function will load the trie automatically. If any issues arise during the
|
// function will load the trie automatically. If any issues arise during the
|
||||||
@@ -357,28 +312,10 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||||||
// Make sure all dirty slots are finalized into the pending storage area
|
// Make sure all dirty slots are finalized into the pending storage area
|
||||||
s.finalise(false)
|
s.finalise(false)
|
||||||
|
|
||||||
// fix 33740 blocks issue, add 1002 contract balance, but not update 1002
|
// Short circuit if nothing changed, don't bother with hashing anything
|
||||||
// storage tree, the case lead to 1002 account version mismatch with 1002
|
if len(s.pendingStorage) == 0 {
|
||||||
// storage tree version, occurs 53409 block open 1002 storage tree error.
|
return s.trie, nil
|
||||||
if s.db.db.Scheme() == rawdb.VersionScheme {
|
|
||||||
if len(s.pendingStorage) == 0 {
|
|
||||||
// transferring balance to a contract or upgrading the code, but
|
|
||||||
// without updating the storage key, a commit is still required to
|
|
||||||
// increment the version number of the storage tree.
|
|
||||||
if !s.IsContractAccount() {
|
|
||||||
return s.trie, nil
|
|
||||||
}
|
|
||||||
//if !s.IsAccountChanged() {
|
|
||||||
// return s.trie, nil
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Short circuit if nothing changed, don't bother with hashing anything
|
|
||||||
if len(s.pendingStorage) == 0 {
|
|
||||||
return s.trie, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track the amount of time wasted on updating the storage trie
|
// Track the amount of time wasted on updating the storage trie
|
||||||
if metrics.EnabledExpensive {
|
if metrics.EnabledExpensive {
|
||||||
defer func(start time.Time) {
|
defer func(start time.Time) {
|
||||||
@@ -398,10 +335,6 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||||||
s.db.setError(err)
|
s.db.setError(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if len(s.pendingStorage) == 0 {
|
|
||||||
return s.trie, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert all the pending storage updates into the trie
|
// Insert all the pending storage updates into the trie
|
||||||
usedStorage := make([][]byte, 0, len(s.pendingStorage))
|
usedStorage := make([][]byte, 0, len(s.pendingStorage))
|
||||||
dirtyStorage := make(map[common.Hash][]byte)
|
dirtyStorage := make(map[common.Hash][]byte)
|
||||||
@@ -417,14 +350,11 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||||||
}
|
}
|
||||||
dirtyStorage[key] = v
|
dirtyStorage[key] = v
|
||||||
}
|
}
|
||||||
|
|
||||||
//storages := make(map[string][]byte)
|
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
for key, value := range dirtyStorage {
|
for key, value := range dirtyStorage {
|
||||||
//TODO:: add version schema check
|
|
||||||
if len(value) == 0 {
|
if len(value) == 0 {
|
||||||
if err := tr.DeleteStorage(s.address, key[:]); err != nil {
|
if err := tr.DeleteStorage(s.address, key[:]); err != nil {
|
||||||
s.db.setError(err)
|
s.db.setError(err)
|
||||||
@@ -436,16 +366,6 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
|||||||
}
|
}
|
||||||
s.db.StorageUpdated += 1
|
s.db.StorageUpdated += 1
|
||||||
}
|
}
|
||||||
//if len(value) == 0 {
|
|
||||||
// storages[string(key[:])] = nil
|
|
||||||
//} else {
|
|
||||||
// v, _ := rlp.EncodeToBytes(value)
|
|
||||||
// storages[string(key[:])] = v
|
|
||||||
//}
|
|
||||||
//if err := tr.WriteBatch(storages); err != nil {
|
|
||||||
// s.db.setError(err)
|
|
||||||
//}
|
|
||||||
|
|
||||||
// Cache the items for preloading
|
// Cache the items for preloading
|
||||||
usedStorage = append(usedStorage, common.CopyBytes(key[:]))
|
usedStorage = append(usedStorage, common.CopyBytes(key[:]))
|
||||||
}
|
}
|
||||||
@@ -532,11 +452,6 @@ func (s *stateObject) updateRoot() {
|
|||||||
// The returned set can be nil if nothing to commit. This function assumes all
|
// The returned set can be nil if nothing to commit. This function assumes all
|
||||||
// storage mutations have already been flushed into trie by updateRoot.
|
// storage mutations have already been flushed into trie by updateRoot.
|
||||||
func (s *stateObject) commit() (*trienode.NodeSet, error) {
|
func (s *stateObject) commit() (*trienode.NodeSet, error) {
|
||||||
if s.IsContractAccount() && s.trie == nil && s.db.db.GetVersion() != 0 {
|
|
||||||
panic(fmt.Sprintf("not open contract account, owner: %s, r_version: %d, c_version: %d, root: %s",
|
|
||||||
s.address.String(), s.db.db.GetVersion(), s.version, s.Root().String()))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Short circuit if trie is not even loaded, don't bother with committing anything
|
// Short circuit if trie is not even loaded, don't bother with committing anything
|
||||||
if s.trie == nil {
|
if s.trie == nil {
|
||||||
s.origin = s.data.Copy()
|
s.origin = s.data.Copy()
|
||||||
@@ -596,7 +511,6 @@ func (s *stateObject) setBalance(amount *uint256.Int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *stateObject) deepCopy(db *StateDB) *stateObject {
|
func (s *stateObject) deepCopy(db *StateDB) *stateObject {
|
||||||
//TODO:: debug code, deleted in the future
|
|
||||||
obj := &stateObject{
|
obj := &stateObject{
|
||||||
db: db,
|
db: db,
|
||||||
address: s.address,
|
address: s.address,
|
||||||
|
|||||||
@@ -54,16 +54,6 @@ type revision struct {
|
|||||||
journalIndex int
|
journalIndex int
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
stateDBGetTimer = metrics.NewRegisteredTimer("statedb/get/time", nil)
|
|
||||||
stateDBGetQPS = metrics.NewRegisteredMeter("statedb/get/qps", nil)
|
|
||||||
|
|
||||||
stateDBGetAccountTimer = metrics.NewRegisteredTimer("statedb/account/get/time", nil)
|
|
||||||
stateDBGetAccountQPS = metrics.NewRegisteredMeter("statedb/account/get/qps", nil)
|
|
||||||
stateDBGetStorageTimer = metrics.NewRegisteredTimer("statedb/storage/get/time", nil)
|
|
||||||
stateDBGetStorageQPS = metrics.NewRegisteredMeter("statedb/storage/get/qps", nil)
|
|
||||||
)
|
|
||||||
|
|
||||||
// StateDB structs within the ethereum protocol are used to store anything
|
// StateDB structs within the ethereum protocol are used to store anything
|
||||||
// within the merkle trie. StateDBs take care of caching and storing
|
// within the merkle trie. StateDBs take care of caching and storing
|
||||||
// nested states. It's the general query interface to retrieve:
|
// nested states. It's the general query interface to retrieve:
|
||||||
@@ -176,18 +166,12 @@ func NewWithSharedPool(root common.Hash, db Database, snaps *snapshot.Tree) (*St
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
//statedb.storagePool = NewStoragePool()
|
statedb.storagePool = NewStoragePool()
|
||||||
return statedb, nil
|
return statedb, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new state from a given trie.
|
// New creates a new state from a given trie.
|
||||||
func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) {
|
func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) {
|
||||||
if db.Scheme() == rawdb.VersionScheme && snaps != nil {
|
|
||||||
panic("statedb snapshot must be nil in version db.")
|
|
||||||
}
|
|
||||||
// clean up previous traces
|
|
||||||
db.Reset()
|
|
||||||
|
|
||||||
sdb := &StateDB{
|
sdb := &StateDB{
|
||||||
db: db,
|
db: db,
|
||||||
originalRoot: root,
|
originalRoot: root,
|
||||||
@@ -212,7 +196,6 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
|
|||||||
sdb.snap = sdb.snaps.Snapshot(root)
|
sdb.snap = sdb.snaps.Snapshot(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
// It should only one to open account tree
|
|
||||||
tr, err := db.OpenTrie(root)
|
tr, err := db.OpenTrie(root)
|
||||||
// return error when 1. failed to open trie and 2. the snap is nil or the snap is not nil and done verification
|
// return error when 1. failed to open trie and 2. the snap is nil or the snap is not nil and done verification
|
||||||
if err != nil && (sdb.snap == nil || sdb.snap.Verified()) {
|
if err != nil && (sdb.snap == nil || sdb.snap.Verified()) {
|
||||||
@@ -239,9 +222,6 @@ func (s *StateDB) TransferPrefetcher(prev *StateDB) {
|
|||||||
prev.prefetcherLock.Lock()
|
prev.prefetcherLock.Lock()
|
||||||
fetcher = prev.prefetcher
|
fetcher = prev.prefetcher
|
||||||
prev.prefetcher = nil
|
prev.prefetcher = nil
|
||||||
if fetcher != nil {
|
|
||||||
panic("TransferPrefetcher is not nil")
|
|
||||||
}
|
|
||||||
prev.prefetcherLock.Unlock()
|
prev.prefetcherLock.Unlock()
|
||||||
|
|
||||||
s.prefetcherLock.Lock()
|
s.prefetcherLock.Lock()
|
||||||
@@ -263,8 +243,6 @@ func (s *StateDB) StartPrefetcher(namespace string) {
|
|||||||
s.prefetcher = nil
|
s.prefetcher = nil
|
||||||
}
|
}
|
||||||
if s.snap != nil {
|
if s.snap != nil {
|
||||||
// TODO:: debug code , will be deleted in the future
|
|
||||||
panic("snapshot is not nill, will start prefetch")
|
|
||||||
parent := s.snap.Parent()
|
parent := s.snap.Parent()
|
||||||
if parent != nil {
|
if parent != nil {
|
||||||
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, parent.Root(), namespace)
|
s.prefetcher = newTriePrefetcher(s.db, s.originalRoot, parent.Root(), namespace)
|
||||||
@@ -327,7 +305,6 @@ func (s *StateDB) EnablePipeCommit() {
|
|||||||
if s.snap != nil && s.snaps.Layers() > 1 {
|
if s.snap != nil && s.snaps.Layers() > 1 {
|
||||||
// after big merge, disable pipeCommit for now,
|
// after big merge, disable pipeCommit for now,
|
||||||
// because `s.db.TrieDB().Update` should be called after `s.trie.Commit(true)`
|
// because `s.db.TrieDB().Update` should be called after `s.trie.Commit(true)`
|
||||||
panic("snapshot is not nil")
|
|
||||||
s.pipeCommit = false
|
s.pipeCommit = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -346,8 +323,6 @@ func (s *StateDB) MarkFullProcessed() {
|
|||||||
func (s *StateDB) setError(err error) {
|
func (s *StateDB) setError(err error) {
|
||||||
if s.dbErr == nil {
|
if s.dbErr == nil {
|
||||||
s.dbErr = err
|
s.dbErr = err
|
||||||
} else {
|
|
||||||
s.dbErr = fmt.Errorf(s.dbErr.Error()+", ", err.Error())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,8 +338,6 @@ func (s *StateDB) Error() error {
|
|||||||
// Not thread safe
|
// Not thread safe
|
||||||
func (s *StateDB) Trie() (Trie, error) {
|
func (s *StateDB) Trie() (Trie, error) {
|
||||||
if s.trie == nil {
|
if s.trie == nil {
|
||||||
// TODO:: debug code, will be deleted in the future.
|
|
||||||
panic("state get trie is nil")
|
|
||||||
err := s.WaitPipeVerification()
|
err := s.WaitPipeVerification()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -692,7 +665,6 @@ func (s *StateDB) updateStateObject(obj *stateObject) {
|
|||||||
if err := s.trie.UpdateAccount(addr, &obj.data); err != nil {
|
if err := s.trie.UpdateAccount(addr, &obj.data); err != nil {
|
||||||
s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err))
|
s.setError(fmt.Errorf("updateStateObject (%x) error: %v", addr[:], err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if obj.dirtyCode {
|
if obj.dirtyCode {
|
||||||
s.trie.UpdateContractCode(obj.Address(), common.BytesToHash(obj.CodeHash()), obj.code)
|
s.trie.UpdateContractCode(obj.Address(), common.BytesToHash(obj.CodeHash()), obj.code)
|
||||||
}
|
}
|
||||||
@@ -720,7 +692,6 @@ func (s *StateDB) deleteStateObject(obj *stateObject) {
|
|||||||
}
|
}
|
||||||
// Delete the account from the trie
|
// Delete the account from the trie
|
||||||
addr := obj.Address()
|
addr := obj.Address()
|
||||||
|
|
||||||
if err := s.trie.DeleteAccount(addr); err != nil {
|
if err := s.trie.DeleteAccount(addr); err != nil {
|
||||||
s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err))
|
s.setError(fmt.Errorf("deleteStateObject (%x) error: %v", addr[:], err))
|
||||||
}
|
}
|
||||||
@@ -745,18 +716,9 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
|
|||||||
if obj := s.stateObjects[addr]; obj != nil {
|
if obj := s.stateObjects[addr]; obj != nil {
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func(start time.Time) {
|
|
||||||
stateDBGetTimer.UpdateSince(start)
|
|
||||||
stateDBGetQPS.Mark(1)
|
|
||||||
stateDBGetAccountTimer.UpdateSince(start)
|
|
||||||
stateDBGetAccountQPS.Mark(1)
|
|
||||||
}(time.Now())
|
|
||||||
|
|
||||||
// If no live objects are available, attempt to use snapshots
|
// If no live objects are available, attempt to use snapshots
|
||||||
var data *types.StateAccount
|
var data *types.StateAccount
|
||||||
if s.snap != nil {
|
if s.snap != nil {
|
||||||
panic("snapshot is not nil")
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
acc, err := s.snap.Account(crypto.HashData(s.hasher, addr.Bytes()))
|
acc, err := s.snap.Account(crypto.HashData(s.hasher, addr.Bytes()))
|
||||||
if metrics.EnabledExpensive {
|
if metrics.EnabledExpensive {
|
||||||
@@ -781,12 +743,9 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
version := InvalidSateObjectVersion
|
|
||||||
// If snapshot unavailable or reading from it failed, load from the database
|
// If snapshot unavailable or reading from it failed, load from the database
|
||||||
if data == nil {
|
if data == nil {
|
||||||
if s.trie == nil {
|
if s.trie == nil {
|
||||||
// TODO:: debug code, will be deleted in the future.
|
|
||||||
panic("getDeletedStateObject get trie is nil")
|
|
||||||
tr, err := s.db.OpenTrie(s.originalRoot)
|
tr, err := s.db.OpenTrie(s.originalRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.setError(errors.New("failed to open trie tree"))
|
s.setError(errors.New("failed to open trie tree"))
|
||||||
@@ -796,12 +755,7 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
|
|||||||
}
|
}
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
var err error
|
var err error
|
||||||
if vtr, ok := s.trie.(*VersaTree); ok {
|
data, err = s.trie.GetAccount(addr)
|
||||||
version, data, err = vtr.getAccountWithVersion(addr)
|
|
||||||
} else {
|
|
||||||
data, err = s.trie.GetAccount(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
if metrics.EnabledExpensive {
|
if metrics.EnabledExpensive {
|
||||||
s.AccountReads += time.Since(start)
|
s.AccountReads += time.Since(start)
|
||||||
}
|
}
|
||||||
@@ -814,7 +768,7 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Insert into the live set
|
// Insert into the live set
|
||||||
obj := newObject(s, addr, data, version)
|
obj := newObject(s, addr, data)
|
||||||
s.setStateObject(obj)
|
s.setStateObject(obj)
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
@@ -836,7 +790,7 @@ func (s *StateDB) getOrNewStateObject(addr common.Address) *stateObject {
|
|||||||
// the given address, it is overwritten and returned as the second return value.
|
// the given address, it is overwritten and returned as the second return value.
|
||||||
func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
|
func (s *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
|
||||||
prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that!
|
prev = s.getDeletedStateObject(addr) // Note, prev might have been deleted, we need that!
|
||||||
newobj = newObject(s, addr, nil, InvalidSateObjectVersion)
|
newobj = newObject(s, addr, nil)
|
||||||
if prev == nil {
|
if prev == nil {
|
||||||
s.journal.append(createObjectChange{account: &addr})
|
s.journal.append(createObjectChange{account: &addr})
|
||||||
} else {
|
} else {
|
||||||
@@ -905,12 +859,10 @@ func (s *StateDB) CopyDoPrefetch() *StateDB {
|
|||||||
// If doPrefetch is true, it tries to reuse the prefetcher, the copied StateDB will do active trie prefetch.
|
// If doPrefetch is true, it tries to reuse the prefetcher, the copied StateDB will do active trie prefetch.
|
||||||
// otherwise, just do inactive copy trie prefetcher.
|
// otherwise, just do inactive copy trie prefetcher.
|
||||||
func (s *StateDB) copyInternal(doPrefetch bool) *StateDB {
|
func (s *StateDB) copyInternal(doPrefetch bool) *StateDB {
|
||||||
db := s.db.Copy()
|
|
||||||
tr := db.CopyTrie(s.trie)
|
|
||||||
// Copy all the basic fields, initialize the memory ones
|
// Copy all the basic fields, initialize the memory ones
|
||||||
state := &StateDB{
|
state := &StateDB{
|
||||||
db: db,
|
db: s.db,
|
||||||
trie: tr,
|
trie: s.db.CopyTrie(s.trie),
|
||||||
// noTrie:s.noTrie,
|
// noTrie:s.noTrie,
|
||||||
// expectedRoot: s.expectedRoot,
|
// expectedRoot: s.expectedRoot,
|
||||||
// stateRoot: s.stateRoot,
|
// stateRoot: s.stateRoot,
|
||||||
@@ -1051,7 +1003,6 @@ func (s *StateDB) GetRefund() uint64 {
|
|||||||
func (s *StateDB) WaitPipeVerification() error {
|
func (s *StateDB) WaitPipeVerification() error {
|
||||||
// Need to wait for the parent trie to commit
|
// Need to wait for the parent trie to commit
|
||||||
if s.snap != nil {
|
if s.snap != nil {
|
||||||
panic("snapshot is not nil")
|
|
||||||
if valid := s.snap.WaitAndGetVerifyRes(); !valid {
|
if valid := s.snap.WaitAndGetVerifyRes(); !valid {
|
||||||
return errors.New("verification on parent snap failed")
|
return errors.New("verification on parent snap failed")
|
||||||
}
|
}
|
||||||
@@ -1157,7 +1108,6 @@ func (s *StateDB) PopulateSnapAccountAndStorage() {
|
|||||||
for addr := range s.stateObjectsPending {
|
for addr := range s.stateObjectsPending {
|
||||||
if obj := s.stateObjects[addr]; !obj.deleted {
|
if obj := s.stateObjects[addr]; !obj.deleted {
|
||||||
if s.snap != nil {
|
if s.snap != nil {
|
||||||
panic("snapshot is not nil")
|
|
||||||
s.populateSnapStorage(obj)
|
s.populateSnapStorage(obj)
|
||||||
s.accounts[obj.addrHash] = types.SlimAccountRLP(obj.data)
|
s.accounts[obj.addrHash] = types.SlimAccountRLP(obj.data)
|
||||||
}
|
}
|
||||||
@@ -1197,10 +1147,6 @@ func (s *StateDB) populateSnapStorage(obj *stateObject) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) AccountsIntermediateRoot() {
|
func (s *StateDB) AccountsIntermediateRoot() {
|
||||||
defer func(start time.Time) {
|
|
||||||
storageIntermediateRootTimer.UpdateSince(start)
|
|
||||||
}(time.Now())
|
|
||||||
|
|
||||||
tasks := make(chan func())
|
tasks := make(chan func())
|
||||||
finishCh := make(chan struct{})
|
finishCh := make(chan struct{})
|
||||||
defer close(finishCh)
|
defer close(finishCh)
|
||||||
@@ -1228,6 +1174,7 @@ func (s *StateDB) AccountsIntermediateRoot() {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
tasks <- func() {
|
tasks <- func() {
|
||||||
obj.updateRoot()
|
obj.updateRoot()
|
||||||
|
|
||||||
// Cache the data until commit. Note, this update mechanism is not symmetric
|
// Cache the data until commit. Note, this update mechanism is not symmetric
|
||||||
// to the deletion, because whereas it is enough to track account updates
|
// to the deletion, because whereas it is enough to track account updates
|
||||||
// at commit time, deletions need tracking at transaction boundary level to
|
// at commit time, deletions need tracking at transaction boundary level to
|
||||||
@@ -1244,9 +1191,6 @@ func (s *StateDB) AccountsIntermediateRoot() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) StateIntermediateRoot() common.Hash {
|
func (s *StateDB) StateIntermediateRoot() common.Hash {
|
||||||
defer func(start time.Time) {
|
|
||||||
accountIntermediateRootTimer.UpdateSince(start)
|
|
||||||
}(time.Now())
|
|
||||||
// If there was a trie prefetcher operating, it gets aborted and irrevocably
|
// If there was a trie prefetcher operating, it gets aborted and irrevocably
|
||||||
// modified after we start retrieving tries. Remove it from the statedb after
|
// modified after we start retrieving tries. Remove it from the statedb after
|
||||||
// this round of use.
|
// this round of use.
|
||||||
@@ -1266,8 +1210,6 @@ func (s *StateDB) StateIntermediateRoot() common.Hash {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.trie == nil {
|
if s.trie == nil {
|
||||||
// TODO:: debug code, will be deleted in the future.
|
|
||||||
panic("StateIntermediateRoot get trie is nil")
|
|
||||||
tr, err := s.db.OpenTrie(s.originalRoot)
|
tr, err := s.db.OpenTrie(s.originalRoot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("failed to open trie tree %s", s.originalRoot))
|
panic(fmt.Sprintf("failed to open trie tree %s", s.originalRoot))
|
||||||
@@ -1427,7 +1369,6 @@ func (s *StateDB) deleteStorage(addr common.Address, addrHash common.Hash, root
|
|||||||
// generated, or it's internally corrupted. Fallback to the slow
|
// generated, or it's internally corrupted. Fallback to the slow
|
||||||
// one just in case.
|
// one just in case.
|
||||||
if s.snap != nil {
|
if s.snap != nil {
|
||||||
panic("snapshot is not nil")
|
|
||||||
aborted, size, slots, nodes, err = s.fastDeleteStorage(addrHash, root)
|
aborted, size, slots, nodes, err = s.fastDeleteStorage(addrHash, root)
|
||||||
}
|
}
|
||||||
if s.snap == nil || err != nil {
|
if s.snap == nil || err != nil {
|
||||||
@@ -1481,8 +1422,7 @@ func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) (map[common.A
|
|||||||
// considerable time and storage deletion isn't supported in hash mode, thus
|
// considerable time and storage deletion isn't supported in hash mode, thus
|
||||||
// preemptively avoiding unnecessary expenses.
|
// preemptively avoiding unnecessary expenses.
|
||||||
incomplete := make(map[common.Address]struct{})
|
incomplete := make(map[common.Address]struct{})
|
||||||
// Only pbss need handler incomplete destruction storage trie
|
if s.db.TrieDB().Scheme() == rawdb.HashScheme {
|
||||||
if s.db.TrieDB().Scheme() != rawdb.PathScheme {
|
|
||||||
return incomplete, nil
|
return incomplete, nil
|
||||||
}
|
}
|
||||||
for addr, prev := range s.stateObjectsDestruct {
|
for addr, prev := range s.stateObjectsDestruct {
|
||||||
@@ -1558,7 +1498,6 @@ func (s *StateDB) Commit(block uint64, failPostCommitFunc func(), postCommitFunc
|
|||||||
)
|
)
|
||||||
|
|
||||||
if s.snap != nil {
|
if s.snap != nil {
|
||||||
panic("snapshot is not nil")
|
|
||||||
diffLayer = &types.DiffLayer{}
|
diffLayer = &types.DiffLayer{}
|
||||||
}
|
}
|
||||||
if s.pipeCommit {
|
if s.pipeCommit {
|
||||||
@@ -1674,33 +1613,18 @@ func (s *StateDB) Commit(block uint64, failPostCommitFunc func(), postCommitFunc
|
|||||||
origin = types.EmptyRootHash
|
origin = types.EmptyRootHash
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.db.Scheme() == rawdb.VersionScheme {
|
if root != origin {
|
||||||
// flush and release will occur regardless of whether the root changes
|
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
if err := s.db.Flush(); err != nil {
|
set := triestate.New(s.accountsOrigin, s.storagesOrigin, incomplete)
|
||||||
|
if err := s.db.TrieDB().Update(root, origin, block, nodes, set); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
//if err := s.db.Release(); err != nil {
|
|
||||||
// return err
|
|
||||||
//}
|
|
||||||
s.originalRoot = root
|
s.originalRoot = root
|
||||||
if metrics.EnabledExpensive {
|
if metrics.EnabledExpensive {
|
||||||
s.TrieDBCommits += time.Since(start)
|
s.TrieDBCommits += time.Since(start)
|
||||||
}
|
}
|
||||||
} else {
|
if s.onCommit != nil {
|
||||||
if root != origin {
|
s.onCommit(set)
|
||||||
start := time.Now()
|
|
||||||
set := triestate.New(s.accountsOrigin, s.storagesOrigin, incomplete)
|
|
||||||
if err := s.db.TrieDB().Update(root, origin, block, nodes, set); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
s.originalRoot = root
|
|
||||||
if metrics.EnabledExpensive {
|
|
||||||
s.TrieDBCommits += time.Since(start)
|
|
||||||
}
|
|
||||||
if s.onCommit != nil {
|
|
||||||
s.onCommit(set)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1739,21 +1663,8 @@ func (s *StateDB) Commit(block uint64, failPostCommitFunc func(), postCommitFunc
|
|||||||
// Write any contract code associated with the state object
|
// Write any contract code associated with the state object
|
||||||
if obj.code != nil && obj.dirtyCode {
|
if obj.code != nil && obj.dirtyCode {
|
||||||
rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code)
|
rawdb.WriteCode(codeWriter, common.BytesToHash(obj.CodeHash()), obj.code)
|
||||||
//switch d := s.db.(type) {
|
|
||||||
//case *cachingVersaDB:
|
|
||||||
// if d.debug != nil {
|
|
||||||
// d.debug.OnUpdateCode(obj.address, common.BytesToHash(obj.CodeHash()))
|
|
||||||
// }
|
|
||||||
//case *cachingDB:
|
|
||||||
// if d.debug != nil {
|
|
||||||
// d.debug.OnUpdateCode(obj.address, common.BytesToHash(obj.CodeHash()))
|
|
||||||
// }
|
|
||||||
//default:
|
|
||||||
// panic("caching db type error")
|
|
||||||
//}
|
|
||||||
obj.dirtyCode = false
|
obj.dirtyCode = false
|
||||||
if s.snap != nil {
|
if s.snap != nil {
|
||||||
panic("snapshot is not nil")
|
|
||||||
diffLayer.Codes = append(diffLayer.Codes, types.DiffCode{
|
diffLayer.Codes = append(diffLayer.Codes, types.DiffCode{
|
||||||
Hash: common.BytesToHash(obj.CodeHash()),
|
Hash: common.BytesToHash(obj.CodeHash()),
|
||||||
Code: obj.code,
|
Code: obj.code,
|
||||||
@@ -1779,7 +1690,6 @@ func (s *StateDB) Commit(block uint64, failPostCommitFunc func(), postCommitFunc
|
|||||||
func() error {
|
func() error {
|
||||||
// If snapshotting is enabled, update the snapshot tree with this new version
|
// If snapshotting is enabled, update the snapshot tree with this new version
|
||||||
if s.snap != nil {
|
if s.snap != nil {
|
||||||
panic("snapshot is not nil")
|
|
||||||
if metrics.EnabledExpensive {
|
if metrics.EnabledExpensive {
|
||||||
defer func(start time.Time) { s.SnapshotCommits += time.Since(start) }(time.Now())
|
defer func(start time.Time) { s.SnapshotCommits += time.Since(start) }(time.Now())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,207 +0,0 @@
|
|||||||
package state
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
VersionState = "version"
|
|
||||||
HashState = "hash"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DebugStateDiff struct {
|
|
||||||
DiffUpdateAccount map[string][]*VersaAccountInfo
|
|
||||||
DiffDeleteAccount map[string][]common.Address
|
|
||||||
|
|
||||||
DiffUpdateStorage map[string][]*VersaStorageInfo
|
|
||||||
DiffDeleteStorage map[string][]*VersaStorageInfo
|
|
||||||
|
|
||||||
DiffCalcHash map[string]map[common.Address]common.Hash
|
|
||||||
OwnerMap map[common.Address]common.Hash
|
|
||||||
DiffErrs map[string][]string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (df *DebugStateDiff) diffUpdateAccount(vs []*VersaAccountInfo, hs []*VersaAccountInfo) {
|
|
||||||
count := len(vs)
|
|
||||||
if count > len(hs) {
|
|
||||||
count = len(hs)
|
|
||||||
}
|
|
||||||
idx := 0
|
|
||||||
for ; idx < count; idx++ {
|
|
||||||
if vs[idx].Address.Cmp(hs[idx].Address) != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if vs[idx].Account.Nonce != hs[idx].Account.Nonce {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if vs[idx].Account.Balance.Cmp(hs[idx].Account.Balance) != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if vs[idx].Account.Root.Cmp(hs[idx].Account.Root) != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if common.BytesToHash(vs[idx].Account.CodeHash).Cmp(common.BytesToHash(hs[idx].Account.CodeHash)) != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if idx < len(vs) {
|
|
||||||
df.DiffUpdateAccount[VersionState] = vs[idx:]
|
|
||||||
}
|
|
||||||
if idx < len(hs) {
|
|
||||||
df.DiffUpdateAccount[HashState] = hs[idx:]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (df *DebugStateDiff) diffDeleteAccount(vs []common.Address, hs []common.Address) {
|
|
||||||
count := len(vs)
|
|
||||||
if count > len(hs) {
|
|
||||||
count = len(hs)
|
|
||||||
}
|
|
||||||
idx := 0
|
|
||||||
for ; idx < count; idx++ {
|
|
||||||
if vs[idx].Cmp(hs[idx]) != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if idx < len(vs) {
|
|
||||||
df.DiffDeleteAccount[VersionState] = vs[idx:]
|
|
||||||
}
|
|
||||||
if idx < len(hs) {
|
|
||||||
df.DiffDeleteAccount[HashState] = hs[idx:]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (df *DebugStateDiff) diffUpdateStorage(vs []*VersaStorageInfo, hs []*VersaStorageInfo) {
|
|
||||||
count := len(vs)
|
|
||||||
if count > len(hs) {
|
|
||||||
count = len(hs)
|
|
||||||
}
|
|
||||||
idx := 0
|
|
||||||
for ; idx < count; idx++ {
|
|
||||||
if vs[idx].Address.Cmp(hs[idx].Address) != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if vs[idx].Key != hs[idx].Key {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if vs[idx].Val != hs[idx].Val {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if idx < len(vs) {
|
|
||||||
df.DiffUpdateStorage[VersionState] = vs[idx:]
|
|
||||||
}
|
|
||||||
if idx < len(hs) {
|
|
||||||
df.DiffUpdateStorage[HashState] = hs[idx:]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (df *DebugStateDiff) diffDeleteStorage(vs []*VersaStorageInfo, hs []*VersaStorageInfo) {
|
|
||||||
count := len(vs)
|
|
||||||
if count > len(hs) {
|
|
||||||
count = len(hs)
|
|
||||||
}
|
|
||||||
idx := 0
|
|
||||||
for ; idx < count; idx++ {
|
|
||||||
if vs[idx].Address.Cmp(hs[idx].Address) != 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if vs[idx].Key != hs[idx].Key {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if idx < len(vs) {
|
|
||||||
df.DiffDeleteStorage[VersionState] = vs[idx:]
|
|
||||||
}
|
|
||||||
if idx < len(hs) {
|
|
||||||
df.DiffDeleteStorage[HashState] = hs[idx:]
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (df *DebugStateDiff) diffCalcHash(vs map[common.Address]common.Hash, hs map[common.Address]common.Hash) {
|
|
||||||
record := make(map[common.Address]struct{})
|
|
||||||
for address, vch := range vs {
|
|
||||||
record[address] = struct{}{}
|
|
||||||
hch, ok := hs[address]
|
|
||||||
if !ok {
|
|
||||||
df.DiffCalcHash[VersionState][address] = vch
|
|
||||||
}
|
|
||||||
if vch.Cmp(hch) != 0 {
|
|
||||||
df.DiffCalcHash[VersionState][address] = vch
|
|
||||||
df.DiffCalcHash[HashState][address] = hch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for address := range record {
|
|
||||||
delete(vs, address)
|
|
||||||
delete(hs, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
for address, hash := range vs {
|
|
||||||
df.DiffCalcHash[VersionState][address] = hash
|
|
||||||
}
|
|
||||||
|
|
||||||
for address, hash := range hs {
|
|
||||||
df.DiffCalcHash[HashState][address] = hash
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GenerateDebugStateDiff(vs *DebugVersionState, hs *DebugHashState) string {
|
|
||||||
diff := &DebugStateDiff{
|
|
||||||
DiffUpdateAccount: make(map[string][]*VersaAccountInfo),
|
|
||||||
DiffDeleteAccount: make(map[string][]common.Address),
|
|
||||||
|
|
||||||
DiffUpdateStorage: make(map[string][]*VersaStorageInfo),
|
|
||||||
DiffDeleteStorage: make(map[string][]*VersaStorageInfo),
|
|
||||||
|
|
||||||
DiffCalcHash: make(map[string]map[common.Address]common.Hash),
|
|
||||||
OwnerMap: make(map[common.Address]common.Hash),
|
|
||||||
DiffErrs: make(map[string][]string),
|
|
||||||
}
|
|
||||||
diff.DiffUpdateAccount[VersionState] = make([]*VersaAccountInfo, 0)
|
|
||||||
diff.DiffUpdateAccount[HashState] = make([]*VersaAccountInfo, 0)
|
|
||||||
diff.DiffDeleteAccount[VersionState] = make([]common.Address, 0)
|
|
||||||
diff.DiffDeleteAccount[HashState] = make([]common.Address, 0)
|
|
||||||
|
|
||||||
diff.DiffUpdateStorage[VersionState] = make([]*VersaStorageInfo, 0)
|
|
||||||
diff.DiffUpdateStorage[HashState] = make([]*VersaStorageInfo, 0)
|
|
||||||
diff.DiffDeleteStorage[VersionState] = make([]*VersaStorageInfo, 0)
|
|
||||||
diff.DiffDeleteStorage[HashState] = make([]*VersaStorageInfo, 0)
|
|
||||||
|
|
||||||
diff.DiffCalcHash[VersionState] = make(map[common.Address]common.Hash)
|
|
||||||
diff.DiffCalcHash[HashState] = make(map[common.Address]common.Hash)
|
|
||||||
|
|
||||||
diff.DiffErrs[VersionState] = make([]string, 0)
|
|
||||||
diff.DiffErrs[HashState] = make([]string, 0)
|
|
||||||
|
|
||||||
diff.diffUpdateAccount(vs.UpdateAccounts, hs.UpdateAccounts)
|
|
||||||
diff.diffDeleteAccount(vs.DeleteAccounts, hs.DeleteAccounts)
|
|
||||||
diff.diffUpdateStorage(vs.UpdateStorage, hs.UpdateStorage)
|
|
||||||
diff.diffDeleteStorage(vs.DeleteStorage, hs.DeleteStorage)
|
|
||||||
diff.diffCalcHash(vs.CalcHash, hs.CalcHash)
|
|
||||||
|
|
||||||
for address, _ := range diff.DiffCalcHash[HashState] {
|
|
||||||
diff.OwnerMap[address] = hs.StorageAddr2Owner[address]
|
|
||||||
}
|
|
||||||
for address, _ := range diff.DiffCalcHash[VersionState] {
|
|
||||||
diff.OwnerMap[address] = vs.StorageAddr2Owner[address]
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(vs.Errs) != 0 || len(hs.Errs) != 0 {
|
|
||||||
diff.DiffErrs[VersionState] = vs.Errs
|
|
||||||
diff.DiffErrs[HashState] = hs.Errs
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := json.Marshal(diff)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to json encode debug info, err: %s", err.Error()))
|
|
||||||
}
|
|
||||||
return string(data)
|
|
||||||
}
|
|
||||||
@@ -1,216 +0,0 @@
|
|||||||
package state
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DebugHashState struct {
|
|
||||||
disk ethdb.KeyValueStore
|
|
||||||
lock sync.Mutex
|
|
||||||
|
|
||||||
Version int64
|
|
||||||
AccessTrees map[common.Address][]common.Hash
|
|
||||||
CommitTrees map[common.Address][]common.Hash
|
|
||||||
CalcHash map[common.Address]common.Hash
|
|
||||||
|
|
||||||
GetAccounts []*VersaAccountInfo
|
|
||||||
UpdateAccounts []*VersaAccountInfo
|
|
||||||
DeleteAccounts []common.Address
|
|
||||||
|
|
||||||
GetStorage []*VersaStorageInfo
|
|
||||||
UpdateStorage []*VersaStorageInfo
|
|
||||||
DeleteStorage []*VersaStorageInfo
|
|
||||||
StorageAddr2Owner map[common.Address]common.Hash
|
|
||||||
|
|
||||||
GetCode map[common.Address][]common.Hash
|
|
||||||
UpdateCode map[common.Address][]common.Hash
|
|
||||||
|
|
||||||
Errs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDebugHashState(disk ethdb.KeyValueStore) *DebugHashState {
|
|
||||||
return &DebugHashState{
|
|
||||||
disk: disk,
|
|
||||||
AccessTrees: make(map[common.Address][]common.Hash),
|
|
||||||
CommitTrees: make(map[common.Address][]common.Hash),
|
|
||||||
CalcHash: make(map[common.Address]common.Hash),
|
|
||||||
GetAccounts: make([]*VersaAccountInfo, 0),
|
|
||||||
UpdateAccounts: make([]*VersaAccountInfo, 0),
|
|
||||||
DeleteAccounts: make([]common.Address, 0),
|
|
||||||
GetStorage: make([]*VersaStorageInfo, 0),
|
|
||||||
UpdateStorage: make([]*VersaStorageInfo, 0),
|
|
||||||
DeleteStorage: make([]*VersaStorageInfo, 0),
|
|
||||||
StorageAddr2Owner: make(map[common.Address]common.Hash),
|
|
||||||
GetCode: make(map[common.Address][]common.Hash),
|
|
||||||
UpdateCode: make(map[common.Address][]common.Hash),
|
|
||||||
Errs: make([]string, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) OnOpenTree(root common.Hash, owner common.Hash, address common.Address) {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
|
|
||||||
if _, ok := hs.AccessTrees[address]; !ok {
|
|
||||||
hs.AccessTrees[address] = make([]common.Hash, 0)
|
|
||||||
}
|
|
||||||
hs.AccessTrees[address] = append(hs.AccessTrees[address], root)
|
|
||||||
hs.StorageAddr2Owner[address] = owner
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) OnGetAccount(addr common.Address, acc *types.StateAccount) {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
hs.GetAccounts = append(hs.GetAccounts, &VersaAccountInfo{
|
|
||||||
Address: addr,
|
|
||||||
Account: acc,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) OnUpdateAccount(addr common.Address, acc *types.StateAccount) {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
hs.UpdateAccounts = append(hs.UpdateAccounts, &VersaAccountInfo{
|
|
||||||
Address: addr,
|
|
||||||
Account: acc,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) OnDeleteAccount(address common.Address) {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
hs.DeleteAccounts = append(hs.DeleteAccounts, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) OnGetStorage(address common.Address, key []byte, val []byte) {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
|
|
||||||
hs.GetStorage = append(hs.GetStorage, &VersaStorageInfo{
|
|
||||||
Address: address,
|
|
||||||
Key: common.Bytes2Hex(key),
|
|
||||||
Val: common.Bytes2Hex(val),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) OnUpdateStorage(address common.Address, key []byte, val []byte) {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
|
|
||||||
hs.UpdateStorage = append(hs.UpdateStorage, &VersaStorageInfo{
|
|
||||||
Address: address,
|
|
||||||
Key: common.Bytes2Hex(key),
|
|
||||||
Val: common.Bytes2Hex(val),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) OnDeleteStorage(address common.Address, key []byte) {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
|
|
||||||
hs.DeleteStorage = append(hs.DeleteStorage, &VersaStorageInfo{
|
|
||||||
Address: address,
|
|
||||||
Key: common.Bytes2Hex(key),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) OnGetCode(addr common.Address, codeHash common.Hash) {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
if _, ok := hs.GetCode[addr]; !ok {
|
|
||||||
hs.GetCode[addr] = make([]common.Hash, 0)
|
|
||||||
}
|
|
||||||
hs.GetCode[addr] = append(hs.GetCode[addr], codeHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) OnUpdateCode(addr common.Address, codeHash common.Hash) {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
if _, ok := hs.UpdateCode[addr]; !ok {
|
|
||||||
hs.UpdateCode[addr] = make([]common.Hash, 0)
|
|
||||||
}
|
|
||||||
hs.UpdateCode[addr] = append(hs.UpdateCode[addr], codeHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) OnCalcHash(addr common.Address, root common.Hash) {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
hs.CalcHash[addr] = root
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) OnCommitTree(addr common.Address, root common.Hash) {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
if _, ok := hs.CommitTrees[addr]; !ok {
|
|
||||||
hs.CommitTrees[addr] = make([]common.Hash, 0)
|
|
||||||
}
|
|
||||||
hs.CommitTrees[addr] = append(hs.CommitTrees[addr], root)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) OnError(err error) {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
hs.Errs = append(hs.Errs, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) flush() {
|
|
||||||
hs.lock.Lock()
|
|
||||||
defer hs.lock.Unlock()
|
|
||||||
|
|
||||||
hs.sortItems()
|
|
||||||
data, err := json.Marshal(hs)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to json encode debug info, err: %s", err.Error()))
|
|
||||||
}
|
|
||||||
|
|
||||||
err = hs.disk.Put(DebugHashStateKey(hs.Version), data)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to put debug version state into disk, err: %s", err.Error()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (hs *DebugHashState) sortItems() {
|
|
||||||
sort.Slice(hs.GetAccounts, func(i, j int) bool {
|
|
||||||
return hs.GetAccounts[i].Address.Cmp(hs.GetAccounts[j].Address) < 0
|
|
||||||
})
|
|
||||||
sort.Slice(hs.UpdateAccounts, func(i, j int) bool {
|
|
||||||
return hs.UpdateAccounts[i].Address.Cmp(hs.UpdateAccounts[j].Address) < 0
|
|
||||||
})
|
|
||||||
sort.Slice(hs.DeleteAccounts, func(i, j int) bool {
|
|
||||||
return hs.DeleteAccounts[i].Cmp(hs.DeleteAccounts[j]) < 0
|
|
||||||
})
|
|
||||||
|
|
||||||
sort.Slice(hs.GetStorage, func(i, j int) bool {
|
|
||||||
if hs.GetStorage[i].Address.Cmp(hs.GetStorage[j].Address) == 0 {
|
|
||||||
return hs.GetStorage[i].Key < hs.GetStorage[j].Key
|
|
||||||
}
|
|
||||||
return hs.GetStorage[i].Address.Cmp(hs.GetStorage[j].Address) < 0
|
|
||||||
})
|
|
||||||
|
|
||||||
sort.Slice(hs.UpdateStorage, func(i, j int) bool {
|
|
||||||
if hs.UpdateStorage[i].Address.Cmp(hs.UpdateStorage[j].Address) == 0 {
|
|
||||||
return hs.UpdateStorage[i].Key < hs.UpdateStorage[j].Key
|
|
||||||
}
|
|
||||||
return hs.UpdateStorage[i].Address.Cmp(hs.UpdateStorage[j].Address) < 0
|
|
||||||
})
|
|
||||||
|
|
||||||
sort.Slice(hs.DeleteStorage, func(i, j int) bool {
|
|
||||||
if hs.DeleteStorage[i].Address.Cmp(hs.DeleteStorage[j].Address) == 0 {
|
|
||||||
return hs.DeleteStorage[i].Key < hs.DeleteStorage[j].Key
|
|
||||||
}
|
|
||||||
return hs.DeleteStorage[i].Address.Cmp(hs.DeleteStorage[j].Address) < 0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func DebugHashStateKey(version int64) []byte {
|
|
||||||
key := "debug_hash_prefix" + strconv.FormatInt(version, 10)
|
|
||||||
return []byte(key)
|
|
||||||
}
|
|
||||||
@@ -1,290 +0,0 @@
|
|||||||
package state
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
versa "github.com/bnb-chain/versioned-state-database"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
DiffVersionCount = 0
|
|
||||||
DiskVersionCount = 0
|
|
||||||
)
|
|
||||||
|
|
||||||
type VersaAccountInfo struct {
|
|
||||||
Address common.Address
|
|
||||||
Account *types.StateAccount
|
|
||||||
}
|
|
||||||
|
|
||||||
type VersaStorageInfo struct {
|
|
||||||
Handler versa.TreeHandler
|
|
||||||
Address common.Address
|
|
||||||
Key string
|
|
||||||
Val string
|
|
||||||
}
|
|
||||||
|
|
||||||
type DebugVersionState struct {
|
|
||||||
disk ethdb.KeyValueStore
|
|
||||||
versionDB versa.Database
|
|
||||||
lock sync.Mutex
|
|
||||||
|
|
||||||
Version int64
|
|
||||||
PreState *versa.StateInfo
|
|
||||||
PostState *versa.StateInfo
|
|
||||||
AccessTrees map[common.Address][]*versa.TreeInfo
|
|
||||||
CommitTrees map[common.Address][]*versa.TreeInfo
|
|
||||||
CalcHash map[common.Address]common.Hash
|
|
||||||
|
|
||||||
GetAccounts []*VersaAccountInfo
|
|
||||||
UpdateAccounts []*VersaAccountInfo
|
|
||||||
DeleteAccounts []common.Address
|
|
||||||
|
|
||||||
GetStorage []*VersaStorageInfo
|
|
||||||
UpdateStorage []*VersaStorageInfo
|
|
||||||
DeleteStorage []*VersaStorageInfo
|
|
||||||
StorageAddr2Owner map[common.Address]common.Hash
|
|
||||||
|
|
||||||
GetCode map[common.Address][]common.Hash
|
|
||||||
UpdateCode map[common.Address][]common.Hash
|
|
||||||
|
|
||||||
Errs []string
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDebugVersionState(disk ethdb.KeyValueStore, versionDB versa.Database) *DebugVersionState {
|
|
||||||
return &DebugVersionState{
|
|
||||||
disk: disk,
|
|
||||||
versionDB: versionDB,
|
|
||||||
AccessTrees: make(map[common.Address][]*versa.TreeInfo, 0),
|
|
||||||
CommitTrees: make(map[common.Address][]*versa.TreeInfo, 0),
|
|
||||||
CalcHash: make(map[common.Address]common.Hash),
|
|
||||||
GetAccounts: make([]*VersaAccountInfo, 0),
|
|
||||||
UpdateAccounts: make([]*VersaAccountInfo, 0),
|
|
||||||
DeleteAccounts: make([]common.Address, 0),
|
|
||||||
GetStorage: make([]*VersaStorageInfo, 0),
|
|
||||||
UpdateStorage: make([]*VersaStorageInfo, 0),
|
|
||||||
DeleteStorage: make([]*VersaStorageInfo, 0),
|
|
||||||
StorageAddr2Owner: make(map[common.Address]common.Hash),
|
|
||||||
GetCode: make(map[common.Address][]common.Hash, 0),
|
|
||||||
UpdateCode: make(map[common.Address][]common.Hash, 0),
|
|
||||||
Errs: make([]string, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (ds *DebugVersionState) SetVersion(version int64) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
ds.Version = version
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnOpenState(handler versa.StateHandler) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
|
|
||||||
stateInfo, err := ds.versionDB.GetStateInfo(handler)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to get state info on open state, err: %s", err.Error()))
|
|
||||||
}
|
|
||||||
ds.PreState = stateInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnOpenTree(handler versa.TreeHandler, owner common.Hash, address common.Address) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
|
|
||||||
treeInfo, err := ds.versionDB.GetTreeInfo(handler)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to get tree info on open tree, err: %s", err.Error()))
|
|
||||||
}
|
|
||||||
if _, ok := ds.AccessTrees[address]; !ok {
|
|
||||||
ds.AccessTrees[address] = make([]*versa.TreeInfo, 0)
|
|
||||||
}
|
|
||||||
ds.AccessTrees[address] = append(ds.AccessTrees[address], treeInfo)
|
|
||||||
ds.StorageAddr2Owner[address] = owner
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnGetAccount(addr common.Address, acc *types.StateAccount) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
ds.GetAccounts = append(ds.GetAccounts, &VersaAccountInfo{
|
|
||||||
Address: addr,
|
|
||||||
Account: acc,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnUpdateAccount(addr common.Address, acc *types.StateAccount) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
ds.UpdateAccounts = append(ds.UpdateAccounts, &VersaAccountInfo{
|
|
||||||
Address: addr,
|
|
||||||
Account: acc,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnDeleteAccount(address common.Address) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
ds.DeleteAccounts = append(ds.DeleteAccounts, address)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnGetStorage(handler versa.TreeHandler, address common.Address, key []byte, val []byte) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
|
|
||||||
ds.GetStorage = append(ds.GetStorage, &VersaStorageInfo{
|
|
||||||
Handler: handler,
|
|
||||||
Address: address,
|
|
||||||
Key: common.Bytes2Hex(key),
|
|
||||||
Val: common.Bytes2Hex(val),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnUpdateStorage(handler versa.TreeHandler, address common.Address, key []byte, val []byte) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
|
|
||||||
ds.UpdateStorage = append(ds.UpdateStorage, &VersaStorageInfo{
|
|
||||||
Handler: handler,
|
|
||||||
Address: address,
|
|
||||||
Key: common.Bytes2Hex(key),
|
|
||||||
Val: common.Bytes2Hex(val),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnDeleteStorage(handler versa.TreeHandler, address common.Address, key []byte) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
|
|
||||||
ds.DeleteStorage = append(ds.DeleteStorage, &VersaStorageInfo{
|
|
||||||
Handler: handler,
|
|
||||||
Address: address,
|
|
||||||
Key: common.Bytes2Hex(key),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnGetCode(addr common.Address, codeHash common.Hash) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
if _, ok := ds.GetCode[addr]; !ok {
|
|
||||||
ds.GetCode[addr] = make([]common.Hash, 0)
|
|
||||||
}
|
|
||||||
ds.GetCode[addr] = append(ds.GetCode[addr], codeHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnUpdateCode(addr common.Address, codeHash common.Hash) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
if _, ok := ds.UpdateCode[addr]; !ok {
|
|
||||||
ds.UpdateCode[addr] = make([]common.Hash, 0)
|
|
||||||
}
|
|
||||||
ds.UpdateCode[addr] = append(ds.UpdateCode[addr], codeHash)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnCalcHash(addr common.Address, root common.Hash) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
ds.CalcHash[addr] = root
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnCommitTree(addr common.Address, handler versa.TreeHandler) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
treeInfo, err := ds.versionDB.GetTreeInfo(handler)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to get tree info on commit tree, err: %s", err.Error()))
|
|
||||||
}
|
|
||||||
if _, ok := ds.CommitTrees[addr]; !ok {
|
|
||||||
ds.CommitTrees[addr] = make([]*versa.TreeInfo, 0)
|
|
||||||
}
|
|
||||||
ds.CommitTrees[addr] = append(ds.CommitTrees[addr], treeInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnError(err error) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
ds.Errs = append(ds.Errs, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) OnCloseState(handler versa.StateHandler) {
|
|
||||||
ds.lock.Lock()
|
|
||||||
defer ds.lock.Unlock()
|
|
||||||
|
|
||||||
stateInfo, err := ds.versionDB.GetStateInfo(handler)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to get state info on close state, err: %s", err.Error()))
|
|
||||||
}
|
|
||||||
ds.PostState = stateInfo
|
|
||||||
|
|
||||||
oldDiskVersionCount := DiskVersionCount
|
|
||||||
if ds.PreState.Root.Cmp(ds.PostState.Root) != 0 {
|
|
||||||
DiffVersionCount++
|
|
||||||
if ds.PostState.IsDiskVersion {
|
|
||||||
DiskVersionCount++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ds.Version%1000 == 0 || oldDiskVersionCount != DiskVersionCount {
|
|
||||||
log.Info("version state info", "current block", ds.Version, "diff version count", DiffVersionCount, "disk version count", DiskVersionCount)
|
|
||||||
}
|
|
||||||
|
|
||||||
ds.sortItems()
|
|
||||||
|
|
||||||
data, err := json.Marshal(ds)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to json encode debug info, err: %s", err.Error()))
|
|
||||||
}
|
|
||||||
|
|
||||||
err = ds.disk.Put(DebugVersionStateKey(ds.Version), data)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to put debug version state into disk, err: %s", err.Error()))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(ds.Errs) != 0 {
|
|
||||||
log.Info("version state occurs error", "debug info", string(data))
|
|
||||||
log.Crit("exit....")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ds *DebugVersionState) sortItems() {
|
|
||||||
sort.Slice(ds.GetAccounts, func(i, j int) bool {
|
|
||||||
return ds.GetAccounts[i].Address.Cmp(ds.GetAccounts[j].Address) < 0
|
|
||||||
})
|
|
||||||
sort.Slice(ds.UpdateAccounts, func(i, j int) bool {
|
|
||||||
return ds.UpdateAccounts[i].Address.Cmp(ds.UpdateAccounts[j].Address) < 0
|
|
||||||
})
|
|
||||||
sort.Slice(ds.DeleteAccounts, func(i, j int) bool {
|
|
||||||
return ds.DeleteAccounts[i].Cmp(ds.DeleteAccounts[j]) < 0
|
|
||||||
})
|
|
||||||
|
|
||||||
sort.Slice(ds.GetStorage, func(i, j int) bool {
|
|
||||||
if ds.GetStorage[i].Address.Cmp(ds.GetStorage[j].Address) == 0 {
|
|
||||||
return ds.GetStorage[i].Key < ds.GetStorage[j].Key
|
|
||||||
}
|
|
||||||
return ds.GetStorage[i].Address.Cmp(ds.GetStorage[j].Address) < 0
|
|
||||||
})
|
|
||||||
|
|
||||||
sort.Slice(ds.UpdateStorage, func(i, j int) bool {
|
|
||||||
if ds.UpdateStorage[i].Address.Cmp(ds.UpdateStorage[j].Address) == 0 {
|
|
||||||
return ds.UpdateStorage[i].Key < ds.UpdateStorage[j].Key
|
|
||||||
}
|
|
||||||
return ds.UpdateStorage[i].Address.Cmp(ds.UpdateStorage[j].Address) < 0
|
|
||||||
})
|
|
||||||
|
|
||||||
sort.Slice(ds.DeleteStorage, func(i, j int) bool {
|
|
||||||
if ds.DeleteStorage[i].Address.Cmp(ds.DeleteStorage[j].Address) == 0 {
|
|
||||||
return ds.DeleteStorage[i].Key < ds.DeleteStorage[j].Key
|
|
||||||
}
|
|
||||||
return ds.DeleteStorage[i].Address.Cmp(ds.DeleteStorage[j].Address) < 0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func DebugVersionStateKey(version int64) []byte {
|
|
||||||
key := "debug_version_prefix" + strconv.FormatInt(version, 10)
|
|
||||||
return []byte(key)
|
|
||||||
}
|
|
||||||
@@ -81,7 +81,6 @@ type triePrefetcher struct {
|
|||||||
|
|
||||||
// newTriePrefetcher
|
// newTriePrefetcher
|
||||||
func newTriePrefetcher(db Database, root, rootParent common.Hash, namespace string) *triePrefetcher {
|
func newTriePrefetcher(db Database, root, rootParent common.Hash, namespace string) *triePrefetcher {
|
||||||
panic("prefetcher not support")
|
|
||||||
prefix := triePrefetchMetricsPrefix + namespace
|
prefix := triePrefetchMetricsPrefix + namespace
|
||||||
p := &triePrefetcher{
|
p := &triePrefetcher{
|
||||||
db: db,
|
db: db,
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
|||||||
// the transaction messages using the statedb, but any changes are discarded. The
|
// the transaction messages using the statedb, but any changes are discarded. The
|
||||||
// only goal is to pre-cache transaction signatures and snapshot clean state. Only used for mining stage
|
// only goal is to pre-cache transaction signatures and snapshot clean state. Only used for mining stage
|
||||||
func (p *statePrefetcher) PrefetchMining(txs TransactionsByPriceAndNonce, header *types.Header, gasLimit uint64, statedb *state.StateDB, cfg vm.Config, interruptCh <-chan struct{}, txCurr **types.Transaction) {
|
func (p *statePrefetcher) PrefetchMining(txs TransactionsByPriceAndNonce, header *types.Header, gasLimit uint64, statedb *state.StateDB, cfg vm.Config, interruptCh <-chan struct{}, txCurr **types.Transaction) {
|
||||||
panic("prefetcher not support")
|
|
||||||
var signer = types.MakeSigner(p.config, header.Number, header.Time)
|
var signer = types.MakeSigner(p.config, header.Number, header.Time)
|
||||||
|
|
||||||
txCh := make(chan *types.Transaction, 2*prefetchThread)
|
txCh := make(chan *types.Transaction, 2*prefetchThread)
|
||||||
|
|||||||
@@ -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
|
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
||||||
// contract. This method is exported to be used in tests.
|
// contract. This method is exported to be used in tests.
|
||||||
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
|
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
|
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
|
||||||
// the new root
|
// the new root
|
||||||
msg := &Message{
|
msg := &Message{
|
||||||
|
|||||||
1
core/systemcontracts/bohr/chapel/StakeHubContract
Normal file
1
core/systemcontracts/bohr/chapel/StakeHubContract
Normal file
File diff suppressed because one or more lines are too long
1
core/systemcontracts/bohr/chapel/ValidatorContract
Normal file
1
core/systemcontracts/bohr/chapel/ValidatorContract
Normal file
File diff suppressed because one or more lines are too long
1
core/systemcontracts/bohr/mainnet/StakeHubContract
Normal file
1
core/systemcontracts/bohr/mainnet/StakeHubContract
Normal file
File diff suppressed because one or more lines are too long
1
core/systemcontracts/bohr/mainnet/ValidatorContract
Normal file
1
core/systemcontracts/bohr/mainnet/ValidatorContract
Normal file
File diff suppressed because one or more lines are too long
1
core/systemcontracts/bohr/rialto/StakeHubContract
Normal file
1
core/systemcontracts/bohr/rialto/StakeHubContract
Normal file
File diff suppressed because one or more lines are too long
1
core/systemcontracts/bohr/rialto/ValidatorContract
Normal file
1
core/systemcontracts/bohr/rialto/ValidatorContract
Normal file
File diff suppressed because one or more lines are too long
27
core/systemcontracts/bohr/types.go
Normal file
27
core/systemcontracts/bohr/types.go
Normal 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
|
||||||
|
)
|
||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"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/bruno"
|
||||||
"github.com/ethereum/go-ethereum/core/systemcontracts/euler"
|
"github.com/ethereum/go-ethereum/core/systemcontracts/euler"
|
||||||
"github.com/ethereum/go-ethereum/core/systemcontracts/feynman"
|
"github.com/ethereum/go-ethereum/core/systemcontracts/feynman"
|
||||||
@@ -78,6 +79,8 @@ var (
|
|||||||
feynmanFixUpgrade = make(map[string]*Upgrade)
|
feynmanFixUpgrade = make(map[string]*Upgrade)
|
||||||
|
|
||||||
haberFixUpgrade = make(map[string]*Upgrade)
|
haberFixUpgrade = make(map[string]*Upgrade)
|
||||||
|
|
||||||
|
bohrUpgrade = make(map[string]*Upgrade)
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
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) {
|
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)
|
applySystemContractUpgrade(haberFixUpgrade[network], blockNumber, statedb, logger)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if config.IsOnBohr(blockNumber, lastBlockTime, blockTime) {
|
||||||
|
applySystemContractUpgrade(bohrUpgrade[network], blockNumber, statedb, logger)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
apply other upgrades
|
apply other upgrades
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -366,9 +366,9 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres
|
|||||||
// Initialize the state with head block, or fallback to empty one in
|
// Initialize the state with head block, or fallback to empty one in
|
||||||
// case the head state is not available (might occur when node is not
|
// case the head state is not available (might occur when node is not
|
||||||
// fully synced).
|
// fully synced).
|
||||||
state, err := p.chain.StateAt(head.Number.Int64(), head.Root)
|
state, err := p.chain.StateAt(head.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
state, err = p.chain.StateAt(-1, types.EmptyRootHash)
|
state, err = p.chain.StateAt(types.EmptyRootHash)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -793,7 +793,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
|
|||||||
resettimeHist.Update(time.Since(start).Nanoseconds())
|
resettimeHist.Update(time.Since(start).Nanoseconds())
|
||||||
}(time.Now())
|
}(time.Now())
|
||||||
|
|
||||||
statedb, err := p.chain.StateAt(newHead.Number.Int64(), newHead.Root)
|
statedb, err := p.chain.StateAt(newHead.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to reset blobpool state", "err", err)
|
log.Error("Failed to reset blobpool state", "err", err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -40,5 +40,5 @@ type BlockChain interface {
|
|||||||
GetBlock(hash common.Hash, number uint64) *types.Block
|
GetBlock(hash common.Hash, number uint64) *types.Block
|
||||||
|
|
||||||
// StateAt returns a state database for a given root hash (generally the head).
|
// StateAt returns a state database for a given root hash (generally the head).
|
||||||
StateAt(number int64, root common.Hash) (*state.StateDB, error)
|
StateAt(root common.Hash) (*state.StateDB, error)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ type BlockChain interface {
|
|||||||
GetBlock(hash common.Hash, number uint64) *types.Block
|
GetBlock(hash common.Hash, number uint64) *types.Block
|
||||||
|
|
||||||
// StateAt returns a state database for a given root hash (generally the head).
|
// StateAt returns a state database for a given root hash (generally the head).
|
||||||
StateAt(number int64, root common.Hash) (*state.StateDB, error)
|
StateAt(root common.Hash) (*state.StateDB, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config are the configuration parameters of the transaction pool.
|
// Config are the configuration parameters of the transaction pool.
|
||||||
@@ -311,9 +311,9 @@ func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserve txpool.A
|
|||||||
// Initialize the state with head block, or fallback to empty one in
|
// Initialize the state with head block, or fallback to empty one in
|
||||||
// case the head state is not available (might occur when node is not
|
// case the head state is not available (might occur when node is not
|
||||||
// fully synced).
|
// fully synced).
|
||||||
statedb, err := pool.chain.StateAt(head.Number.Int64(), head.Root)
|
statedb, err := pool.chain.StateAt(head.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statedb, err = pool.chain.StateAt(-1, types.EmptyRootHash)
|
statedb, err = pool.chain.StateAt(types.EmptyRootHash)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -1492,7 +1492,7 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) {
|
|||||||
if newHead == nil {
|
if newHead == nil {
|
||||||
newHead = pool.chain.CurrentBlock() // Special case during testing
|
newHead = pool.chain.CurrentBlock() // Special case during testing
|
||||||
}
|
}
|
||||||
statedb, err := pool.chain.StateAt(newHead.Number.Int64(), newHead.Root)
|
statedb, err := pool.chain.StateAt(newHead.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to reset txpool state", "err", err)
|
log.Error("Failed to reset txpool state", "err", err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -673,10 +673,7 @@ type DiffAccountsInBlock struct {
|
|||||||
Transactions []DiffAccountsInTx
|
Transactions []DiffAccountsInTx
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var extraSeal = 65 // Fixed number of extra-data suffix bytes reserved for signer seal
|
||||||
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
|
|
||||||
)
|
|
||||||
|
|
||||||
// SealHash returns the hash of a block prior to it being sealed.
|
// SealHash returns the hash of a block prior to it being sealed.
|
||||||
func SealHash(header *Header, chainId *big.Int) (hash common.Hash) {
|
func SealHash(header *Header, chainId *big.Int) (hash common.Hash) {
|
||||||
@@ -687,48 +684,51 @@ func SealHash(header *Header, chainId *big.Int) (hash common.Hash) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func EncodeSigHeader(w io.Writer, header *Header, chainId *big.Int) {
|
func EncodeSigHeader(w io.Writer, header *Header, chainId *big.Int) {
|
||||||
err := rlp.Encode(w, []interface{}{
|
var err error
|
||||||
chainId,
|
if header.ParentBeaconRoot != nil && *header.ParentBeaconRoot == (common.Hash{}) {
|
||||||
header.ParentHash,
|
err = rlp.Encode(w, []interface{}{
|
||||||
header.UncleHash,
|
chainId,
|
||||||
header.Coinbase,
|
header.ParentHash,
|
||||||
header.Root,
|
header.UncleHash,
|
||||||
header.TxHash,
|
header.Coinbase,
|
||||||
header.ReceiptHash,
|
header.Root,
|
||||||
header.Bloom,
|
header.TxHash,
|
||||||
header.Difficulty,
|
header.ReceiptHash,
|
||||||
header.Number,
|
header.Bloom,
|
||||||
header.GasLimit,
|
header.Difficulty,
|
||||||
header.GasUsed,
|
header.Number,
|
||||||
header.Time,
|
header.GasLimit,
|
||||||
header.Extra[:len(header.Extra)-extraSeal], // this will panic if extra is too short, should check before calling encodeSigHeader
|
header.GasUsed,
|
||||||
header.MixDigest,
|
header.Time,
|
||||||
header.Nonce,
|
header.Extra[:len(header.Extra)-extraSeal], // this will panic if extra is too short, should check before calling encodeSigHeader
|
||||||
})
|
header.MixDigest,
|
||||||
if err != nil {
|
header.Nonce,
|
||||||
panic("can't encode: " + err.Error())
|
header.BaseFee,
|
||||||
}
|
header.WithdrawalsHash,
|
||||||
}
|
header.BlobGasUsed,
|
||||||
|
header.ExcessBlobGas,
|
||||||
func EncodeSigHeaderWithoutVoteAttestation(w io.Writer, header *Header, chainId *big.Int) {
|
header.ParentBeaconRoot,
|
||||||
err := rlp.Encode(w, []interface{}{
|
})
|
||||||
chainId,
|
} else {
|
||||||
header.ParentHash,
|
err = rlp.Encode(w, []interface{}{
|
||||||
header.UncleHash,
|
chainId,
|
||||||
header.Coinbase,
|
header.ParentHash,
|
||||||
header.Root,
|
header.UncleHash,
|
||||||
header.TxHash,
|
header.Coinbase,
|
||||||
header.ReceiptHash,
|
header.Root,
|
||||||
header.Bloom,
|
header.TxHash,
|
||||||
header.Difficulty,
|
header.ReceiptHash,
|
||||||
header.Number,
|
header.Bloom,
|
||||||
header.GasLimit,
|
header.Difficulty,
|
||||||
header.GasUsed,
|
header.Number,
|
||||||
header.Time,
|
header.GasLimit,
|
||||||
header.Extra[:extraVanity], // this will panic if extra is too short, should check before calling encodeSigHeaderWithoutVoteAttestation
|
header.GasUsed,
|
||||||
header.MixDigest,
|
header.Time,
|
||||||
header.Nonce,
|
header.Extra[:len(header.Extra)-extraSeal], // this will panic if extra is too short, should check before calling encodeSigHeader
|
||||||
})
|
header.MixDigest,
|
||||||
|
header.Nonce,
|
||||||
|
})
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic("can't encode: " + err.Error())
|
panic("can't encode: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ package types
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
@@ -59,11 +58,6 @@ func (acct *StateAccount) Copy() *StateAccount {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (acct *StateAccount) String() string {
|
|
||||||
return fmt.Sprintf("nonce: %d, balance: %d, root: %s, codeHash: %s",
|
|
||||||
acct.Nonce, acct.Balance, acct.Root.String(), common.Bytes2Hex(acct.CodeHash))
|
|
||||||
}
|
|
||||||
|
|
||||||
// SlimAccount is a modified version of an Account, where the root is replaced
|
// SlimAccount is a modified version of an Account, where the root is replaced
|
||||||
// with a byte slice. This format can be used to represent full-consensus format
|
// with a byte slice. This format can be used to represent full-consensus format
|
||||||
// or slim format which replaces the empty root and code hash as nil byte slice.
|
// or slim format which replaces the empty root and code hash as nil byte slice.
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package vote
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/big"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"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
|
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 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.
|
// Backend wraps all methods required for voting.
|
||||||
type Backend interface {
|
type Backend interface {
|
||||||
@@ -33,8 +40,8 @@ type VoteManager struct {
|
|||||||
|
|
||||||
chain *core.BlockChain
|
chain *core.BlockChain
|
||||||
|
|
||||||
chainHeadCh chan core.ChainHeadEvent
|
highestVerifiedBlockCh chan core.HighestVerifiedBlockEvent
|
||||||
chainHeadSub event.Subscription
|
highestVerifiedBlockSub event.Subscription
|
||||||
|
|
||||||
// used for backup validators to sync votes from corresponding mining validator
|
// used for backup validators to sync votes from corresponding mining validator
|
||||||
syncVoteCh chan core.NewVoteEvent
|
syncVoteCh chan core.NewVoteEvent
|
||||||
@@ -49,12 +56,12 @@ type VoteManager struct {
|
|||||||
|
|
||||||
func NewVoteManager(eth Backend, chain *core.BlockChain, pool *VotePool, journalPath, blsPasswordPath, blsWalletPath string, engine consensus.PoSA) (*VoteManager, error) {
|
func NewVoteManager(eth Backend, chain *core.BlockChain, pool *VotePool, journalPath, blsPasswordPath, blsWalletPath string, engine consensus.PoSA) (*VoteManager, error) {
|
||||||
voteManager := &VoteManager{
|
voteManager := &VoteManager{
|
||||||
eth: eth,
|
eth: eth,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
|
highestVerifiedBlockCh: make(chan core.HighestVerifiedBlockEvent, highestVerifiedBlockChanSize),
|
||||||
syncVoteCh: make(chan core.NewVoteEvent, voteBufferForPut),
|
syncVoteCh: make(chan core.NewVoteEvent, voteBufferForPut),
|
||||||
pool: pool,
|
pool: pool,
|
||||||
engine: engine,
|
engine: engine,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create voteSigner.
|
// Create voteSigner.
|
||||||
@@ -74,7 +81,7 @@ func NewVoteManager(eth Backend, chain *core.BlockChain, pool *VotePool, journal
|
|||||||
voteManager.journal = voteJournal
|
voteManager.journal = voteJournal
|
||||||
|
|
||||||
// Subscribe to chain head event.
|
// Subscribe to chain head event.
|
||||||
voteManager.chainHeadSub = voteManager.chain.SubscribeChainHeadEvent(voteManager.chainHeadCh)
|
voteManager.highestVerifiedBlockSub = voteManager.chain.SubscribeHighestVerifiedHeaderEvent(voteManager.highestVerifiedBlockCh)
|
||||||
voteManager.syncVoteSub = voteManager.pool.SubscribeNewVoteEvent(voteManager.syncVoteCh)
|
voteManager.syncVoteSub = voteManager.pool.SubscribeNewVoteEvent(voteManager.syncVoteCh)
|
||||||
|
|
||||||
go voteManager.loop()
|
go voteManager.loop()
|
||||||
@@ -84,7 +91,7 @@ func NewVoteManager(eth Backend, chain *core.BlockChain, pool *VotePool, journal
|
|||||||
|
|
||||||
func (voteManager *VoteManager) loop() {
|
func (voteManager *VoteManager) loop() {
|
||||||
log.Debug("vote manager routine loop started")
|
log.Debug("vote manager routine loop started")
|
||||||
defer voteManager.chainHeadSub.Unsubscribe()
|
defer voteManager.highestVerifiedBlockSub.Unsubscribe()
|
||||||
defer voteManager.syncVoteSub.Unsubscribe()
|
defer voteManager.syncVoteSub.Unsubscribe()
|
||||||
|
|
||||||
events := voteManager.eth.EventMux().Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
|
events := voteManager.eth.EventMux().Subscribe(downloader.StartEvent{}, downloader.DoneEvent{}, downloader.FailedEvent{})
|
||||||
@@ -119,7 +126,7 @@ func (voteManager *VoteManager) loop() {
|
|||||||
log.Debug("downloader is in DoneEvent mode, set the startVote flag to true")
|
log.Debug("downloader is in DoneEvent mode, set the startVote flag to true")
|
||||||
startVote = true
|
startVote = true
|
||||||
}
|
}
|
||||||
case cHead := <-voteManager.chainHeadCh:
|
case cHead := <-voteManager.highestVerifiedBlockCh:
|
||||||
if !startVote {
|
if !startVote {
|
||||||
log.Debug("startVote flag is false, continue")
|
log.Debug("startVote flag is false, continue")
|
||||||
continue
|
continue
|
||||||
@@ -135,12 +142,12 @@ func (voteManager *VoteManager) loop() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if cHead.Block == nil {
|
if cHead.Header == nil {
|
||||||
log.Debug("cHead.Block is nil, continue")
|
log.Debug("cHead.Header is nil, continue")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
curHead := cHead.Block.Header()
|
curHead := cHead.Header
|
||||||
if p, ok := voteManager.engine.(*parlia.Parlia); ok {
|
if p, ok := voteManager.engine.(*parlia.Parlia); ok {
|
||||||
nextBlockMinedTime := time.Unix(int64((curHead.Time + p.Period())), 0)
|
nextBlockMinedTime := time.Unix(int64((curHead.Time + p.Period())), 0)
|
||||||
timeForBroadcast := 50 * time.Millisecond // enough to broadcast a vote
|
timeForBroadcast := 50 * time.Millisecond // enough to broadcast a vote
|
||||||
@@ -155,7 +162,7 @@ func (voteManager *VoteManager) loop() {
|
|||||||
func(bLSPublicKey *types.BLSPublicKey) bool {
|
func(bLSPublicKey *types.BLSPublicKey) bool {
|
||||||
return bytes.Equal(voteManager.signer.PubKey[:], bLSPublicKey[:])
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,6 +209,36 @@ func (voteManager *VoteManager) loop() {
|
|||||||
voteManager.pool.PutVote(voteMessage)
|
voteManager.pool.PutVote(voteMessage)
|
||||||
votesManagerCounter.Inc(1)
|
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:
|
case event := <-voteManager.syncVoteCh:
|
||||||
voteMessage := event.Vote
|
voteMessage := event.Vote
|
||||||
if voteManager.eth.IsMining() || !bytes.Equal(voteManager.signer.PubKey[:], voteMessage.VoteAddress[:]) {
|
if voteManager.eth.IsMining() || !bytes.Equal(voteManager.signer.PubKey[:], voteMessage.VoteAddress[:]) {
|
||||||
@@ -217,7 +254,7 @@ func (voteManager *VoteManager) loop() {
|
|||||||
case <-voteManager.syncVoteSub.Err():
|
case <-voteManager.syncVoteSub.Err():
|
||||||
log.Debug("voteManager subscribed votes failed")
|
log.Debug("voteManager subscribed votes failed")
|
||||||
return
|
return
|
||||||
case <-voteManager.chainHeadSub.Err():
|
case <-voteManager.highestVerifiedBlockSub.Err():
|
||||||
log.Debug("voteManager subscribed chainHead failed")
|
log.Debug("voteManager subscribed chainHead failed")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const (
|
|||||||
lowerLimitOfVoteBlockNumber = 256
|
lowerLimitOfVoteBlockNumber = 256
|
||||||
upperLimitOfVoteBlockNumber = 11 // refer to fetcher.maxUncleDist
|
upperLimitOfVoteBlockNumber = 11 // refer to fetcher.maxUncleDist
|
||||||
|
|
||||||
chainHeadChanSize = 10 // chainHeadChanSize is the size of channel listening to ChainHeadEvent.
|
highestVerifiedBlockChanSize = 10 // highestVerifiedBlockChanSize is the size of channel listening to HighestVerifiedBlockEvent.
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -57,8 +57,8 @@ type VotePool struct {
|
|||||||
curVotesPq *votesPriorityQueue
|
curVotesPq *votesPriorityQueue
|
||||||
futureVotesPq *votesPriorityQueue
|
futureVotesPq *votesPriorityQueue
|
||||||
|
|
||||||
chainHeadCh chan core.ChainHeadEvent
|
highestVerifiedBlockCh chan core.HighestVerifiedBlockEvent
|
||||||
chainHeadSub event.Subscription
|
highestVerifiedBlockSub event.Subscription
|
||||||
|
|
||||||
votesCh chan *types.VoteEnvelope
|
votesCh chan *types.VoteEnvelope
|
||||||
|
|
||||||
@@ -69,19 +69,19 @@ type votesPriorityQueue []*types.VoteData
|
|||||||
|
|
||||||
func NewVotePool(chain *core.BlockChain, engine consensus.PoSA) *VotePool {
|
func NewVotePool(chain *core.BlockChain, engine consensus.PoSA) *VotePool {
|
||||||
votePool := &VotePool{
|
votePool := &VotePool{
|
||||||
chain: chain,
|
chain: chain,
|
||||||
receivedVotes: mapset.NewSet[common.Hash](),
|
receivedVotes: mapset.NewSet[common.Hash](),
|
||||||
curVotes: make(map[common.Hash]*VoteBox),
|
curVotes: make(map[common.Hash]*VoteBox),
|
||||||
futureVotes: make(map[common.Hash]*VoteBox),
|
futureVotes: make(map[common.Hash]*VoteBox),
|
||||||
curVotesPq: &votesPriorityQueue{},
|
curVotesPq: &votesPriorityQueue{},
|
||||||
futureVotesPq: &votesPriorityQueue{},
|
futureVotesPq: &votesPriorityQueue{},
|
||||||
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
|
highestVerifiedBlockCh: make(chan core.HighestVerifiedBlockEvent, highestVerifiedBlockChanSize),
|
||||||
votesCh: make(chan *types.VoteEnvelope, voteBufferForPut),
|
votesCh: make(chan *types.VoteEnvelope, voteBufferForPut),
|
||||||
engine: engine,
|
engine: engine,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe events from blockchain and start the main event loop.
|
// Subscribe events from blockchain and start the main event loop.
|
||||||
votePool.chainHeadSub = votePool.chain.SubscribeChainHeadEvent(votePool.chainHeadCh)
|
votePool.highestVerifiedBlockSub = votePool.chain.SubscribeHighestVerifiedHeaderEvent(votePool.highestVerifiedBlockCh)
|
||||||
|
|
||||||
go votePool.loop()
|
go votePool.loop()
|
||||||
return votePool
|
return votePool
|
||||||
@@ -89,18 +89,18 @@ func NewVotePool(chain *core.BlockChain, engine consensus.PoSA) *VotePool {
|
|||||||
|
|
||||||
// loop is the vote pool's main even loop, waiting for and reacting to outside blockchain events and votes channel event.
|
// loop is the vote pool's main even loop, waiting for and reacting to outside blockchain events and votes channel event.
|
||||||
func (pool *VotePool) loop() {
|
func (pool *VotePool) loop() {
|
||||||
defer pool.chainHeadSub.Unsubscribe()
|
defer pool.highestVerifiedBlockSub.Unsubscribe()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
// Handle ChainHeadEvent.
|
// Handle ChainHeadEvent.
|
||||||
case ev := <-pool.chainHeadCh:
|
case ev := <-pool.highestVerifiedBlockCh:
|
||||||
if ev.Block != nil {
|
if ev.Header != nil {
|
||||||
latestBlockNumber := ev.Block.NumberU64()
|
latestBlockNumber := ev.Header.Number.Uint64()
|
||||||
pool.prune(latestBlockNumber)
|
pool.prune(latestBlockNumber)
|
||||||
pool.transferVotesFromFutureToCur(ev.Block.Header())
|
pool.transferVotesFromFutureToCur(ev.Header)
|
||||||
}
|
}
|
||||||
case <-pool.chainHeadSub.Err():
|
case <-pool.highestVerifiedBlockSub.Err():
|
||||||
return
|
return
|
||||||
|
|
||||||
// Handle votes channel and put the vote into vote pool.
|
// Handle votes channel and put the vote into vote pool.
|
||||||
@@ -135,7 +135,7 @@ func (pool *VotePool) putIntoVotePool(vote *types.VoteEnvelope) bool {
|
|||||||
var votesPq *votesPriorityQueue
|
var votesPq *votesPriorityQueue
|
||||||
isFutureVote := false
|
isFutureVote := false
|
||||||
|
|
||||||
voteBlock := pool.chain.GetHeaderByHash(targetHash)
|
voteBlock := pool.chain.GetVerifiedBlockByHash(targetHash)
|
||||||
if voteBlock == nil {
|
if voteBlock == nil {
|
||||||
votes = pool.futureVotes
|
votes = pool.futureVotes
|
||||||
votesPq = pool.futureVotesPq
|
votesPq = pool.futureVotesPq
|
||||||
@@ -226,7 +226,7 @@ func (pool *VotePool) transferVotesFromFutureToCur(latestBlockHeader *types.Head
|
|||||||
futurePqBuffer := make([]*types.VoteData, 0)
|
futurePqBuffer := make([]*types.VoteData, 0)
|
||||||
for futurePq.Len() > 0 && futurePq.Peek().TargetNumber <= latestBlockNumber {
|
for futurePq.Len() > 0 && futurePq.Peek().TargetNumber <= latestBlockNumber {
|
||||||
blockHash := futurePq.Peek().TargetHash
|
blockHash := futurePq.Peek().TargetHash
|
||||||
header := pool.chain.GetHeaderByHash(blockHash)
|
header := pool.chain.GetVerifiedBlockByHash(blockHash)
|
||||||
if header == nil {
|
if header == nil {
|
||||||
// Put into pq buffer used for later put again into futurePq
|
// Put into pq buffer used for later put again into futurePq
|
||||||
futurePqBuffer = append(futurePqBuffer, heap.Pop(futurePq).(*types.VoteData))
|
futurePqBuffer = append(futurePqBuffer, heap.Pop(futurePq).(*types.VoteData))
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"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"
|
||||||
"github.com/ethereum/go-ethereum/core/bloombits"
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
@@ -204,7 +205,7 @@ func (b *EthAPIBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.B
|
|||||||
if header == nil {
|
if header == nil {
|
||||||
return nil, nil, errors.New("header not found")
|
return nil, nil, errors.New("header not found")
|
||||||
}
|
}
|
||||||
stateDb, err := b.eth.BlockChain().StateAt(header.Number.Int64(), header.Root)
|
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -226,7 +227,7 @@ func (b *EthAPIBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockN
|
|||||||
if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
|
if blockNrOrHash.RequireCanonical && b.eth.blockchain.GetCanonicalHash(header.Number.Uint64()) != hash {
|
||||||
return nil, nil, errors.New("hash is not currently canonical")
|
return nil, nil, errors.New("hash is not currently canonical")
|
||||||
}
|
}
|
||||||
stateDb, err := b.eth.BlockChain().StateAt(header.Number.Int64(), header.Root)
|
stateDb, err := b.eth.BlockChain().StateAt(header.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
@@ -440,6 +441,16 @@ func (b *EthAPIBackend) Engine() consensus.Engine {
|
|||||||
return b.eth.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(¤tHead)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) CurrentHeader() *types.Header {
|
func (b *EthAPIBackend) CurrentHeader() *types.Header {
|
||||||
return b.eth.blockchain.CurrentHeader()
|
return b.eth.blockchain.CurrentHeader()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ func (api *DebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
|
|||||||
if header == nil {
|
if header == nil {
|
||||||
return state.Dump{}, fmt.Errorf("block #%d not found", blockNr)
|
return state.Dump{}, fmt.Errorf("block #%d not found", blockNr)
|
||||||
}
|
}
|
||||||
stateDb, err := api.eth.BlockChain().StateAt(header.Number.Int64(), header.Root)
|
stateDb, err := api.eth.BlockChain().StateAt(header.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return state.Dump{}, err
|
return state.Dump{}, err
|
||||||
}
|
}
|
||||||
@@ -167,7 +167,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
|
|||||||
if header == nil {
|
if header == nil {
|
||||||
return state.Dump{}, fmt.Errorf("block #%d not found", number)
|
return state.Dump{}, fmt.Errorf("block #%d not found", number)
|
||||||
}
|
}
|
||||||
stateDb, err = api.eth.BlockChain().StateAt(header.Number.Int64(), header.Root)
|
stateDb, err = api.eth.BlockChain().StateAt(header.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return state.Dump{}, err
|
return state.Dump{}, err
|
||||||
}
|
}
|
||||||
@@ -177,7 +177,7 @@ func (api *DebugAPI) AccountRange(blockNrOrHash rpc.BlockNumberOrHash, start hex
|
|||||||
if block == nil {
|
if block == nil {
|
||||||
return state.Dump{}, fmt.Errorf("block %s not found", hash.Hex())
|
return state.Dump{}, fmt.Errorf("block %s not found", hash.Hex())
|
||||||
}
|
}
|
||||||
stateDb, err = api.eth.BlockChain().StateAt(block.Number().Int64(), block.Root())
|
stateDb, err = api.eth.BlockChain().StateAt(block.Root())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return state.Dump{}, err
|
return state.Dump{}, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,18 +123,6 @@ type Ethereum struct {
|
|||||||
// New creates a new Ethereum object (including the
|
// New creates a new Ethereum object (including the
|
||||||
// initialisation of the common Ethereum object)
|
// initialisation of the common Ethereum object)
|
||||||
func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
||||||
onlyFullSync := false
|
|
||||||
if config.StateScheme == rawdb.VersionScheme {
|
|
||||||
config.SnapshotCache = 0
|
|
||||||
onlyFullSync = true
|
|
||||||
config.SyncMode = downloader.FullSync
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO:: debug code
|
|
||||||
config.SnapshotCache = 0
|
|
||||||
onlyFullSync = true
|
|
||||||
config.SyncMode = downloader.FullSync
|
|
||||||
|
|
||||||
// Ensure configuration values are compatible and sane
|
// Ensure configuration values are compatible and sane
|
||||||
if config.SyncMode == downloader.LightSync {
|
if config.SyncMode == downloader.LightSync {
|
||||||
return nil, errors.New("can't run eth.Ethereum in light sync mode, light mode has been deprecated")
|
return nil, errors.New("can't run eth.Ethereum in light sync mode, light mode has been deprecated")
|
||||||
@@ -197,6 +185,16 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||||||
}
|
}
|
||||||
// Override the chain config with provided settings.
|
// Override the chain config with provided settings.
|
||||||
var overrides core.ChainOverrides
|
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 {
|
if config.OverrideBohr != nil {
|
||||||
chainConfig.BohrTime = config.OverrideBohr
|
chainConfig.BohrTime = config.OverrideBohr
|
||||||
overrides.OverrideBohr = config.OverrideBohr
|
overrides.OverrideBohr = config.OverrideBohr
|
||||||
@@ -340,7 +338,6 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||||||
DirectBroadcast: config.DirectBroadcast,
|
DirectBroadcast: config.DirectBroadcast,
|
||||||
DisablePeerTxBroadcast: config.DisablePeerTxBroadcast,
|
DisablePeerTxBroadcast: config.DisablePeerTxBroadcast,
|
||||||
PeerSet: peers,
|
PeerSet: peers,
|
||||||
OnlyFullSync: onlyFullSync,
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -188,6 +188,9 @@ type Config struct {
|
|||||||
// send-transaction variants. The unit is ether.
|
// send-transaction variants. The unit is ether.
|
||||||
RPCTxFeeCap float64
|
RPCTxFeeCap float64
|
||||||
|
|
||||||
|
// OverridePassedForkTime
|
||||||
|
OverridePassedForkTime *uint64 `toml:",omitempty"`
|
||||||
|
|
||||||
// OverrideBohr (TODO: remove after the fork)
|
// OverrideBohr (TODO: remove after the fork)
|
||||||
OverrideBohr *uint64 `toml:",omitempty"`
|
OverrideBohr *uint64 `toml:",omitempty"`
|
||||||
|
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||||||
RPCGasCap uint64
|
RPCGasCap uint64
|
||||||
RPCEVMTimeout time.Duration
|
RPCEVMTimeout time.Duration
|
||||||
RPCTxFeeCap float64
|
RPCTxFeeCap float64
|
||||||
|
OverridePassedForkTime *uint64 `toml:",omitempty"`
|
||||||
OverrideBohr *uint64 `toml:",omitempty"`
|
OverrideBohr *uint64 `toml:",omitempty"`
|
||||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||||
BlobExtraReserve uint64
|
BlobExtraReserve uint64
|
||||||
@@ -128,6 +129,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
|||||||
enc.RPCGasCap = c.RPCGasCap
|
enc.RPCGasCap = c.RPCGasCap
|
||||||
enc.RPCEVMTimeout = c.RPCEVMTimeout
|
enc.RPCEVMTimeout = c.RPCEVMTimeout
|
||||||
enc.RPCTxFeeCap = c.RPCTxFeeCap
|
enc.RPCTxFeeCap = c.RPCTxFeeCap
|
||||||
|
enc.OverridePassedForkTime = c.OverridePassedForkTime
|
||||||
enc.OverrideBohr = c.OverrideBohr
|
enc.OverrideBohr = c.OverrideBohr
|
||||||
enc.OverrideVerkle = c.OverrideVerkle
|
enc.OverrideVerkle = c.OverrideVerkle
|
||||||
enc.BlobExtraReserve = c.BlobExtraReserve
|
enc.BlobExtraReserve = c.BlobExtraReserve
|
||||||
@@ -190,6 +192,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||||||
RPCGasCap *uint64
|
RPCGasCap *uint64
|
||||||
RPCEVMTimeout *time.Duration
|
RPCEVMTimeout *time.Duration
|
||||||
RPCTxFeeCap *float64
|
RPCTxFeeCap *float64
|
||||||
|
OverridePassedForkTime *uint64 `toml:",omitempty"`
|
||||||
OverrideBohr *uint64 `toml:",omitempty"`
|
OverrideBohr *uint64 `toml:",omitempty"`
|
||||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||||
BlobExtraReserve *uint64
|
BlobExtraReserve *uint64
|
||||||
@@ -357,6 +360,9 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
|||||||
if dec.RPCTxFeeCap != nil {
|
if dec.RPCTxFeeCap != nil {
|
||||||
c.RPCTxFeeCap = *dec.RPCTxFeeCap
|
c.RPCTxFeeCap = *dec.RPCTxFeeCap
|
||||||
}
|
}
|
||||||
|
if dec.OverridePassedForkTime != nil {
|
||||||
|
c.OverridePassedForkTime = dec.OverridePassedForkTime
|
||||||
|
}
|
||||||
if dec.OverrideBohr != nil {
|
if dec.OverrideBohr != nil {
|
||||||
c.OverrideBohr = dec.OverrideBohr
|
c.OverrideBohr = dec.OverrideBohr
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ func TestInvalidLogFilterCreation(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestLogFilterUninstall tests invalid getLogs requests
|
// TestInvalidGetLogsRequest tests invalid getLogs requests
|
||||||
func TestInvalidGetLogsRequest(t *testing.T) {
|
func TestInvalidGetLogsRequest(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -124,7 +124,6 @@ type handlerConfig struct {
|
|||||||
DirectBroadcast bool
|
DirectBroadcast bool
|
||||||
DisablePeerTxBroadcast bool
|
DisablePeerTxBroadcast bool
|
||||||
PeerSet *peerSet
|
PeerSet *peerSet
|
||||||
OnlyFullSync bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type handler struct {
|
type handler struct {
|
||||||
@@ -203,37 +202,35 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
|||||||
handlerStartCh: make(chan struct{}),
|
handlerStartCh: make(chan struct{}),
|
||||||
stopCh: make(chan struct{}),
|
stopCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
if !config.OnlyFullSync {
|
if config.Sync == downloader.FullSync {
|
||||||
if config.Sync == downloader.FullSync {
|
// The database seems empty as the current block is the genesis. Yet the snap
|
||||||
// The database seems empty as the current block is the genesis. Yet the snap
|
// block is ahead, so snap sync was enabled for this node at a certain point.
|
||||||
// block is ahead, so snap sync was enabled for this node at a certain point.
|
// The scenarios where this can happen is
|
||||||
// The scenarios where this can happen is
|
// * if the user manually (or via a bad block) rolled back a snap sync node
|
||||||
// * if the user manually (or via a bad block) rolled back a snap sync node
|
// below the sync point.
|
||||||
// below the sync point.
|
// * the last snap sync is not finished while user specifies a full sync this
|
||||||
// * the last snap sync is not finished while user specifies a full sync this
|
// time. But we don't have any recent state for full sync.
|
||||||
// time. But we don't have any recent state for full sync.
|
// In these cases however it's safe to reenable snap sync.
|
||||||
// In these cases however it's safe to reenable snap sync.
|
fullBlock, snapBlock := h.chain.CurrentBlock(), h.chain.CurrentSnapBlock()
|
||||||
fullBlock, snapBlock := h.chain.CurrentBlock(), h.chain.CurrentSnapBlock()
|
if fullBlock.Number.Uint64() == 0 && snapBlock.Number.Uint64() > 0 {
|
||||||
if fullBlock.Number.Uint64() == 0 && snapBlock.Number.Uint64() > 0 {
|
if rawdb.ReadAncientType(h.database) == rawdb.PruneFreezerType {
|
||||||
if rawdb.ReadAncientType(h.database) == rawdb.PruneFreezerType {
|
log.Crit("Fast Sync not finish, can't enable pruneancient mode")
|
||||||
log.Crit("Fast Sync not finish, can't enable pruneancient mode")
|
|
||||||
}
|
|
||||||
h.snapSync.Store(true)
|
|
||||||
log.Warn("Switch sync mode from full sync to snap sync", "reason", "snap sync incomplete")
|
|
||||||
} else if !h.chain.NoTries() && !h.chain.HasState(fullBlock.Number.Int64(), fullBlock.Root) {
|
|
||||||
h.snapSync.Store(true)
|
|
||||||
log.Warn("Switch sync mode from full sync to snap sync", "reason", "head state missing")
|
|
||||||
}
|
}
|
||||||
|
h.snapSync.Store(true)
|
||||||
|
log.Warn("Switch sync mode from full sync to snap sync", "reason", "snap sync incomplete")
|
||||||
|
} else if !h.chain.NoTries() && !h.chain.HasState(fullBlock.Root) {
|
||||||
|
h.snapSync.Store(true)
|
||||||
|
log.Warn("Switch sync mode from full sync to snap sync", "reason", "head state missing")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
head := h.chain.CurrentBlock()
|
||||||
|
if head.Number.Uint64() > 0 && h.chain.HasState(head.Root) {
|
||||||
|
// Print warning log if database is not empty to run snap sync.
|
||||||
|
log.Warn("Switch sync mode from snap sync to full sync", "reason", "snap sync complete")
|
||||||
} else {
|
} else {
|
||||||
head := h.chain.CurrentBlock()
|
// If snap sync was requested and our database is empty, grant it
|
||||||
if head.Number.Uint64() > 0 && h.chain.HasState(head.Number.Int64(), head.Root) {
|
h.snapSync.Store(true)
|
||||||
// Print warning log if database is not empty to run snap sync.
|
log.Info("Enabled snap sync", "head", head.Number, "hash", head.Hash())
|
||||||
log.Warn("Switch sync mode from snap sync to full sync", "reason", "snap sync complete")
|
|
||||||
} else {
|
|
||||||
// If snap sync was requested and our database is empty, grant it
|
|
||||||
h.snapSync.Store(true)
|
|
||||||
log.Info("Enabled snap sync", "head", head.Number, "hash", head.Hash())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If snap sync is requested but snapshots are disabled, fail loudly
|
// If snap sync is requested but snapshots are disabled, fail loudly
|
||||||
|
|||||||
@@ -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.
|
// sink.
|
||||||
func (p *Peer) dispatchResponse(res *Response, metadata func() interface{}) error {
|
func (p *Peer) dispatchResponse(res *Response, metadata func() interface{}) error {
|
||||||
resOp := &response{
|
resOp := &response{
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
|
|||||||
// The state is available in live database, create a reference
|
// The state is available in live database, create a reference
|
||||||
// on top to prevent garbage collection and return a release
|
// on top to prevent garbage collection and return a release
|
||||||
// function to deref it.
|
// function to deref it.
|
||||||
if statedb, err = eth.blockchain.StateAt(block.Number().Int64(), block.Root()); err == nil {
|
if statedb, err = eth.blockchain.StateAt(block.Root()); err == nil {
|
||||||
eth.blockchain.TrieDB().Reference(block.Root(), common.Hash{})
|
eth.blockchain.TrieDB().Reference(block.Root(), common.Hash{})
|
||||||
return statedb, func() {
|
return statedb, func() {
|
||||||
eth.blockchain.TrieDB().Dereference(block.Root())
|
eth.blockchain.TrieDB().Dereference(block.Root())
|
||||||
@@ -71,7 +71,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
|
|||||||
// the internal junks created by tracing will be persisted into the disk.
|
// the internal junks created by tracing will be persisted into the disk.
|
||||||
// TODO(rjl493456442), clean cache is disabled to prevent memory leak,
|
// TODO(rjl493456442), clean cache is disabled to prevent memory leak,
|
||||||
// please re-enable it for better performance.
|
// please re-enable it for better performance.
|
||||||
database = state.NewDatabaseWithConfig(eth.chainDb, triedb.HashDefaults, false)
|
database = state.NewDatabaseWithConfig(eth.chainDb, triedb.HashDefaults)
|
||||||
if statedb, err = state.New(block.Root(), database, nil); err == nil {
|
if statedb, err = state.New(block.Root(), database, nil); err == nil {
|
||||||
log.Info("Found disk backend for state trie", "root", block.Root(), "number", block.Number())
|
log.Info("Found disk backend for state trie", "root", block.Root(), "number", block.Number())
|
||||||
return statedb, noopReleaser, nil
|
return statedb, noopReleaser, nil
|
||||||
@@ -92,7 +92,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
|
|||||||
// TODO(rjl493456442), clean cache is disabled to prevent memory leak,
|
// TODO(rjl493456442), clean cache is disabled to prevent memory leak,
|
||||||
// please re-enable it for better performance.
|
// please re-enable it for better performance.
|
||||||
tdb = triedb.NewDatabase(eth.chainDb, triedb.HashDefaults)
|
tdb = triedb.NewDatabase(eth.chainDb, triedb.HashDefaults)
|
||||||
database = state.NewDatabaseWithNodeDB(eth.chainDb, tdb, false)
|
database = state.NewDatabaseWithNodeDB(eth.chainDb, tdb)
|
||||||
|
|
||||||
// If we didn't check the live database, do check state over ephemeral database,
|
// If we didn't check the live database, do check state over ephemeral database,
|
||||||
// otherwise we would rewind past a persisted block (specific corner case is
|
// otherwise we would rewind past a persisted block (specific corner case is
|
||||||
@@ -185,7 +185,7 @@ func (eth *Ethereum) hashState(ctx context.Context, block *types.Block, reexec u
|
|||||||
|
|
||||||
func (eth *Ethereum) pathState(block *types.Block) (*state.StateDB, func(), error) {
|
func (eth *Ethereum) pathState(block *types.Block) (*state.StateDB, func(), error) {
|
||||||
// Check if the requested state is available in the live chain.
|
// Check if the requested state is available in the live chain.
|
||||||
statedb, err := eth.blockchain.StateAt(block.Number().Int64(), block.Root())
|
statedb, err := eth.blockchain.StateAt(block.Root())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return statedb, noopReleaser, nil
|
return statedb, noopReleaser, nil
|
||||||
}
|
}
|
||||||
@@ -221,7 +221,6 @@ func (eth *Ethereum) stateAtBlock(ctx context.Context, block *types.Block, reexe
|
|||||||
if eth.blockchain.TrieDB().Scheme() == rawdb.HashScheme {
|
if eth.blockchain.TrieDB().Scheme() == rawdb.HashScheme {
|
||||||
return eth.hashState(ctx, block, reexec, base, readOnly, preferDisk)
|
return eth.hashState(ctx, block, reexec, base, readOnly, preferDisk)
|
||||||
}
|
}
|
||||||
// path and version schema use the same interface
|
|
||||||
return eth.pathState(block)
|
return eth.pathState(block)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
50
eth/sync.go
50
eth/sync.go
@@ -17,7 +17,6 @@
|
|||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -192,40 +191,33 @@ func peerToSyncOp(mode downloader.SyncMode, p *eth.Peer) *chainSyncOp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) {
|
func (cs *chainSyncer) modeAndLocalHead() (downloader.SyncMode, *big.Int) {
|
||||||
|
// If we're in snap sync mode, return that directly
|
||||||
|
if cs.handler.snapSync.Load() {
|
||||||
|
block := cs.handler.chain.CurrentSnapBlock()
|
||||||
|
td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64())
|
||||||
|
return downloader.SnapSync, td
|
||||||
|
}
|
||||||
|
// We are probably in full sync, but we might have rewound to before the
|
||||||
|
// snap sync pivot, check if we should re-enable snap sync.
|
||||||
head := cs.handler.chain.CurrentBlock()
|
head := cs.handler.chain.CurrentBlock()
|
||||||
if cs.handler.chain.TrieDB().Scheme() != rawdb.VersionScheme {
|
if pivot := rawdb.ReadLastPivotNumber(cs.handler.database); pivot != nil {
|
||||||
// If we're in snap sync mode, return that directly
|
if head.Number.Uint64() < *pivot {
|
||||||
if cs.handler.snapSync.Load() {
|
if rawdb.ReadAncientType(cs.handler.database) == rawdb.PruneFreezerType {
|
||||||
block := cs.handler.chain.CurrentSnapBlock()
|
log.Crit("Current rewound to before the fast sync pivot, can't enable pruneancient mode", "current block number", head.Number.Uint64(), "pivot", *pivot)
|
||||||
td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64())
|
|
||||||
return downloader.SnapSync, td
|
|
||||||
}
|
|
||||||
// We are probably in full sync, but we might have rewound to before the
|
|
||||||
// snap sync pivot, check if we should re-enable snap sync.
|
|
||||||
head = cs.handler.chain.CurrentBlock()
|
|
||||||
if pivot := rawdb.ReadLastPivotNumber(cs.handler.database); pivot != nil {
|
|
||||||
if head.Number.Uint64() < *pivot {
|
|
||||||
if rawdb.ReadAncientType(cs.handler.database) == rawdb.PruneFreezerType {
|
|
||||||
log.Crit("Current rewound to before the fast sync pivot, can't enable pruneancient mode", "current block number", head.Number.Uint64(), "pivot", *pivot)
|
|
||||||
}
|
|
||||||
block := cs.handler.chain.CurrentSnapBlock()
|
|
||||||
td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64())
|
|
||||||
return downloader.SnapSync, td
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// We are in a full sync, but the associated head state is missing. To complete
|
|
||||||
// the head state, forcefully rerun the snap sync. Note it doesn't mean the
|
|
||||||
// persistent state is corrupted, just mismatch with the head block.
|
|
||||||
if !cs.handler.chain.NoTries() && !cs.handler.chain.HasState(head.Number.Int64(), head.Root) {
|
|
||||||
block := cs.handler.chain.CurrentSnapBlock()
|
block := cs.handler.chain.CurrentSnapBlock()
|
||||||
td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64())
|
td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64())
|
||||||
log.Info("Reenabled snap sync as chain is stateless")
|
|
||||||
return downloader.SnapSync, td
|
return downloader.SnapSync, td
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
if !cs.handler.chain.HasState(head.Number.Int64(), head.Root) {
|
// We are in a full sync, but the associated head state is missing. To complete
|
||||||
panic(fmt.Sprintf("version db not support snap sync, version: %d, root: %s", head.Number.Int64(), head.Root))
|
// the head state, forcefully rerun the snap sync. Note it doesn't mean the
|
||||||
}
|
// persistent state is corrupted, just mismatch with the head block.
|
||||||
|
if !cs.handler.chain.NoTries() && !cs.handler.chain.HasState(head.Root) {
|
||||||
|
block := cs.handler.chain.CurrentSnapBlock()
|
||||||
|
td := cs.handler.chain.GetTd(block.Hash(), block.Number.Uint64())
|
||||||
|
log.Info("Reenabled snap sync as chain is stateless")
|
||||||
|
return downloader.SnapSync, td
|
||||||
}
|
}
|
||||||
// Nope, we're really full syncing
|
// Nope, we're really full syncing
|
||||||
td := cs.handler.chain.GetTd(head.Hash(), head.Number.Uint64())
|
td := cs.handler.chain.GetTd(head.Hash(), head.Number.Uint64())
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
|
|||||||
return json.tx, err
|
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) {
|
func (ec *Client) TransactionsInBlock(ctx context.Context, number *big.Int) ([]*types.Transaction, error) {
|
||||||
var rpcTxs []*rpcTransaction
|
var rpcTxs []*rpcTransaction
|
||||||
err := ec.c.CallContext(ctx, &rpcTxs, "eth_getTransactionsByBlockNumber", toBlockNumArg(number))
|
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
|
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) {
|
func (ec *Client) TransactionRecipientsInBlock(ctx context.Context, number *big.Int) ([]*types.Receipt, error) {
|
||||||
var rs []*types.Receipt
|
var rs []*types.Receipt
|
||||||
err := ec.c.CallContext(ctx, &rs, "eth_getTransactionReceiptsByBlockNumber", toBlockNumArg(number))
|
err := ec.c.CallContext(ctx, &rs, "eth_getTransactionReceiptsByBlockNumber", toBlockNumArg(number))
|
||||||
|
|||||||
26
go.mod
26
go.mod
@@ -12,7 +12,6 @@ require (
|
|||||||
github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.30.2
|
||||||
github.com/bnb-chain/fastssz v0.1.2
|
github.com/bnb-chain/fastssz v0.1.2
|
||||||
github.com/bnb-chain/ics23 v0.1.0
|
github.com/bnb-chain/ics23 v0.1.0
|
||||||
github.com/bnb-chain/versioned-state-database v0.0.0-00010101000000-000000000000
|
|
||||||
github.com/btcsuite/btcd/btcec/v2 v2.3.2
|
github.com/btcsuite/btcd/btcec/v2 v2.3.2
|
||||||
github.com/cespare/cp v1.1.1
|
github.com/cespare/cp v1.1.1
|
||||||
github.com/cloudflare/cloudflare-go v0.79.0
|
github.com/cloudflare/cloudflare-go v0.79.0
|
||||||
@@ -42,10 +41,10 @@ require (
|
|||||||
github.com/gorilla/websocket v1.5.1
|
github.com/gorilla/websocket v1.5.1
|
||||||
github.com/graph-gophers/graphql-go v1.3.0
|
github.com/graph-gophers/graphql-go v1.3.0
|
||||||
github.com/hashicorp/go-bexpr v0.1.10
|
github.com/hashicorp/go-bexpr v0.1.10
|
||||||
github.com/hashicorp/golang-lru v1.0.2
|
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
|
||||||
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4
|
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3
|
github.com/holiman/bloomfilter/v2 v2.0.3
|
||||||
github.com/holiman/uint256 v1.3.0
|
github.com/holiman/uint256 v1.2.4
|
||||||
github.com/huin/goupnp v1.3.0
|
github.com/huin/goupnp v1.3.0
|
||||||
github.com/influxdata/influxdb-client-go/v2 v2.4.0
|
github.com/influxdata/influxdb-client-go/v2 v2.4.0
|
||||||
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
github.com/influxdata/influxdb1-client v0.0.0-20220302092344-a9ab5670611c
|
||||||
@@ -68,7 +67,7 @@ require (
|
|||||||
github.com/rs/cors v1.8.2
|
github.com/rs/cors v1.8.2
|
||||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||||
github.com/status-im/keycard-go v0.2.0
|
github.com/status-im/keycard-go v0.2.0
|
||||||
github.com/stretchr/testify v1.9.0
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/supranational/blst v0.3.11
|
github.com/supranational/blst v0.3.11
|
||||||
github.com/syndtr/goleveldb v1.0.1
|
github.com/syndtr/goleveldb v1.0.1
|
||||||
github.com/tendermint/go-amino v0.14.1
|
github.com/tendermint/go-amino v0.14.1
|
||||||
@@ -80,13 +79,13 @@ require (
|
|||||||
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3
|
github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4 v1.1.3
|
||||||
github.com/willf/bitset v1.1.3
|
github.com/willf/bitset v1.1.3
|
||||||
go.uber.org/automaxprocs v1.5.2
|
go.uber.org/automaxprocs v1.5.2
|
||||||
golang.org/x/crypto v0.25.0
|
golang.org/x/crypto v0.21.0
|
||||||
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
|
golang.org/x/exp v0.0.0-20240213143201-ec583247a57a
|
||||||
golang.org/x/sync v0.7.0
|
golang.org/x/sync v0.6.0
|
||||||
golang.org/x/sys v0.22.0
|
golang.org/x/sys v0.20.0
|
||||||
golang.org/x/text v0.16.0
|
golang.org/x/text v0.14.0
|
||||||
golang.org/x/time v0.5.0
|
golang.org/x/time v0.5.0
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d
|
golang.org/x/tools v0.18.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
@@ -112,7 +111,7 @@ require (
|
|||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bits-and-blooms/bitset v1.11.0 // indirect
|
github.com/bits-and-blooms/bitset v1.11.0 // indirect
|
||||||
github.com/cespare/xxhash v1.1.0 // indirect
|
github.com/cespare/xxhash v1.1.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/chzyer/readline v1.5.1 // indirect
|
github.com/chzyer/readline v1.5.1 // indirect
|
||||||
github.com/cockroachdb/errors v1.11.1 // indirect
|
github.com/cockroachdb/errors v1.11.1 // indirect
|
||||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
||||||
@@ -272,10 +271,10 @@ require (
|
|||||||
go.uber.org/mock v0.4.0 // indirect
|
go.uber.org/mock v0.4.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.uber.org/zap v1.27.0 // indirect
|
go.uber.org/zap v1.27.0 // indirect
|
||||||
golang.org/x/mod v0.17.0 // indirect
|
golang.org/x/mod v0.15.0 // indirect
|
||||||
golang.org/x/net v0.25.0 // indirect
|
golang.org/x/net v0.23.0 // indirect
|
||||||
golang.org/x/oauth2 v0.16.0 // indirect
|
golang.org/x/oauth2 v0.16.0 // indirect
|
||||||
golang.org/x/term v0.22.0 // indirect
|
golang.org/x/term v0.18.0 // indirect
|
||||||
google.golang.org/api v0.44.0 // indirect
|
google.golang.org/api v0.44.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
|
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
|
||||||
@@ -296,7 +295,6 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
github.com/bnb-chain/versioned-state-database => ../versioned-state-database
|
|
||||||
github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-cometbft v1.3.1
|
github.com/cometbft/cometbft => github.com/bnb-chain/greenfield-cometbft v1.3.1
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 => github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1
|
github.com/grpc-ecosystem/grpc-gateway/v2 => github.com/prysmaticlabs/grpc-gateway/v2 v2.3.1-0.20210702154020-550e1cd83ec1
|
||||||
github.com/syndtr/goleveldb v1.0.1 => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
|
github.com/syndtr/goleveldb v1.0.1 => github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
|
||||||
|
|||||||
51
go.sum
51
go.sum
@@ -185,9 +185,8 @@ github.com/cespare/cp v1.1.1/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW
|
|||||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
|
github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY=
|
||||||
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
|
github.com/chzyer/logex v1.2.1 h1:XHDu3E6q+gdHgsdTPH6ImJMIp436vR6MPtH8gP05QzM=
|
||||||
@@ -327,6 +326,7 @@ 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/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/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.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
|
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 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
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 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||||
@@ -598,8 +598,8 @@ github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09
|
|||||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v1.0.2 h1:dV3g9Z/unq5DpblPpw+Oqcv4dU/1omnb4Ok8iPY6p1c=
|
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d h1:dg1dEPuWpEqDnvIw251EVy4zlP8gWbsGj4BsUKCRpYs=
|
||||||
github.com/hashicorp/golang-lru v1.0.2/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
|
github.com/hashicorp/golang-lru/v2 v2.0.5 h1:wW7h1TG88eUIJ2i69gaE3uNVtEPIagzhGvHgwfx2Vm4=
|
||||||
github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
github.com/hashicorp/golang-lru/v2 v2.0.5/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
@@ -614,8 +614,8 @@ github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4 h1:X4egAf/gcS1zATw6w
|
|||||||
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
|
github.com/holiman/billy v0.0.0-20240216141850-2abb0c79d3c4/go.mod h1:5GuXa7vkL8u9FkFuWdVvfR5ix8hRB7DbOAaYULamFpc=
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
|
||||||
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA=
|
||||||
github.com/holiman/uint256 v1.3.0 h1:4wdcm/tnd0xXdu7iS3ruNvxkWwrb4aeBQv19ayYn8F4=
|
github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU=
|
||||||
github.com/holiman/uint256 v1.3.0/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
|
||||||
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc=
|
||||||
@@ -1121,9 +1121,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
|||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
|
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
@@ -1134,8 +1133,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
|
github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
|
||||||
github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
|
||||||
@@ -1287,8 +1286,8 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm
|
|||||||
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
@@ -1327,8 +1326,8 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
|
||||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
@@ -1380,8 +1379,8 @@ golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLd
|
|||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
@@ -1412,8 +1411,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@@ -1504,13 +1503,13 @@ 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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.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.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
|
||||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
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-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-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||||
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -1521,8 +1520,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
@@ -1596,8 +1595,8 @@ golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4f
|
|||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
golang.org/x/tools v0.18.0 h1:k8NLag8AGHnn+PHbl7g43CtqZAwG60vZkLqgyZgIHgQ=
|
||||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
golang.org/x/tools v0.18.0/go.mod h1:GL7B4CwcLLeo59yx/9UWWuNOW1n3VZ4f5axWfML7Lcg=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|||||||
@@ -870,7 +870,10 @@ func (s *BlockChainAPI) GetFinalizedHeader(ctx context.Context, probabilisticFin
|
|||||||
return nil, fmt.Errorf("%d out of range [2,21]", probabilisticFinalized)
|
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)
|
fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
|
||||||
if err != nil { // impossible
|
if err != nil { // impossible
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -879,7 +882,7 @@ func (s *BlockChainAPI) GetFinalizedHeader(ctx context.Context, probabilisticFin
|
|||||||
if err != nil { // impossible
|
if err != nil { // impossible
|
||||||
return nil, err
|
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))
|
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)
|
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)
|
fastFinalizedHeader, err := s.b.HeaderByNumber(ctx, rpc.FinalizedBlockNumber)
|
||||||
if err != nil { // impossible
|
if err != nil { // impossible
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -903,7 +909,7 @@ func (s *BlockChainAPI) GetFinalizedBlock(ctx context.Context, probabilisticFina
|
|||||||
if err != nil { // impossible
|
if err != nil { // impossible
|
||||||
return nil, err
|
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)
|
return s.GetBlockByNumber(ctx, rpc.BlockNumber(finalizedBlockNumber), fullTx)
|
||||||
}
|
}
|
||||||
@@ -1367,11 +1373,11 @@ func (s *BlockChainAPI) needToReplay(ctx context.Context, block *types.Block, ac
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("block not found for block number (%d): %v", block.NumberU64()-1, err)
|
return false, fmt.Errorf("block not found for block number (%d): %v", block.NumberU64()-1, err)
|
||||||
}
|
}
|
||||||
parentState, err := s.b.Chain().StateAt(parent.Number().Int64(), parent.Root())
|
parentState, err := s.b.Chain().StateAt(parent.Root())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("statedb not found for block number (%d): %v", block.NumberU64()-1, err)
|
return false, fmt.Errorf("statedb not found for block number (%d): %v", block.NumberU64()-1, err)
|
||||||
}
|
}
|
||||||
currentState, err := s.b.Chain().StateAt(parent.Number().Int64(), block.Root())
|
currentState, err := s.b.Chain().StateAt(block.Root())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, fmt.Errorf("statedb not found for block number (%d): %v", block.NumberU64(), err)
|
return false, fmt.Errorf("statedb not found for block number (%d): %v", block.NumberU64(), err)
|
||||||
}
|
}
|
||||||
@@ -1397,7 +1403,7 @@ func (s *BlockChainAPI) replay(ctx context.Context, block *types.Block, accounts
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("block not found for block number (%d): %v", block.NumberU64()-1, err)
|
return nil, nil, fmt.Errorf("block not found for block number (%d): %v", block.NumberU64()-1, err)
|
||||||
}
|
}
|
||||||
statedb, err := s.b.Chain().StateAt(parent.Number().Int64(), parent.Root())
|
statedb, err := s.b.Chain().StateAt(parent.Root())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, fmt.Errorf("state not found for block number (%d): %v", block.NumberU64()-1, err)
|
return nil, nil, fmt.Errorf("state not found for block number (%d): %v", block.NumberU64()-1, err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -631,8 +631,9 @@ func (b testBackend) TxPoolContentFrom(addr common.Address) ([]*types.Transactio
|
|||||||
func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.Subscription {
|
func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.Subscription {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
|
func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
|
||||||
func (b testBackend) Engine() consensus.Engine { return b.chain.Engine() }
|
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) {
|
func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,6 +89,8 @@ type Backend interface {
|
|||||||
|
|
||||||
ChainConfig() *params.ChainConfig
|
ChainConfig() *params.ChainConfig
|
||||||
Engine() consensus.Engine
|
Engine() consensus.Engine
|
||||||
|
// CurrentTurnLength return the turnLength at the latest block
|
||||||
|
CurrentTurnLength() (uint8, error)
|
||||||
|
|
||||||
// This is copied from filters.Backend
|
// This is copied from filters.Backend
|
||||||
// eth/filters needs to be initialized from this backend type, so methods needed by
|
// eth/filters needs to be initialized from this backend type, so methods needed by
|
||||||
|
|||||||
@@ -416,6 +416,8 @@ func (b *backendMock) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent)
|
|||||||
|
|
||||||
func (b *backendMock) Engine() consensus.Engine { return nil }
|
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) MevRunning() bool { return false }
|
||||||
func (b *backendMock) HasBuilder(builder common.Address) bool { return false }
|
func (b *backendMock) HasBuilder(builder common.Address) bool { return false }
|
||||||
func (b *backendMock) MevParams() *types.MevParams {
|
func (b *backendMock) MevParams() *types.MevParams {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/common/bidutil"
|
"github.com/ethereum/go-ethereum/common/bidutil"
|
||||||
"github.com/ethereum/go-ethereum/consensus"
|
"github.com/ethereum/go-ethereum/consensus"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"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/core/types"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
@@ -82,6 +83,7 @@ type bidSimulator struct {
|
|||||||
delayLeftOver time.Duration
|
delayLeftOver time.Duration
|
||||||
minGasPrice *big.Int
|
minGasPrice *big.Int
|
||||||
chain *core.BlockChain
|
chain *core.BlockChain
|
||||||
|
txpool *txpool.TxPool
|
||||||
chainConfig *params.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
engine consensus.Engine
|
engine consensus.Engine
|
||||||
bidWorker bidWorker
|
bidWorker bidWorker
|
||||||
@@ -118,7 +120,7 @@ func newBidSimulator(
|
|||||||
config *MevConfig,
|
config *MevConfig,
|
||||||
delayLeftOver time.Duration,
|
delayLeftOver time.Duration,
|
||||||
minGasPrice *big.Int,
|
minGasPrice *big.Int,
|
||||||
chain *core.BlockChain,
|
eth Backend,
|
||||||
chainConfig *params.ChainConfig,
|
chainConfig *params.ChainConfig,
|
||||||
engine consensus.Engine,
|
engine consensus.Engine,
|
||||||
bidWorker bidWorker,
|
bidWorker bidWorker,
|
||||||
@@ -127,7 +129,8 @@ func newBidSimulator(
|
|||||||
config: config,
|
config: config,
|
||||||
delayLeftOver: delayLeftOver,
|
delayLeftOver: delayLeftOver,
|
||||||
minGasPrice: minGasPrice,
|
minGasPrice: minGasPrice,
|
||||||
chain: chain,
|
chain: eth.BlockChain(),
|
||||||
|
txpool: eth.TxPool(),
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
engine: engine,
|
engine: engine,
|
||||||
bidWorker: bidWorker,
|
bidWorker: bidWorker,
|
||||||
@@ -141,7 +144,7 @@ func newBidSimulator(
|
|||||||
simulatingBid: make(map[common.Hash]*BidRuntime),
|
simulatingBid: make(map[common.Hash]*BidRuntime),
|
||||||
}
|
}
|
||||||
|
|
||||||
b.chainHeadSub = chain.SubscribeChainHeadEvent(b.chainHeadCh)
|
b.chainHeadSub = b.chain.SubscribeChainHeadEvent(b.chainHeadCh)
|
||||||
|
|
||||||
if config.Enabled {
|
if config.Enabled {
|
||||||
b.bidReceiving.Store(true)
|
b.bidReceiving.Store(true)
|
||||||
@@ -409,7 +412,7 @@ func (b *bidSimulator) clearLoop() {
|
|||||||
}
|
}
|
||||||
delete(b.bestBid, parentHash)
|
delete(b.bestBid, parentHash)
|
||||||
for k, v := range b.bestBid {
|
for k, v := range b.bestBid {
|
||||||
if v.bid.BlockNumber <= blockNumber-core.TriesInMemory {
|
if v.bid.BlockNumber <= blockNumber-b.chain.TriesInMemory() {
|
||||||
v.env.discard()
|
v.env.discard()
|
||||||
delete(b.bestBid, k)
|
delete(b.bestBid, k)
|
||||||
}
|
}
|
||||||
@@ -418,7 +421,7 @@ func (b *bidSimulator) clearLoop() {
|
|||||||
|
|
||||||
b.simBidMu.Lock()
|
b.simBidMu.Lock()
|
||||||
for k, v := range b.simulatingBid {
|
for k, v := range b.simulatingBid {
|
||||||
if v.bid.BlockNumber <= blockNumber-core.TriesInMemory {
|
if v.bid.BlockNumber <= blockNumber-b.chain.TriesInMemory() {
|
||||||
v.env.discard()
|
v.env.discard()
|
||||||
delete(b.simulatingBid, k)
|
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
|
// check if bid gas price is lower than min gas price
|
||||||
{
|
{
|
||||||
bidGasUsed := uint64(0)
|
bidGasUsed := uint64(0)
|
||||||
bidGasFee := bidRuntime.env.state.GetBalance(consensus.SystemAddress)
|
bidGasFee := big.NewInt(0)
|
||||||
|
|
||||||
for _, receipt := range bidRuntime.env.receipts {
|
for i, receipt := range bidRuntime.env.receipts {
|
||||||
bidGasUsed += receipt.GasUsed
|
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 bid txs are all from mempool, do not check gas price
|
||||||
if bidGasPrice.Cmp(b.minGasPrice) < 0 {
|
if bidGasUsed != 0 {
|
||||||
err = errors.New("bid gas price is lower than min gas price")
|
bidGasPrice := new(big.Int).Div(bidGasFee, new(big.Int).SetUint64(bidGasUsed))
|
||||||
return
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ func New(eth Backend, config *Config, chainConfig *params.ChainConfig, mux *even
|
|||||||
worker: newWorker(config, chainConfig, engine, eth, mux, isLocalBlock, false),
|
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.worker.setBestBidFetcher(miner.bidSimulator)
|
||||||
|
|
||||||
miner.wg.Add(1)
|
miner.wg.Add(1)
|
||||||
@@ -245,7 +245,7 @@ func (miner *Miner) Pending() (*types.Block, *state.StateDB) {
|
|||||||
if block == nil {
|
if block == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
stateDb, err := miner.worker.chain.StateAt(block.Number.Int64(), block.Root)
|
stateDb, err := miner.worker.chain.StateAt(block.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -690,7 +690,7 @@ func (w *worker) makeEnv(parent *types.Header, header *types.Header, coinbase co
|
|||||||
prevEnv *environment) (*environment, error) {
|
prevEnv *environment) (*environment, error) {
|
||||||
// Retrieve the parent state to execute on top and start a prefetcher for
|
// Retrieve the parent state to execute on top and start a prefetcher for
|
||||||
// the miner to speed block sealing up a bit
|
// the miner to speed block sealing up a bit
|
||||||
state, err := w.chain.StateAt(parent.Number.Int64(), parent.Root)
|
state, err := w.chain.StateAt(parent.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -1032,6 +1032,8 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
|
|||||||
}
|
}
|
||||||
if w.chainConfig.Parlia == nil {
|
if w.chainConfig.Parlia == nil {
|
||||||
header.ParentBeaconRoot = genParams.beaconRoot
|
header.ParentBeaconRoot = genParams.beaconRoot
|
||||||
|
} else if w.chainConfig.IsBohr(header.Number, header.Time) {
|
||||||
|
header.ParentBeaconRoot = new(common.Hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Could potentially happen if starting to mine in an odd state.
|
// Could potentially happen if starting to mine in an odd state.
|
||||||
|
|||||||
@@ -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.
|
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.
|
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
|
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
|
// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations
|
||||||
|
|||||||
@@ -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
|
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
|
--- a/core/vm/contracts.go
|
||||||
+++ b/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{7}): &bn256ScalarMulIstanbul{},
|
||||||
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
|
common.BytesToAddress([]byte{8}): &bn256PairingIstanbul{},
|
||||||
common.BytesToAddress([]byte{9}): &blake2F{},
|
common.BytesToAddress([]byte{9}): &blake2F{},
|
||||||
@@ -12,7 +23,7 @@ index 5988bb15f..c92cbf542 100644
|
|||||||
}
|
}
|
||||||
|
|
||||||
var PrecompiledContractsNano = map[common.Address]PrecompiledContract{
|
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{8}): &bn256PairingIstanbul{},
|
||||||
common.BytesToAddress([]byte{9}): &blake2F{},
|
common.BytesToAddress([]byte{9}): &blake2F{},
|
||||||
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
|
common.BytesToAddress([]byte{0x0a}): &kzgPointEvaluation{},
|
||||||
@@ -25,7 +36,7 @@ index 5988bb15f..c92cbf542 100644
|
|||||||
- common.BytesToAddress([]byte{105}): &secp256k1SignatureRecover{},
|
- 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
|
diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go
|
||||||
index 70c543f14..65716f944 100644
|
index 70c543f14..65716f944 100644
|
||||||
--- a/core/vm/jump_table.go
|
--- a/core/vm/jump_table.go
|
||||||
@@ -40,7 +51,7 @@ index 70c543f14..65716f944 100644
|
|||||||
enable3860(&instructionSet) // Limit and meter initcode
|
enable3860(&instructionSet) // Limit and meter initcode
|
||||||
|
|
||||||
diff --git a/params/protocol_params.go b/params/protocol_params.go
|
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
|
--- a/params/protocol_params.go
|
||||||
+++ b/params/protocol_params.go
|
+++ b/params/protocol_params.go
|
||||||
@@ -23,7 +23,7 @@ import (
|
@@ -23,7 +23,7 @@ import (
|
||||||
@@ -52,3 +63,6 @@ index b84fa148f..97bf6c4d2 100644
|
|||||||
MinGasLimit uint64 = 5000 // Minimum the gas limit may ever be.
|
MinGasLimit uint64 = 5000 // Minimum the gas limit may ever be.
|
||||||
MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1).
|
MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1).
|
||||||
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
|
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
|
||||||
|
--
|
||||||
|
2.41.0
|
||||||
|
|
||||||
|
|||||||
@@ -11,4 +11,5 @@ echo "PASS",$PASS,"FAIL",$FAIL
|
|||||||
if [ $FAIL -ne 0 ]
|
if [ $FAIL -ne 0 ]
|
||||||
then
|
then
|
||||||
cat fail.log
|
cat fail.log
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -31,11 +31,6 @@ func NewEmptyTrie() *EmptyTrie {
|
|||||||
return &EmptyTrie{}
|
return &EmptyTrie{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *EmptyTrie) WriteBatch(values map[string][]byte) error {
|
|
||||||
panic("EmptyTrie not support WriteBatch")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *EmptyTrie) GetKey(shaKey []byte) []byte {
|
func (t *EmptyTrie) GetKey(shaKey []byte) []byte {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,11 +73,6 @@ func NewStateTrie(id *ID, db database.Database) (*StateTrie, error) {
|
|||||||
return &StateTrie{trie: *trie, db: db}, nil
|
return &StateTrie{trie: *trie, db: db}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *StateTrie) WriteBatch(values map[string][]byte) error {
|
|
||||||
panic("StateTrie not support WriteBatch")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MustGet returns the value for key stored in the trie.
|
// MustGet returns the value for key stored in the trie.
|
||||||
// The value bytes must not be modified by the caller.
|
// The value bytes must not be modified by the caller.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type ID struct {
|
|||||||
StateRoot common.Hash // The root of the corresponding state(block.root)
|
StateRoot common.Hash // The root of the corresponding state(block.root)
|
||||||
Owner common.Hash // The contract address hash which the trie belongs to
|
Owner common.Hash // The contract address hash which the trie belongs to
|
||||||
Root common.Hash // The root hash of trie
|
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.
|
// StateTrieID constructs an identifier for state trie with the provided state root.
|
||||||
|
|||||||
@@ -69,11 +69,6 @@ func NewVerkleTrie(root common.Hash, db database.Database, cache *utils.PointCac
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *VerkleTrie) WriteBatch(values map[string][]byte) error {
|
|
||||||
panic("VerkleTrie not support WriteBatch")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetKey returns the sha3 preimage of a hashed key that was previously used
|
// GetKey returns the sha3 preimage of a hashed key that was previously used
|
||||||
// to store a value.
|
// to store a value.
|
||||||
func (t *VerkleTrie) GetKey(key []byte) []byte {
|
func (t *VerkleTrie) GetKey(key []byte) []byte {
|
||||||
|
|||||||
119
trie/version_trie.go
Normal file
119
trie/version_trie.go
Normal 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
|
||||||
|
}
|
||||||
@@ -18,9 +18,9 @@ package triedb
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/ethereum/go-ethereum/triedb/versadb"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
versa "github.com/bnb-chain/versioned-state-database"
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
@@ -31,7 +31,6 @@ import (
|
|||||||
"github.com/ethereum/go-ethereum/triedb/database"
|
"github.com/ethereum/go-ethereum/triedb/database"
|
||||||
"github.com/ethereum/go-ethereum/triedb/hashdb"
|
"github.com/ethereum/go-ethereum/triedb/hashdb"
|
||||||
"github.com/ethereum/go-ethereum/triedb/pathdb"
|
"github.com/ethereum/go-ethereum/triedb/pathdb"
|
||||||
"github.com/ethereum/go-ethereum/triedb/versiondb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config defines all necessary options for database.
|
// Config defines all necessary options for database.
|
||||||
@@ -40,10 +39,10 @@ type Config struct {
|
|||||||
Cache int
|
Cache int
|
||||||
NoTries bool
|
NoTries bool
|
||||||
IsVerkle bool // Flag whether the db is holding a verkle tree
|
IsVerkle bool // Flag whether the db is holding a verkle tree
|
||||||
IsVersion bool
|
IsVersa bool
|
||||||
VersionDB *versiondb.Config
|
HashDB *hashdb.Config // Configs for hash-based scheme
|
||||||
HashDB *hashdb.Config // Configs for hash-based scheme
|
PathDB *pathdb.Config // Configs for experimental path-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
|
// HashDefaults represents a config for using hash-based scheme with
|
||||||
@@ -96,16 +95,6 @@ type Database struct {
|
|||||||
// NewDatabase initializes the trie database with default settings, note
|
// NewDatabase initializes the trie database with default settings, note
|
||||||
// the legacy hash-based scheme is used by default.
|
// the legacy hash-based scheme is used by default.
|
||||||
func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
|
func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
|
||||||
if config != nil && config.IsVersion {
|
|
||||||
// TODO:: Wait for debugging to stabilize, and then consider initialization compatibility with other databases
|
|
||||||
db := &Database{
|
|
||||||
config: config,
|
|
||||||
diskdb: diskdb,
|
|
||||||
backend: versiondb.New(config.VersionDB),
|
|
||||||
}
|
|
||||||
return db
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sanitize the config and use the default one if it's not specified.
|
// Sanitize the config and use the default one if it's not specified.
|
||||||
var triediskdb ethdb.Database
|
var triediskdb ethdb.Database
|
||||||
if diskdb != nil && diskdb.StateStore() != nil {
|
if diskdb != nil && diskdb.StateStore() != nil {
|
||||||
@@ -162,6 +151,11 @@ func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
|
|||||||
config.PathDB = pathdb.Defaults
|
config.PathDB = pathdb.Defaults
|
||||||
}
|
}
|
||||||
db.backend = pathdb.New(triediskdb, config.PathDB)
|
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 {
|
} else {
|
||||||
var resolver hashdb.ChildResolver
|
var resolver hashdb.ChildResolver
|
||||||
if config.IsVerkle {
|
if config.IsVerkle {
|
||||||
@@ -424,11 +418,7 @@ func (db *Database) IsVerkle() bool {
|
|||||||
return db.config.IsVerkle
|
return db.config.IsVerkle
|
||||||
}
|
}
|
||||||
|
|
||||||
// VersaDB returns versioned database instance, it is useless for hashdb and pathdb
|
// IsVersionedState returns the indicator if the database is holding a versioned state.
|
||||||
func (db *Database) VersaDB() versa.Database {
|
func (db *Database) IsVersionedState() bool {
|
||||||
vdb, ok := db.backend.(*versiondb.VersionDB)
|
return db.config.IsVersa
|
||||||
if !ok {
|
|
||||||
log.Crit("only version db support")
|
|
||||||
}
|
|
||||||
return vdb.VersaDB()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,7 +139,6 @@ func New(diskdb ethdb.Database, config *Config, resolver ChildResolver) *Databas
|
|||||||
if config.CleanCacheSize > 0 {
|
if config.CleanCacheSize > 0 {
|
||||||
cleans = fastcache.New(config.CleanCacheSize)
|
cleans = fastcache.New(config.CleanCacheSize)
|
||||||
}
|
}
|
||||||
log.Info("success to init hash mode triedb")
|
|
||||||
return &Database{
|
return &Database{
|
||||||
diskdb: diskdb,
|
diskdb: diskdb,
|
||||||
resolver: resolver,
|
resolver: resolver,
|
||||||
|
|||||||
@@ -226,7 +226,6 @@ func New(diskdb ethdb.Database, config *Config) *Database {
|
|||||||
log.Crit("Failed to disable database", "err", err) // impossible to happen
|
log.Crit("Failed to disable database", "err", err) // impossible to happen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log.Info("success to init path mode triedb")
|
|
||||||
return db
|
return db
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
82
triedb/versadb/database.go
Normal file
82
triedb/versadb/database.go
Normal 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
|
||||||
|
}
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
package versiondb
|
|
||||||
|
|
||||||
import (
|
|
||||||
versa "github.com/bnb-chain/versioned-state-database"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
|
||||||
"github.com/ethereum/go-ethereum/trie/triestate"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
Path string
|
|
||||||
FlushInterval int64
|
|
||||||
MaxStatesInMem int
|
|
||||||
}
|
|
||||||
|
|
||||||
type VersionDB struct {
|
|
||||||
db versa.Database
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(config *Config) *VersionDB {
|
|
||||||
var (
|
|
||||||
//cfg *versa.VersaDBConfig
|
|
||||||
path = "./node/version_db" // TODO:: debug code
|
|
||||||
)
|
|
||||||
|
|
||||||
//if config != nil {
|
|
||||||
// path = config.Path
|
|
||||||
// cfg = &versa.VersaDBConfig{
|
|
||||||
// FlushInterval: 2000,
|
|
||||||
// MaxStatesInMem: 128,
|
|
||||||
// MemLowWaterMark: 10,
|
|
||||||
// MemHighWaterMark: 20,
|
|
||||||
// MemEvictInternal: 200,
|
|
||||||
// }
|
|
||||||
// _ = cfg
|
|
||||||
//}
|
|
||||||
db, err := versa.NewVersaDB(path, &versa.VersaDBConfig{})
|
|
||||||
if err != nil {
|
|
||||||
log.Crit("failed to new version db", "error", err)
|
|
||||||
}
|
|
||||||
v := &VersionDB{
|
|
||||||
db: db,
|
|
||||||
}
|
|
||||||
log.Info("success to init version mode triedb")
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VersionDB) Scheme() string {
|
|
||||||
return rawdb.VersionScheme
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VersionDB) Initialized(genesisRoot common.Hash) bool {
|
|
||||||
version, _ := v.db.LatestStoreDiskVersionInfo()
|
|
||||||
return version >= 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VersionDB) Size() (common.StorageSize, common.StorageSize, common.StorageSize) {
|
|
||||||
// TODO:: waiting versa db supported
|
|
||||||
return 0, 0, 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VersionDB) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error {
|
|
||||||
// TODO:: debug code, will change to return error.
|
|
||||||
panic("version db not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VersionDB) Commit(root common.Hash, report bool) error {
|
|
||||||
// TODO:: debug code, will change to return error.
|
|
||||||
panic("version db not supported")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VersionDB) Close() error {
|
|
||||||
return v.db.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VersionDB) VersaDB() versa.Database {
|
|
||||||
return v.db
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user