From 97f7d4e5d03f5e0d98977d2583b75808ba27fbcc Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Fri, 3 Nov 2023 16:59:04 +0700 Subject: [PATCH 01/10] precompiled: add procompiled contract to verify proof of possession BLS --- core/vm/consortium_precompiled_contracts.go | 61 +++++++++++++++++++ .../consortium_precompiled_contracts_test.go | 55 +++++++++++++++++ core/vm/contracts_test.go | 1 + core/vm/evm.go | 8 ++- crypto/bls/blst/secret_key.go | 9 ++- crypto/bls/blst/signature.go | 26 +++++--- crypto/bls/blst/signature_test.go | 7 ++- crypto/bls/common/interface.go | 2 + params/protocol_params.go | 1 + 9 files changed, 157 insertions(+), 13 deletions(-) diff --git a/core/vm/consortium_precompiled_contracts.go b/core/vm/consortium_precompiled_contracts.go index 696e3f0279..3ff619ecf9 100644 --- a/core/vm/consortium_precompiled_contracts.go +++ b/core/vm/consortium_precompiled_contracts.go @@ -31,6 +31,7 @@ const ( PickValidatorSet GetDoubleSignSlashingConfig ValidateFinalityVoteProof + ValidateProofOfPossession NumOfAbis ) @@ -41,6 +42,7 @@ var ( rawConsortiumPickValidatorSetAbi = `[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address[]","name":"_candidates","type":"address[]"},{"internalType":"uint256[]","name":"_weights","type":"uint256[]"},{"internalType":"uint256[]","name":"_trustedWeights","type":"uint256[]"},{"internalType":"uint256","name":"_maxValidatorNumber","type":"uint256"},{"internalType":"uint256","name":"_maxPrioritizedValidatorNumber","type":"uint256"}],"name":"pickValidatorSet","outputs":[{"internalType":"address[]","name":"_validators","type":"address[]"}],"stateMutability":"view","type":"function"}]` rawGetDoubleSignSlashingConfigsAbi = `[{"inputs":[],"name":"getDoubleSignSlashingConfigs","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]` rawValidateFinalityVoteProofAbi = `[{"inputs":[{"internalType":"bytes","name":"voterPublicKey","type":"bytes"},{"internalType":"uint256","name":"targetBlockNumber","type":"uint256"},{"internalType":"bytes32[2]","name":"targetBlockHash","type":"bytes32[2]"},{"internalType":"bytes[][2]","name":"listOfPublicKey","type":"bytes[][2]"},{"internalType":"bytes[2]","name":"aggregatedSignature","type":"bytes[2]"}],"name":"validateFinalityVoteProof","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]` + rawValidateProofOfPossessionAbi = `[{"inputs":[{"internalType":"bytes","name":"publicKey","type":"bytes"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"validateProofOfPossession","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"}]` rawABIs = [NumOfAbis]string{ LogContract: rawConsortiumLogAbi, @@ -49,6 +51,7 @@ var ( PickValidatorSet: rawConsortiumPickValidatorSetAbi, GetDoubleSignSlashingConfig: rawGetDoubleSignSlashingConfigsAbi, ValidateFinalityVoteProof: rawValidateFinalityVoteProofAbi, + ValidateProofOfPossession: rawValidateProofOfPossessionAbi, } unmarshalledABIs = [NumOfAbis]*abi.ABI{} @@ -66,6 +69,7 @@ const ( extraVanity = 32 validateFinalityVoteProof = "validateFinalityVoteProof" + validateProofOfPossession = "validateProofOfPossession" maxBlsPublicKeyListLength = 100 ) @@ -90,6 +94,12 @@ func PrecompiledContractsConsortium(caller ContractRef, evm *EVM) map[common.Add } } +func PrecompiledContractsConsortiumMiko(caller ContractRef, evm *EVM) map[common.Address]PrecompiledContract { + contracts := PrecompiledContractsConsortium(caller, evm) + contracts[common.BytesToAddress([]byte{106})] = &consortiumValidateProofOfPossession{caller: caller, evm: evm} + return contracts +} + type consortiumLog struct{} func (c *consortiumLog) RequiredGas(_ []byte) uint64 { @@ -712,3 +722,54 @@ func (contract *consortiumValidateFinalityProof) Run(input []byte) ([]byte, erro return method.Outputs.Pack(true) } + +type consortiumValidateProofOfPossession struct { + caller ContractRef + evm *EVM +} + +func (contract *consortiumValidateProofOfPossession) RequiredGas(input []byte) uint64 { + return params.ValidateProofOfPossession +} + +func (contract *consortiumValidateProofOfPossession) Run(input []byte) ([]byte, error) { + if err := isSystemContractCaller(contract.caller, contract.evm); err != nil { + return nil, err + } + _, method, args, err := loadMethodAndArgs(ValidateProofOfPossession, input) + if err != nil { + return nil, err + } + if method.Name != validateProofOfPossession { + return nil, errors.New("invalid method") + } + if len(args) != 2 { + return nil, fmt.Errorf("invalid arguments, expect 2 got %d", len(args)) + } + + rawPublicKey, ok := args[0].([]byte) + if !ok { + return nil, errors.New("invalid voter public key") + } + + rawSignature, ok := args[1].([]byte) + if !ok { + return nil, errors.New("invalid proof signature") + } + + blsPublicKey, err := blst.PublicKeyFromBytes(rawPublicKey) + if err != nil { + return nil, errors.New("malformed voter public key") + } + + blsSignature, err := blst.SignatureFromBytes(rawSignature) + if err != nil { + return nil, errors.New("malformed proof signature") + } + + if !blsSignature.VerifyProof(blsPublicKey, rawPublicKey) { + return nil, errors.New("invalid possession proof") + } + + return method.Outputs.Pack(true) +} diff --git a/core/vm/consortium_precompiled_contracts_test.go b/core/vm/consortium_precompiled_contracts_test.go index 84c1866139..c60836f994 100644 --- a/core/vm/consortium_precompiled_contracts_test.go +++ b/core/vm/consortium_precompiled_contracts_test.go @@ -2107,3 +2107,58 @@ func BenchmarkPrecompiledValidateFinalityVoteProof(b *testing.B) { benchmarkPrecompiled("69", test, b) } + +func TestValidateProofOfPossession(t *testing.T) { + contract := consortiumValidateProofOfPossession{} + contractAbi := *unmarshalledABIs[ValidateProofOfPossession] + + // Generated by `ronin account generate-bls-proof` + publicKey := common.Hex2Bytes("a9efd6ee7841b5703c70be3348fd546710069ec6912f123b6bb414aaf4815c68f3daa0ab9fb3c18f8cd3af88352ba72b") + proof := common.Hex2Bytes("a93f4ec59b89a3fcab0e71fd0e94990a7ecb28b65bbafd2a03b8ed7bfd480ebbf98c49cacb01fd98f4b24d126a46e3740cfc590f3ae3dd10b9c18f04de158b909f2886ef6dde4c9e01f83d92f33aa2027f825b718e2fe184ea2c952aeca33713") + + input, err := contractAbi.Pack(validateProofOfPossession, publicKey, proof) + if err != nil { + t.Fatalf("Failed to pack contract input, err %s", err) + } + + rawReturn, err := contract.Run(input) + if err != nil { + t.Fatalf("Precompiled contract returns error, err %s", err) + } + + ret, err := contractAbi.Unpack(validateProofOfPossession, rawReturn) + if err != nil { + t.Fatalf("Failed to unpack output, err: %s", err) + } + + returnedBool := (ret[0]).(bool) + if returnedBool != true { + t.Fatalf("Expect the returned value to be true, get %v", returnedBool) + } +} + +func BenchmarkPrecompiledValidateProofOfPossession(b *testing.B) { + contractAbi := *unmarshalledABIs[ValidateProofOfPossession] + + // Generated by `ronin account generate-bls-proof` + publicKey := common.Hex2Bytes("a9efd6ee7841b5703c70be3348fd546710069ec6912f123b6bb414aaf4815c68f3daa0ab9fb3c18f8cd3af88352ba72b") + proof := common.Hex2Bytes("a93f4ec59b89a3fcab0e71fd0e94990a7ecb28b65bbafd2a03b8ed7bfd480ebbf98c49cacb01fd98f4b24d126a46e3740cfc590f3ae3dd10b9c18f04de158b909f2886ef6dde4c9e01f83d92f33aa2027f825b718e2fe184ea2c952aeca33713") + + input, err := contractAbi.Pack(validateProofOfPossession, publicKey, proof) + if err != nil { + b.Fatalf("Failed to pack contract input, err %s", err) + } + + output, err := contractAbi.Methods[validateProofOfPossession].Outputs.Pack(true) + if err != nil { + b.Fatalf("Failed to pack contract output, err: %s", err) + } + + test := precompiledTest{ + Input: common.Bytes2Hex(input), + Expected: common.Bytes2Hex(output), + Name: "proof-of-possession", + } + + benchmarkPrecompiled("6a", test, b) +} diff --git a/core/vm/contracts_test.go b/core/vm/contracts_test.go index 73e1f7f2dd..dad72ac640 100644 --- a/core/vm/contracts_test.go +++ b/core/vm/contracts_test.go @@ -75,6 +75,7 @@ var allPrecompiles = map[common.Address]PrecompiledContract{ common.BytesToAddress([]byte{103}): &consortiumVerifyHeaders{test: true}, common.BytesToAddress([]byte{104}): &consortiumPickValidatorSet{}, common.BytesToAddress([]byte{105}): &consortiumValidateFinalityProof{}, + common.BytesToAddress([]byte{106}): &consortiumValidateProofOfPossession{}, } // EIP-152 test vectors diff --git a/core/vm/evm.go b/core/vm/evm.go index ae7074e68f..14ba321597 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -86,7 +86,13 @@ func (evm *EVM) precompile(caller ContractRef, addr common.Address) (Precompiled } // add consortium precompiled contracts to list - for address, contract := range PrecompiledContractsConsortium(caller, evm) { + var consortiumContracts map[common.Address]PrecompiledContract + if evm.chainRules.IsMiko { + consortiumContracts = PrecompiledContractsConsortiumMiko(caller, evm) + } else { + consortiumContracts = PrecompiledContractsConsortium(caller, evm) + } + for address, contract := range consortiumContracts { precompiles[address] = contract } diff --git a/crypto/bls/blst/secret_key.go b/crypto/bls/blst/secret_key.go index 498922d3a3..330a69a769 100644 --- a/crypto/bls/blst/secret_key.go +++ b/crypto/bls/blst/secret_key.go @@ -5,6 +5,7 @@ package blst import ( "crypto/subtle" "fmt" + "github.com/ethereum/go-ethereum/crypto/bls/common" "github.com/ethereum/go-ethereum/crypto/rand" "github.com/ethereum/go-ethereum/params" @@ -72,7 +73,13 @@ func IsZero(sKey []byte) bool { // In Ethereum proof of stake specification: // def Sign(SK: int, message: Bytes) -> BLSSignature func (s *bls12SecretKey) Sign(msg []byte) common.Signature { - signature := new(blstSignature).Sign(s.p, msg, dst) + signature := new(blstSignature).Sign(s.p, msg, sigDst) + return &Signature{s: signature} +} + +// SignProof is the same as Sign but use different domain separation tag +func (s *bls12SecretKey) SignProof(msg []byte) common.Signature { + signature := new(blstSignature).Sign(s.p, msg, pubDst) return &Signature{s: signature} } diff --git a/crypto/bls/blst/signature.go b/crypto/bls/blst/signature.go index 6467b065ab..85c0d11e01 100644 --- a/crypto/bls/blst/signature.go +++ b/crypto/bls/blst/signature.go @@ -5,16 +5,20 @@ package blst import ( "bytes" "fmt" - "github.com/ethereum/go-ethereum/params" "sync" + "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/crypto/bls/common" "github.com/ethereum/go-ethereum/crypto/rand" "github.com/pkg/errors" blst "github.com/supranational/blst/bindings/go" ) -var dst = []byte("BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_") +var ( + sigDst = []byte("BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_") + pubDst = []byte("BLS_POP_BLS12381G2_XMD:SHA-256_SSWU_RO_POP_") +) const scalarBytes = 32 const randBitsEntropy = 64 @@ -93,7 +97,13 @@ func MultipleSignaturesFromBytes(multiSigs [][]byte) ([]common.Signature, error) // def Verify(PK: BLSPubkey, message: Bytes, signature: BLSSignature) -> bool func (s *Signature) Verify(pubKey common.PublicKey, msg []byte) bool { // Signature and PKs are assumed to have been validated upon decompression! - return s.s.Verify(false, pubKey.(*PublicKey).p, false, msg, dst) + return s.s.Verify(false, pubKey.(*PublicKey).p, false, msg, sigDst) +} + +// VerifyProof is the same as Verify but use different domain separation tag +func (s *Signature) VerifyProof(pubKey common.PublicKey, msg []byte) bool { + // Signature and PKs are assumed to have been validated upon decompression! + return s.s.Verify(false, pubKey.(*PublicKey).p, false, msg, pubDst) } // AggregateVerify verifies each public key against its respective message. This is vulnerable to @@ -129,7 +139,7 @@ func (s *Signature) AggregateVerify(pubKeys []common.PublicKey, msgs [][32]byte) rawKeys[i] = pubKeys[i].(*PublicKey).p } // Signature and PKs are assumed to have been validated upon decompression! - return s.s.AggregateVerify(false, rawKeys, false, msgSlices, dst) + return s.s.AggregateVerify(false, rawKeys, false, msgSlices, sigDst) } // FastAggregateVerify verifies all the provided public keys with their aggregated signature. @@ -151,7 +161,7 @@ func (s *Signature) FastAggregateVerify(pubKeys []common.PublicKey, msg [32]byte for i := 0; i < len(pubKeys); i++ { rawKeys[i] = pubKeys[i].(*PublicKey).p } - return s.s.FastAggregateVerify(true, rawKeys, msg[:], dst) + return s.s.FastAggregateVerify(true, rawKeys, msg[:], sigDst) } // Eth2FastAggregateVerify implements a wrapper on top of bls's FastAggregateVerify. It accepts G2_POINT_AT_INFINITY signature @@ -175,7 +185,7 @@ func (s *Signature) Eth2FastAggregateVerify(pubKeys []common.PublicKey, msg [32] // NewAggregateSignature creates a blank aggregate signature. func NewAggregateSignature() common.Signature { - sig := blst.HashToG2([]byte{'m', 'o', 'c', 'k'}, dst).ToAffine() + sig := blst.HashToG2([]byte{'m', 'o', 'c', 'k'}, sigDst).ToAffine() return &Signature{s: sig} } @@ -247,7 +257,7 @@ func VerifyMultipleSignatures(sigs [][]byte, msgs [][32]byte, pubKeys []common.P dummySig := new(blstSignature) // Validate signatures since we uncompress them here. Public keys should already be validated. - return dummySig.MultipleAggregateVerify(rawSigs, true, mulP1Aff, false, rawMsgs, dst, randFunc, randBitsEntropy), nil + return dummySig.MultipleAggregateVerify(rawSigs, true, mulP1Aff, false, rawMsgs, sigDst, randFunc, randBitsEntropy), nil } // Marshal a signature into a LittleEndian byte slice. @@ -265,5 +275,5 @@ func (s *Signature) Copy() common.Signature { // are valid from the message provided. func VerifyCompressed(signature, pub, msg []byte) bool { // Validate signature and PKs since we will uncompress them here - return new(blstSignature).VerifyCompressed(signature, true, pub, true, msg, dst) + return new(blstSignature).VerifyCompressed(signature, true, pub, true, msg, sigDst) } diff --git a/crypto/bls/blst/signature_test.go b/crypto/bls/blst/signature_test.go index 39dbb63fa9..6d4762273a 100644 --- a/crypto/bls/blst/signature_test.go +++ b/crypto/bls/blst/signature_test.go @@ -5,9 +5,10 @@ package blst import ( "bytes" "errors" + "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "testing" "github.com/ethereum/go-ethereum/crypto/bls/common" ) @@ -291,7 +292,7 @@ func TestCopy(t *testing.T) { key, ok := priv.(*bls12SecretKey) require.Equal(t, true, ok) - signatureA := &Signature{s: new(blstSignature).Sign(key.p, []byte("foo"), dst)} + signatureA := &Signature{s: new(blstSignature).Sign(key.p, []byte("foo"), sigDst)} signatureB, ok := signatureA.Copy().(*Signature) require.Equal(t, true, ok) @@ -304,6 +305,6 @@ func TestCopy(t *testing.T) { } assert.Equal(t, signatureA, signatureB) - signatureA.s.Sign(key.p, []byte("bar"), dst) + signatureA.s.Sign(key.p, []byte("bar"), sigDst) assert.NotEqual(t, signatureA, signatureB) } diff --git a/crypto/bls/common/interface.go b/crypto/bls/common/interface.go index db2c770111..b542f7195b 100644 --- a/crypto/bls/common/interface.go +++ b/crypto/bls/common/interface.go @@ -9,6 +9,7 @@ package common type SecretKey interface { PublicKey() PublicKey Sign(msg []byte) Signature + SignProof(msg []byte) Signature Marshal() []byte } @@ -24,6 +25,7 @@ type PublicKey interface { // Signature represents a BLS signature. type Signature interface { Verify(pubKey PublicKey, msg []byte) bool + VerifyProof(pubKey PublicKey, msg []byte) bool // Deprecated: Use FastAggregateVerify or use this method in spectests only. AggregateVerify(pubKeys []PublicKey, msgs [][32]byte) bool FastAggregateVerify(pubKeys []PublicKey, msg [32]byte) bool diff --git a/params/protocol_params.go b/params/protocol_params.go index 8c2574bb07..5ca54c3db6 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -158,6 +158,7 @@ const ( ValidatorSortingBaseGas uint64 = 30 // Base gas for validator sorting and picking validator set VerifyFinalityHeadersProofGas uint64 = EcrecoverGas*2 + 15000 // Gas for verifying finality headers proof ValidateFinalityProofGas uint64 = 200000 // Gas for validating finality proof + ValidateProofOfPossession uint64 = 100000 // Gas for validating proof of possession // The Refund Quotient is the cap on how much of the used gas can be refunded. Before EIP-3529, // up to half the consumed gas could be refunded. Redefined as 1/5th in EIP-3529 From 8dab0efcdd177fe78005233493f99e4628cbb4b1 Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Mon, 6 Nov 2023 13:56:23 +0700 Subject: [PATCH 02/10] cmd, entrypoint: add an account cmd to generate BLS proof of possession --- Dockerfile | 1 + cmd/ronin/accountcmd.go | 57 +++++++++++++++++++++++++++++++++- docker/chainnode/entrypoint.sh | 6 ++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 065157f8b5..83ccefdeb4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -29,6 +29,7 @@ ENV BLS_PRIVATE_KEY '' ENV BLS_PASSWORD '' ENV BLS_AUTO_GENERATE 'false' ENV BLS_SHOW_PRIVATE_KEY 'false' +ENV GENERATE_BLS_PROOF 'false' COPY --from=builder /opt/build/bin/ronin /usr/local/bin/ronin COPY --from=builder /opt/genesis/ ./ diff --git a/cmd/ronin/accountcmd.go b/cmd/ronin/accountcmd.go index 0787043d78..f3130f84e5 100644 --- a/cmd/ronin/accountcmd.go +++ b/cmd/ronin/accountcmd.go @@ -260,6 +260,24 @@ The keyfile is assumed to contain an unencrypted private key in hexadecimal form }, Description: `ronin account generatebls [--secret]`, }, + { + Name: "generate-bls-proof", + Usage: "Generate BLS proof of possession", + Action: utils.MigrateFlags(blsProofGenerate), + Flags: []cli.Flag{ + utils.BlsWalletPath, + utils.BlsPasswordPath, + }, + ArgsUsage: "[keyFile]", + Description: ` + ronin account generate-bls-proof [keyFile] [--finality.blswalletpath walletpath] [--finality.blspasswordpath passwordpath] + +Generate proof from keyfile or stored encrypted wallet + +The keyfile is assumed to contain an unencrypted private key in hexadecimal format. +You must input either keyfile or a pair of walletpath and passwordpath. +`, + }, }, } ) @@ -490,7 +508,7 @@ func loadKeyManager(ctx *cli.Context) (*bls.KeyManager, []blsCommon.PublicKey, e func loadBlsSecretKey(ctx *cli.Context) (blsCommon.SecretKey, error) { keyfile := ctx.Args().First() if len(keyfile) == 0 { - utils.Fatalf("keyfile must be given as argument") + return nil, fmt.Errorf("keyfile must be given as argument") } secretKeyHex, err := ioutil.ReadFile(keyfile) @@ -627,3 +645,40 @@ func blsAccountGenerate(ctx *cli.Context) error { return nil } + +func blsProofGenerate(ctx *cli.Context) error { + var ( + keyManager *bls.KeyManager + secretKeys []blsCommon.SecretKey + ) + + secretKey, err := loadBlsSecretKey(ctx) + if err != nil { + keyManager, _, err = loadKeyManager(ctx) + if err != nil { + utils.Fatalf("Either keyfile or path to wallet must be provided, err: %s", err) + } + rawSecretKeys, err := keyManager.FetchValidatingSecretKeys(context.Background()) + if err != nil { + utils.Fatalf("Failed to fetch BLS secret key, err %s", err) + } + for _, rawSecretKey := range rawSecretKeys { + secretKey, err := blst.SecretKeyFromBytes(rawSecretKey[:]) + if err != nil { + utils.Fatalf("Failed to decode BLS secret key, err %s", err) + } + secretKeys = append(secretKeys, secretKey) + } + } else { + secretKeys = append(secretKeys, secretKey) + } + + for i, secretKey := range secretKeys { + rawPublicKey := secretKey.PublicKey().Marshal() + proof := secretKey.SignProof(rawPublicKey) + fmt.Printf("BLS public key #%d: {%x}\n", i, rawPublicKey) + fmt.Printf("BLS proof #%d: {%x}\n", i, proof.Marshal()) + } + + return nil +} diff --git a/docker/chainnode/entrypoint.sh b/docker/chainnode/entrypoint.sh index 8290838e7f..40f7d878f5 100755 --- a/docker/chainnode/entrypoint.sh +++ b/docker/chainnode/entrypoint.sh @@ -210,6 +210,12 @@ if [[ "$ENABLE_FAST_FINALITY_SIGN" = "true" ]]; then echo "Using BLS account $blsAccount" fi +if [[ "$GENERATE_BLS_PROOF" = "true" ]]; then + ronin account generate-bls-proof \ + --finality.blspasswordpath $BLS_PASSWORD_FILE \ + --finality.blswalletpath $BLS_PRIVATE_KEY_DIR +fi + # bootnodes if [[ ! -z $BOOTNODES ]]; then params="$params --bootnodes $BOOTNODES" From 6e24e96aef7b8c6bd4b443cbdedeb88b38d6e658 Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Tue, 28 Nov 2023 14:32:20 +0700 Subject: [PATCH 03/10] consortium/v2: upgrade ronin trusted org contract --- consensus/consortium/v2/consortium.go | 17 +++ consensus/consortium/v2/consortium_test.go | 124 +++++++++++++++++++++ genesis/mainnet.json | 6 +- genesis/testnet.json | 6 +- params/config.go | 82 ++++++++------ 5 files changed, 202 insertions(+), 33 deletions(-) diff --git a/consensus/consortium/v2/consortium.go b/consensus/consortium/v2/consortium.go index eb7588280b..0b91785870 100644 --- a/consensus/consortium/v2/consortium.go +++ b/consensus/consortium/v2/consortium.go @@ -58,6 +58,10 @@ var ( diffInTurn = big.NewInt(7) // Block difficulty for in-turn signatures diffNoTurn = big.NewInt(3) // Block difficulty for out-of-turn signatures + + // The proxy contract's implementation slot + // https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/v4.7.3/contracts/proxy/ERC1967/ERC1967UpgradeUpgradeable.sol#L34 + implementationSlot = common.HexToHash("360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc") ) var ( @@ -840,6 +844,17 @@ func (c *Consortium) processSystemTransactions(chain consensus.ChainHeaderReader return nil } +func (c *Consortium) upgradeRoninTrustedOrg(blockNumber *big.Int, state *state.StateDB) { + // The upgrade only happens in 1 block: Miko hardfork block + if c.chainConfig.MikoBlock != nil && c.chainConfig.MikoBlock.Cmp(blockNumber) == 0 { + state.SetState( + c.chainConfig.RoninTrustedOrgUpgrade.ProxyAddress, + implementationSlot, + c.chainConfig.RoninTrustedOrgUpgrade.ImplementationAddress.Hash(), + ) + } +} + // Finalize implements consensus.Engine that calls three methods from smart contracts: // - WrapUpEpoch at epoch to distribute rewards and sort the validators set // - Slash the validator who does not sign if it is in-turn @@ -901,6 +916,7 @@ func (c *Consortium) Finalize(chain consensus.ChainHeaderReader, header *types.H if err := c.processSystemTransactions(chain, header, transactOpts, false); err != nil { return err } + c.upgradeRoninTrustedOrg(header.Number, state) if len(*transactOpts.EVMContext.InternalTransactions) > 0 { *internalTxs = append(*internalTxs, *transactOpts.EVMContext.InternalTransactions...) } @@ -946,6 +962,7 @@ func (c *Consortium) FinalizeAndAssemble(chain consensus.ChainHeaderReader, head if err := c.processSystemTransactions(chain, header, transactOpts, true); err != nil { return nil, nil, err } + c.upgradeRoninTrustedOrg(header.Number, state) // should not happen. Once happen, stop the node is better than broadcast the block if header.GasLimit < header.GasUsed { diff --git a/consensus/consortium/v2/consortium_test.go b/consensus/consortium/v2/consortium_test.go index f2a6612d14..72c190ec43 100644 --- a/consensus/consortium/v2/consortium_test.go +++ b/consensus/consortium/v2/consortium_test.go @@ -1237,3 +1237,127 @@ func TestKnownBlockReorg(t *testing.T) { t.Fatalf("Expect head header to have difficulty %d, got %d", 3, header.Difficulty.Uint64()) } } + +func TestUpgradeRoninTrustedOrg(t *testing.T) { + db := rawdb.NewMemoryDatabase() + blsSecretKey, err := blst.RandKey() + if err != nil { + t.Fatal(err) + } + secretKey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + validatorAddr := crypto.PubkeyToAddress(secretKey.PublicKey) + + chainConfig := params.ChainConfig{ + ChainID: big.NewInt(2021), + HomesteadBlock: common.Big0, + EIP150Block: common.Big0, + EIP155Block: common.Big0, + EIP158Block: common.Big0, + ConsortiumV2Block: common.Big0, + MikoBlock: common.Big3, + Consortium: ¶ms.ConsortiumConfig{ + EpochV2: 200, + }, + RoninTrustedOrgUpgrade: ¶ms.ContractUpgrade{ + ProxyAddress: common.Address{0x10}, + ImplementationAddress: common.Address{0x20}, + }, + } + + genesis := (&core.Genesis{ + Config: &chainConfig, + Alloc: core.GenesisAlloc{ + // Make proxy address non-empty to avoid being deleted + common.Address{0x10}: core.GenesisAccount{Balance: common.Big1}, + }, + }).MustCommit(db) + + mock := &mockContract{ + validators: map[common.Address]blsCommon.PublicKey{ + validatorAddr: blsSecretKey.PublicKey(), + }, + } + recents, _ := lru.NewARC(inmemorySnapshots) + signatures, _ := lru.NewARC(inmemorySignatures) + + v2 := Consortium{ + chainConfig: &chainConfig, + contract: mock, + recents: recents, + signatures: signatures, + config: ¶ms.ConsortiumConfig{ + EpochV2: 200, + }, + } + + chain, _ := core.NewBlockChain(db, nil, &chainConfig, &v2, vm.Config{}, nil, nil) + extraData := [consortiumCommon.ExtraVanity + consortiumCommon.ExtraSeal]byte{} + + parent := genesis + for i := 0; i < 5; i++ { + block, _ := core.GenerateChain( + &chainConfig, + parent, + &v2, + db, + 1, + func(i int, bg *core.BlockGen) { + bg.SetCoinbase(validatorAddr) + bg.SetExtra(extraData[:]) + bg.SetDifficulty(big.NewInt(7)) + }, + true, + ) + + header := block[0].Header() + hash := calculateSealHash(header, big.NewInt(2021)) + sig, err := crypto.Sign(hash[:], secretKey) + if err != nil { + t.Fatalf("Failed to sign block, err %s", err) + } + + copy(header.Extra[len(header.Extra)-consortiumCommon.ExtraSeal:], sig) + block[0] = block[0].WithSeal(header) + parent = block[0] + + if i == int(chainConfig.MikoBlock.Int64()-1) { + statedb, err := chain.State() + if err != nil { + t.Fatalf("Failed to get statedb, err %s", err) + } + + implementationAddr := statedb.GetState(v2.chainConfig.RoninTrustedOrgUpgrade.ProxyAddress, implementationSlot) + if implementationAddr != (common.Hash{}) { + t.Fatalf( + "Implementation slot mismatches, exp: {%x} got {%x}", + common.Hash{}, + implementationAddr, + ) + } + } + + _, err = chain.InsertChain(block) + if err != nil { + t.Fatalf("Failed to insert chain, err %s", err) + } + + if i == int(chainConfig.MikoBlock.Int64()-1) { + statedb, err := chain.State() + if err != nil { + t.Fatalf("Failed to get statedb, err %s", err) + } + + implementationAddr := statedb.GetState(v2.chainConfig.RoninTrustedOrgUpgrade.ProxyAddress, implementationSlot) + if implementationAddr != v2.chainConfig.RoninTrustedOrgUpgrade.ImplementationAddress.Hash() { + t.Fatalf( + "Implementation slot mismatches, exp: {%x} got {%x}", + v2.chainConfig.RoninTrustedOrgUpgrade.ImplementationAddress.Hash(), + implementationAddr, + ) + } + } + } +} diff --git a/genesis/mainnet.json b/genesis/mainnet.json index af7a471bca..a316f0de5f 100644 --- a/genesis/mainnet.json +++ b/genesis/mainnet.json @@ -31,7 +31,11 @@ "olekBlock": 24935500, "shillinBlock": 28825400, "antennaBlock": 28825400, - "whiteListDeployerContractV2Address": "0xc1876d5C4BFAF0eE325E4226B2bdf216D9896AE1" + "whiteListDeployerContractV2Address": "0xc1876d5C4BFAF0eE325E4226B2bdf216D9896AE1", + "roninTrustedOrgUpgrade": { + "proxyAddress": "0x98D0230884448B3E2f09a177433D60fb1E19C090", + "implementationAddress": "" + } }, "alloc": { "0x0000000000000000000000000000000000000011": { diff --git a/genesis/testnet.json b/genesis/testnet.json index 66e88bee80..e08e07bd1f 100644 --- a/genesis/testnet.json +++ b/genesis/testnet.json @@ -31,7 +31,11 @@ "olekBlock": 16849000, "shillinBlock": 20268000, "antennaBlock": 20737258, - "whiteListDeployerContractV2Address": "0x50a7e07Aa75eB9C04281713224f50403cA79851F" + "whiteListDeployerContractV2Address": "0x50a7e07Aa75eB9C04281713224f50403cA79851F", + "roninTrustedOrgUpgrade": { + "proxyAddress": "0x7507dc433a98E1fE105d69f19f3B40E4315A4F32", + "implementationAddress": "" + } }, "alloc": { "0x0000000000000000000000000000000000000011": { diff --git a/params/config.go b/params/config.go index 89ab5c8cc9..086d9d4639 100644 --- a/params/config.go +++ b/params/config.go @@ -240,26 +240,30 @@ var ( }, } - RoninMainnetBlacklistContract = common.HexToAddress("0x313b24994c93FA0471CB4D7aB796b07467041806") - RoninMainnetFenixValidatorContractAddress = common.HexToAddress("0x7f13232Bdc3a010c3f749a1c25bF99f1C053CE70") - RoninMainnetRoninValidatorSetAddress = common.HexToAddress("0x617c5d73662282EA7FfD231E020eCa6D2B0D552f") - RoninMainnetSlashIndicatorAddress = common.HexToAddress("0xEBFFF2b32fA0dF9C5C8C5d5AAa7e8b51d5207bA3") - RoninMainnetStakingContractAddress = common.HexToAddress("0x545edb750eB8769C868429BE9586F5857A768758") + RoninMainnetBlacklistContract = common.HexToAddress("0x313b24994c93FA0471CB4D7aB796b07467041806") + RoninMainnetFenixValidatorContractAddress = common.HexToAddress("0x7f13232Bdc3a010c3f749a1c25bF99f1C053CE70") + RoninMainnetRoninValidatorSetAddress = common.HexToAddress("0x617c5d73662282EA7FfD231E020eCa6D2B0D552f") + RoninMainnetSlashIndicatorAddress = common.HexToAddress("0xEBFFF2b32fA0dF9C5C8C5d5AAa7e8b51d5207bA3") + RoninMainnetStakingContractAddress = common.HexToAddress("0x545edb750eB8769C868429BE9586F5857A768758") + RoninMainnetProfileContractAddress = common.HexToAddress("0x840EBf1CA767CB690029E91856A357a43B85d035") + RoninMainnetFinalityTrackingAddress = common.HexToAddress("0xA30B2932CD8b8A89E34551Cdfa13810af38dA576") + RoninMainnetWhiteListDeployerContractV2Address = common.HexToAddress("0xc1876d5C4BFAF0eE325E4226B2bdf216D9896AE1") RoninMainnetChainConfig = &ChainConfig{ - ChainID: big.NewInt(2020), - HomesteadBlock: big.NewInt(0), - EIP150Block: big.NewInt(0), - EIP155Block: big.NewInt(0), - EIP158Block: big.NewInt(0), - ByzantiumBlock: big.NewInt(0), - ConstantinopleBlock: big.NewInt(0), - PetersburgBlock: big.NewInt(0), - IstanbulBlock: big.NewInt(4977778), - OdysseusBlock: big.NewInt(10301597), - FenixBlock: big.NewInt(14938103), - BlacklistContractAddress: &RoninMainnetBlacklistContract, - FenixValidatorContractAddress: &RoninMainnetFenixValidatorContractAddress, + ChainID: big.NewInt(2020), + HomesteadBlock: big.NewInt(0), + EIP150Block: big.NewInt(0), + EIP155Block: big.NewInt(0), + EIP158Block: big.NewInt(0), + ByzantiumBlock: big.NewInt(0), + ConstantinopleBlock: big.NewInt(0), + PetersburgBlock: big.NewInt(0), + IstanbulBlock: big.NewInt(4977778), + OdysseusBlock: big.NewInt(10301597), + FenixBlock: big.NewInt(14938103), + BlacklistContractAddress: &RoninMainnetBlacklistContract, + FenixValidatorContractAddress: &RoninMainnetFenixValidatorContractAddress, + WhiteListDeployerContractV2Address: &RoninMainnetWhiteListDeployerContractV2Address, Consortium: &ConsortiumConfig{ Period: 3, Epoch: 600, @@ -269,6 +273,8 @@ var ( RoninValidatorSet: RoninMainnetRoninValidatorSetAddress, SlashIndicator: RoninMainnetSlashIndicatorAddress, StakingContract: RoninMainnetStakingContractAddress, + ProfileContract: RoninMainnetProfileContractAddress, + FinalityTracking: RoninMainnetFinalityTrackingAddress, }, ConsortiumV2Block: big.NewInt(23155200), PuffyBlock: big.NewInt(0), @@ -278,16 +284,20 @@ var ( AntennaBlock: big.NewInt(28825400), // TODO: Fill this MikoBlock: nil, + RoninTrustedOrgUpgrade: &ContractUpgrade{ + ProxyAddress: common.HexToAddress("0x98D0230884448B3E2f09a177433D60fb1E19C090"), + ImplementationAddress: common.HexToAddress(""), + }, } - RoninTestnetBlacklistContract = common.HexToAddress("0xF53EED5210c9cF308abFe66bA7CF14884c95A8aC") - RoninTestnetFenixValidatorContractAddress = common.HexToAddress("0x1454cAAd1637b662432Bb795cD5773d21281eDAb") - RoninTestnetRoninValidatorSetAddress = common.HexToAddress("0x54B3AC74a90E64E8dDE60671b6fE8F8DDf18eC9d") - RoninTestnetSlashIndicatorAddress = common.HexToAddress("0xF7837778b6E180Df6696C8Fa986d62f8b6186752") - RoninTestnetStakingContractAddress = common.HexToAddress("0x9C245671791834daf3885533D24dce516B763B28") - RoninTestnetProfileContractAddress = common.HexToAddress("0x3b67c8D22a91572a6AB18acC9F70787Af04A4043") - RoninTestnetFinalityTrackingAddress = common.HexToAddress("0x41aCDFe786171824a037f2Cd6224c5916A58969a") - RoninWhiteListDeployerContractV2Address = common.HexToAddress("0x50a7e07Aa75eB9C04281713224f50403cA79851F") + RoninTestnetBlacklistContract = common.HexToAddress("0xF53EED5210c9cF308abFe66bA7CF14884c95A8aC") + RoninTestnetFenixValidatorContractAddress = common.HexToAddress("0x1454cAAd1637b662432Bb795cD5773d21281eDAb") + RoninTestnetRoninValidatorSetAddress = common.HexToAddress("0x54B3AC74a90E64E8dDE60671b6fE8F8DDf18eC9d") + RoninTestnetSlashIndicatorAddress = common.HexToAddress("0xF7837778b6E180Df6696C8Fa986d62f8b6186752") + RoninTestnetStakingContractAddress = common.HexToAddress("0x9C245671791834daf3885533D24dce516B763B28") + RoninTestnetProfileContractAddress = common.HexToAddress("0x3b67c8D22a91572a6AB18acC9F70787Af04A4043") + RoninTestnetFinalityTrackingAddress = common.HexToAddress("0x41aCDFe786171824a037f2Cd6224c5916A58969a") + RoninTestnetWhiteListDeployerContractV2Address = common.HexToAddress("0x50a7e07Aa75eB9C04281713224f50403cA79851F") RoninTestnetChainConfig = &ChainConfig{ ChainID: big.NewInt(2021), @@ -303,7 +313,7 @@ var ( FenixBlock: big.NewInt(6770400), BlacklistContractAddress: &RoninTestnetBlacklistContract, FenixValidatorContractAddress: &RoninTestnetFenixValidatorContractAddress, - WhiteListDeployerContractV2Address: &RoninWhiteListDeployerContractV2Address, + WhiteListDeployerContractV2Address: &RoninTestnetWhiteListDeployerContractV2Address, Consortium: &ConsortiumConfig{ Period: 3, Epoch: 30, @@ -324,6 +334,10 @@ var ( AntennaBlock: big.NewInt(20737258), // TODO: Fill this MikoBlock: nil, + RoninTrustedOrgUpgrade: &ContractUpgrade{ + ProxyAddress: common.HexToAddress("0x7507dc433a98E1fE105d69f19f3B40E4315A4F32"), + ImplementationAddress: common.HexToAddress(""), + }, } // GoerliTrustedCheckpoint contains the light client trusted checkpoint for the Görli test network. @@ -552,10 +566,16 @@ type ChainConfig struct { TerminalTotalDifficulty *big.Int `json:"terminalTotalDifficulty,omitempty"` // Various consensus engines - Ethash *EthashConfig `json:"ethash,omitempty"` - Clique *CliqueConfig `json:"clique,omitempty"` - Consortium *ConsortiumConfig `json:"consortium,omitempty"` - ConsortiumV2Contracts *ConsortiumV2Contracts `json:"consortiumV2Contracts"` + Ethash *EthashConfig `json:"ethash,omitempty"` + Clique *CliqueConfig `json:"clique,omitempty"` + Consortium *ConsortiumConfig `json:"consortium,omitempty"` + ConsortiumV2Contracts *ConsortiumV2Contracts `json:"consortiumV2Contracts"` + RoninTrustedOrgUpgrade *ContractUpgrade `json:"roninTrustedOrgUpgrade"` +} + +type ContractUpgrade struct { + ProxyAddress common.Address `json:"proxyAddress"` + ImplementationAddress common.Address `json:"implementationAddress"` } // EthashConfig is the consensus engine configs for proof-of-work based sealing. From 71c15514f794e7d075bc7dbfa8ee1d32110d9116 Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Wed, 3 Jan 2024 11:42:34 +0700 Subject: [PATCH 04/10] genesis/testnet: add Miko hardfork on testnet --- genesis/testnet.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/genesis/testnet.json b/genesis/testnet.json index e08e07bd1f..7b5ff3c7e4 100644 --- a/genesis/testnet.json +++ b/genesis/testnet.json @@ -31,10 +31,11 @@ "olekBlock": 16849000, "shillinBlock": 20268000, "antennaBlock": 20737258, + "mikoBlock": 23694400, "whiteListDeployerContractV2Address": "0x50a7e07Aa75eB9C04281713224f50403cA79851F", "roninTrustedOrgUpgrade": { "proxyAddress": "0x7507dc433a98E1fE105d69f19f3B40E4315A4F32", - "implementationAddress": "" + "implementationAddress": "0x6A51C2B073a6daDBeCAC1A420AFcA7788C81612f" } }, "alloc": { From 0fb4cd83000c4da9366482c65afa079b68f3d2c5 Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Wed, 3 Jan 2024 14:48:55 +0700 Subject: [PATCH 05/10] params/version: bump Ronin to version 2.7.0 --- params/version.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/params/version.go b/params/version.go index 8d44b19d40..be57ca9c7e 100644 --- a/params/version.go +++ b/params/version.go @@ -22,8 +22,8 @@ import ( const ( VersionMajor = 2 // Major version component of the current release - VersionMinor = 6 // Minor version component of the current release - VersionPatch = 2 // Patch version component of the current release + VersionMinor = 7 // Minor version component of the current release + VersionPatch = 0 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) From b53b48e03f4b8638385de75ed73c2da0f7e3b01e Mon Sep 17 00:00:00 2001 From: NganSM Date: Fri, 12 Jan 2024 17:39:10 +0700 Subject: [PATCH 06/10] state_processor: fix out-of-order system txs The current way that transactions are processed by Consortium V2 engine allows a system transaction to be placed before a common transaction in a block. However, the generated logs and receipts are ordered so that those of system transactions are stored at the end (see `core/state_processor.go/Process`). This leads to mismatching betwwen logs/receipts and their corresponding transactions because the handler of `eth_getLogs` assume that receipts are stored in the same order with that of `block.Transactions()` (see `core/rawdb/accessors_chain.go/deriveLogFields`). --- core/error.go | 2 ++ core/state_processor.go | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/core/error.go b/core/error.go index 2c68fb0a41..bd8ac96671 100644 --- a/core/error.go +++ b/core/error.go @@ -33,6 +33,8 @@ var ( ErrNoGenesis = errors.New("genesis not found in chain") errSideChainReceipts = errors.New("side blocks can't be accepted as ancient chain data") + + ErrOutOfOrderSystemTx = errors.New("out-of-order system transaction detected") ) // List of evm-call-message pre-checking errors. All state transition messages will diff --git a/core/state_processor.go b/core/state_processor.go index 5465ee293d..6153ab1017 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -91,14 +91,23 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg defer bloomProcessors.Close() // Iterate over and process the individual transactions + // System transactions should be placed at the end of a block + isSystemTxsSection := false + for i, tx := range block.Transactions() { if isPoSA { if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil { return nil, nil, nil, 0, err } else if isSystemTx { + isSystemTxsSection = true systemTxs = append(systemTxs, tx) continue } + + // Common tx cannot appear after a system tx + if isSystemTxsSection { + return nil, nil, nil, 0, ErrOutOfOrderSystemTx + } } // set current transaction in block context to each transaction From b530997822e6c4bcc32255a1ff1fae94ff428eb5 Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Mon, 15 Jan 2024 11:43:11 +0700 Subject: [PATCH 07/10] state_processor, consortium-v2: test out of order system transactions --- consensus/consortium/v2/consortium_test.go | 152 +++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/consensus/consortium/v2/consortium_test.go b/consensus/consortium/v2/consortium_test.go index 72c190ec43..59c10c0c87 100644 --- a/consensus/consortium/v2/consortium_test.go +++ b/consensus/consortium/v2/consortium_test.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/crypto/bls/blst" blsCommon "github.com/ethereum/go-ethereum/crypto/bls/common" "github.com/ethereum/go-ethereum/params" + "github.com/ethereum/go-ethereum/trie" lru "github.com/hashicorp/golang-lru" ) @@ -681,18 +682,30 @@ type mockContract struct { } func (contract *mockContract) WrapUpEpoch(opts *consortiumCommon.ApplyTransactOpts) error { + if opts.ReceivedTxs != nil && len(*opts.ReceivedTxs) != 0 { + *opts.ReceivedTxs = (*opts.ReceivedTxs)[1:] + } return nil } func (contract *mockContract) SubmitBlockReward(opts *consortiumCommon.ApplyTransactOpts) error { + if opts.ReceivedTxs != nil && len(*opts.ReceivedTxs) != 0 { + *opts.ReceivedTxs = (*opts.ReceivedTxs)[1:] + } return nil } func (contract *mockContract) Slash(opts *consortiumCommon.ApplyTransactOpts, spoiledValidator common.Address) error { + if opts.ReceivedTxs != nil && len(*opts.ReceivedTxs) != 0 { + *opts.ReceivedTxs = (*opts.ReceivedTxs)[1:] + } return nil } func (contract *mockContract) FinalityReward(opts *consortiumCommon.ApplyTransactOpts, votedValidators []common.Address) error { + if opts.ReceivedTxs != nil && len(*opts.ReceivedTxs) != 0 { + *opts.ReceivedTxs = (*opts.ReceivedTxs)[1:] + } return nil } @@ -1361,3 +1374,142 @@ func TestUpgradeRoninTrustedOrg(t *testing.T) { } } } + +func TestSystemTransactionOrder(t *testing.T) { + db := rawdb.NewMemoryDatabase() + blsSecretKey, err := blst.RandKey() + if err != nil { + t.Fatal(err) + } + secretKey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + validatorAddr := crypto.PubkeyToAddress(secretKey.PublicKey) + + userKey, err := crypto.GenerateKey() + if err != nil { + t.Fatal(err) + } + + chainConfig := params.ChainConfig{ + ChainID: big.NewInt(2021), + HomesteadBlock: common.Big0, + EIP150Block: common.Big0, + EIP155Block: common.Big0, + EIP158Block: common.Big0, + ConsortiumV2Block: common.Big0, + MikoBlock: common.Big0, + Consortium: ¶ms.ConsortiumConfig{ + EpochV2: 200, + }, + ConsortiumV2Contracts: ¶ms.ConsortiumV2Contracts{ + RoninValidatorSet: common.HexToAddress("0xaa"), + }, + } + + genesis := (&core.Genesis{ + Config: &chainConfig, + Alloc: core.GenesisAlloc{ + // Make proxy address non-empty to avoid being deleted + common.Address{0x10}: core.GenesisAccount{Balance: common.Big1}, + }, + }).MustCommit(db) + + mock := &mockContract{ + validators: map[common.Address]blsCommon.PublicKey{ + validatorAddr: blsSecretKey.PublicKey(), + }, + } + recents, _ := lru.NewARC(inmemorySnapshots) + signatures, _ := lru.NewARC(inmemorySignatures) + + v2 := Consortium{ + chainConfig: &chainConfig, + contract: mock, + recents: recents, + signatures: signatures, + config: ¶ms.ConsortiumConfig{ + EpochV2: 200, + }, + } + + chain, _ := core.NewBlockChain(db, nil, &chainConfig, &v2, vm.Config{}, nil, nil) + extraData := [consortiumCommon.ExtraVanity + consortiumCommon.ExtraSeal]byte{} + + signer := types.NewEIP155Signer(big.NewInt(2021)) + normalTx, err := types.SignTx( + types.NewTransaction( + 0, + common.Address{}, + new(big.Int), + 21000, + new(big.Int), + nil, + ), + signer, + userKey, + ) + if err != nil { + t.Fatalf("Failed to sign transaction, err %s", err) + } + + systemTx, err := types.SignTx( + types.NewTransaction( + 0, + chainConfig.ConsortiumV2Contracts.RoninValidatorSet, + new(big.Int), + 21000, + new(big.Int), + nil, + ), + signer, + secretKey, + ) + if err != nil { + t.Fatalf("Failed to sign transaction, err %s", err) + } + + blocks, receipts := core.GenerateConsortiumChain( + &chainConfig, + genesis, + &v2, + db, + 1, + func(i int, bg *core.BlockGen) { + bg.SetCoinbase(validatorAddr) + bg.SetExtra(extraData[:]) + bg.SetDifficulty(big.NewInt(7)) + bg.AddTx(normalTx) + }, + true, + func(i int, bg *core.BlockGen) { + header := bg.Header() + hash := calculateSealHash(header, big.NewInt(2021)) + sig, err := crypto.Sign(hash[:], secretKey) + if err != nil { + t.Fatalf("Failed to sign block, err %s", err) + } + copy(header.Extra[len(header.Extra)-consortiumCommon.ExtraSeal:], sig) + bg.SetExtra(header.Extra) + }, + ) + + // Mock contract does not create system transaction so right now len(block.transactions) == 1. + // Add the system transaction before normal transaction. + block := types.NewBlock(blocks[0].Header(), []*types.Transaction{systemTx, normalTx}, nil, receipts[0], trie.NewStackTrie(nil)) + header := block.Header() + hash := calculateSealHash(header, big.NewInt(2021)) + sig, err := crypto.Sign(hash[:], secretKey) + if err != nil { + t.Fatalf("Failed to sign block, err %s", err) + } + copy(header.Extra[len(header.Extra)-consortiumCommon.ExtraSeal:], sig) + block = types.NewBlockWithHeader(header) + block = types.NewBlock(block.Header(), []*types.Transaction{systemTx, normalTx}, nil, receipts[0], trie.NewStackTrie(nil)) + + _, err = chain.InsertChain(types.Blocks{block}) + if !errors.Is(err, core.ErrOutOfOrderSystemTx) { + t.Fatalf("Expected err: %s, got %s", core.ErrOutOfOrderSystemTx, err) + } +} From 55faa7d4926114549a9fab9c8289d576b1f485ba Mon Sep 17 00:00:00 2001 From: NganSM Date: Fri, 2 Feb 2024 14:53:53 +0700 Subject: [PATCH 08/10] state_processor: adjust out-of-order tx check The check for out-of-order transactions is applied to Miko blocks only. --- core/state_processor.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/state_processor.go b/core/state_processor.go index 6153ab1017..fdd94bc882 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -92,6 +92,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Iterate over and process the individual transactions // System transactions should be placed at the end of a block + isMiko := p.config.IsMiko(blockNumber) isSystemTxsSection := false for i, tx := range block.Transactions() { @@ -105,7 +106,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } // Common tx cannot appear after a system tx - if isSystemTxsSection { + if isMiko && isSystemTxsSection { return nil, nil, nil, 0, ErrOutOfOrderSystemTx } } From 9d851ea06dc57414c275c0cb4828e9fd688b1467 Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Wed, 7 Feb 2024 11:50:28 +0700 Subject: [PATCH 09/10] genesis, params: add Miko hardfork on mainnet --- genesis/mainnet.json | 3 ++- params/config.go | 10 ++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/genesis/mainnet.json b/genesis/mainnet.json index a316f0de5f..8d7060a9e6 100644 --- a/genesis/mainnet.json +++ b/genesis/mainnet.json @@ -31,10 +31,11 @@ "olekBlock": 24935500, "shillinBlock": 28825400, "antennaBlock": 28825400, + "mikoBlock": 32367400, "whiteListDeployerContractV2Address": "0xc1876d5C4BFAF0eE325E4226B2bdf216D9896AE1", "roninTrustedOrgUpgrade": { "proxyAddress": "0x98D0230884448B3E2f09a177433D60fb1E19C090", - "implementationAddress": "" + "implementationAddress": "0x59646258Ec25CC329f5ce93223e0A50ccfA3e885" } }, "alloc": { diff --git a/params/config.go b/params/config.go index 086d9d4639..d955ce65ad 100644 --- a/params/config.go +++ b/params/config.go @@ -282,11 +282,10 @@ var ( OlekBlock: big.NewInt(24935500), ShillinBlock: big.NewInt(28825400), AntennaBlock: big.NewInt(28825400), - // TODO: Fill this - MikoBlock: nil, + MikoBlock: big.NewInt(32367400), RoninTrustedOrgUpgrade: &ContractUpgrade{ ProxyAddress: common.HexToAddress("0x98D0230884448B3E2f09a177433D60fb1E19C090"), - ImplementationAddress: common.HexToAddress(""), + ImplementationAddress: common.HexToAddress("0x59646258Ec25CC329f5ce93223e0A50ccfA3e885"), }, } @@ -332,11 +331,10 @@ var ( OlekBlock: big.NewInt(16849000), ShillinBlock: big.NewInt(20268000), AntennaBlock: big.NewInt(20737258), - // TODO: Fill this - MikoBlock: nil, + MikoBlock: big.NewInt(23694400), RoninTrustedOrgUpgrade: &ContractUpgrade{ ProxyAddress: common.HexToAddress("0x7507dc433a98E1fE105d69f19f3B40E4315A4F32"), - ImplementationAddress: common.HexToAddress(""), + ImplementationAddress: common.HexToAddress("0x6A51C2B073a6daDBeCAC1A420AFcA7788C81612f"), }, } From 02f176e877b2fcb5ab83573202aae69e8ea3fb73 Mon Sep 17 00:00:00 2001 From: Bui Quang Minh Date: Wed, 7 Feb 2024 11:52:15 +0700 Subject: [PATCH 10/10] params/version: bump Ronin to version 2.7.1 --- params/version.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/params/version.go b/params/version.go index be57ca9c7e..2512352166 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 2 // Major version component of the current release VersionMinor = 7 // Minor version component of the current release - VersionPatch = 0 // Patch version component of the current release + VersionPatch = 1 // Patch version component of the current release VersionMeta = "" // Version metadata to append to the version string ) @@ -43,7 +43,8 @@ var VersionWithMeta = func() string { // ArchiveVersion holds the textual version string used for Geth archives. // e.g. "1.8.11-dea1ce05" for stable releases, or -// "1.8.13-unstable-21c059b6" for unstable releases +// +// "1.8.13-unstable-21c059b6" for unstable releases func ArchiveVersion(gitCommit string) string { vsn := Version if VersionMeta != "stable" {