From 19434b8de6c8613be1ef1a5a660d1098cfaa6610 Mon Sep 17 00:00:00 2001 From: egonspace Date: Tue, 14 May 2024 11:44:48 +0900 Subject: [PATCH 01/51] feat: brioche first implementation --- consensus/ethash/consensus.go | 6 +-- core/block_validator.go | 10 +++++ core/blockchain.go | 24 +++--------- core/blockchain_test.go | 34 ++++++++++++++++- core/state_processor.go | 8 ++-- core/types.go | 5 ++- eth/downloader/downloader.go | 1 + eth/state_accessor.go | 2 +- go.mod | 4 +- params/config.go | 41 ++++++++++++++++++--- wemix/admin.go | 69 +++++++++++++++++++++++++++-------- wemix/admin_test.go | 48 ++++++++++++++++++++++++ wemix/miner/miner.go | 6 +-- wemix/rewards_test.go | 59 ++++++++++++++++++++++++++++-- 14 files changed, 259 insertions(+), 58 deletions(-) create mode 100644 wemix/admin_test.go diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 506bd8cb8114..4ab4413b8443 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -42,7 +42,6 @@ import ( var ( FrontierBlockReward = big.NewInt(5e+18) // Block reward in wei for successfully mining a block ByzantiumBlockReward = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium - WemixBlockReward = big.NewInt(0) // Block reward in wei for Wemix ConstantinopleBlockReward = big.NewInt(2e+18) // Block reward in wei for successfully mining a block upward from Constantinople maxUncles = 2 // Maximum number of uncles allowed in a single block allowedFutureBlockTimeSeconds = int64(15) // Max seconds from current time allowed for blocks, before they're considered future blocks @@ -698,9 +697,8 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header } state.AddBalance(header.Coinbase, reward) } else { - blockReward = WemixBlockReward coinbase, rewards, err := wemixminer.CalculateRewards( - header.Number, blockReward, header.Fees, + config, header.Number, header.Fees, func(addr common.Address, amt *big.Int) { state.AddBalance(addr, amt) }) @@ -713,7 +711,7 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header if err == wemixminer.ErrNotInitialized { reward := new(big.Int) if header.Fees != nil { - reward.Add(blockReward, header.Fees) + reward.Add(reward, header.Fees) } state.AddBalance(header.Coinbase, reward) return nil diff --git a/core/block_validator.go b/core/block_validator.go index 028beadc491a..7b5f8f8ad518 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -17,6 +17,7 @@ package core import ( + "bytes" "fmt" "math/big" @@ -108,6 +109,15 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD return nil } +// ValidateReward validates the reward info of remote block with the reward processed locally +func (v *BlockValidator) ValidateReward(header *types.Header, localHeader *types.Header) error { + // verify rewards info + if !bytes.Equal(header.Rewards, localHeader.Rewards) { + return fmt.Errorf("invalid rewards (remote: %x local: %x)", header.Rewards, localHeader.Rewards) + } + return nil +} + // CalcGasLimit computes the gas limit of the next block after parent. It aims // to keep the baseline gas close to the provided target, and increase it towards // the target if the baseline gas is lower. diff --git a/core/blockchain.go b/core/blockchain.go index 41d4bbeb84e2..8a570e7fa758 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -43,7 +43,6 @@ import ( "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/trie" - wemixminer "github.com/ethereum/go-ethereum/wemix/miner" lru "github.com/hashicorp/golang-lru" ) @@ -1608,11 +1607,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1) } - // wemix: reward calculation uses governance contract, meaning - // the previous block is required. For fast sync, we need to wait for - // governance is initialized and try again. - retryCount := 2 - retry: statedb, err := state.New(parent.Root, bc.stateCache, bc.snaps) if err != nil { return it.index, err @@ -1642,13 +1636,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) // Process block using the parent state as reference point substart := time.Now() - receipts, logs, usedGas, fees, err := bc.processor.Process(block, statedb, bc.vmConfig) + appliedHeader, receipts, logs, usedGas, fees, err := bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { bc.reportBlock(block, receipts, err) atomic.StoreUint32(&followupInterrupt, 1) return it.index, err } - // Update the metrics touched during block processing accountReadTimer.Update(statedb.AccountReads) // Account reads are complete, we can mark them storageReadTimer.Update(statedb.StorageReads) // Storage reads are complete, we can mark them @@ -1665,17 +1658,12 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) // Validate the state using the default validator substart = time.Now() if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, fees); err != nil { - if retryCount--; !wemixminer.IsPoW() && retryCount > 0 { - // make sure the previous block exists in order to calculate rewards distribution - for try := 100; try > 0; try-- { - if _, _, err := wemixminer.CalculateRewards(block.Number(), big.NewInt(0), big.NewInt(100000000), nil); err == nil { - break - } - time.Sleep(100 * time.Millisecond) - } - goto retry - } + bc.reportBlock(block, receipts, err) + atomic.StoreUint32(&followupInterrupt, 1) + return it.index, err + } + if err := bc.validator.ValidateReward(block.Header(), appliedHeader); err != nil { bc.reportBlock(block, receipts, err) atomic.StoreUint32(&followupInterrupt, 1) return it.index, err diff --git a/core/blockchain_test.go b/core/blockchain_test.go index cda30f0f5860..568bc677ef29 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -159,17 +159,24 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { if err != nil { return err } - receipts, _, usedGas, fees, err := blockchain.processor.Process(block, statedb, vm.Config{}) + appliedHeader, receipts, _, usedGas, fees, err := blockchain.processor.Process(block, statedb, vm.Config{}) if err != nil { blockchain.reportBlock(block, receipts, err) return err } + err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, fees) if err != nil { blockchain.reportBlock(block, receipts, err) return err } + err = blockchain.validator.ValidateReward(block.Header(), appliedHeader) + if err != nil { + blockchain.reportBlock(block, receipts, err) + return err + } + blockchain.chainmu.MustLock() rawdb.WriteTd(blockchain.db, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTd(block.ParentHash(), block.NumberU64()-1))) rawdb.WriteBlock(blockchain.db, block) @@ -3770,3 +3777,28 @@ func TestSetCanonical(t *testing.T) { chain.SetCanonical(canon[DefaultCacheConfig.TriesInMemory-1]) verify(canon[DefaultCacheConfig.TriesInMemory-1]) } + +func TestRewardValidation(t *testing.T) { + // Configure and generate a sample block chain + var ( + db = rawdb.NewMemoryDatabase() + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000) + deleteAddr = common.Address{1} + gspec = &Genesis{ + Config: ¶ms.ChainConfig{ChainID: big.NewInt(1), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}, + Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, + } + genesis = gspec.MustCommit(db) + ) + + blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + defer blockchain.Stop() + + blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 1, nil) + + if _, err := blockchain.InsertChain(blocks); err != nil { + t.Fatal(err) + } +} diff --git a/core/state_processor.go b/core/state_processor.go index e2b2c1fc5efc..743d3d6f98ed 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -56,7 +56,7 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen // Process returns the receipts and logs accumulated during the process and // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. -func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, *big.Int, error) { +func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*types.Header, types.Receipts, []*types.Log, uint64, *big.Int, error) { var ( receipts types.Receipts usedGas = new(uint64) @@ -77,12 +77,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg for i, tx := range block.Transactions() { msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee) if err != nil { - return nil, nil, 0, big.NewInt(0), fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) + return nil, nil, nil, 0, big.NewInt(0), fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.Prepare(tx.Hash(), i) receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, fees, vmenv) if err != nil { - return nil, nil, 0, big.NewInt(0), fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) + return nil, nil, nil, 0, big.NewInt(0), fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) @@ -90,7 +90,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) - return receipts, allLogs, *usedGas, fees, nil + return header, receipts, allLogs, *usedGas, fees, nil } func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, fees *big.Int, evm *vm.EVM) (*types.Receipt, error) { diff --git a/core/types.go b/core/types.go index ae909a48fb1f..3c565d1118cf 100644 --- a/core/types.go +++ b/core/types.go @@ -34,6 +34,9 @@ type Validator interface { // ValidateState validates the given statedb and optionally the receipts and // gas used. ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, fees *big.Int) error + + // ValidateReward validates the reward info of the block header with the reward processed in local + ValidateReward(header *types.Header, localHeader *types.Header) error } // Prefetcher is an interface for pre-caching transaction signatures and state. @@ -49,5 +52,5 @@ type Processor interface { // Process processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb and applying any rewards to both // the processor (coinbase) and any included uncles. - Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, *big.Int, error) + Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*types.Header, types.Receipts, []*types.Log, uint64, *big.Int, error) } diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 9eef5dfd8d70..9537a5a3e7fa 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -384,6 +384,7 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int, // Post a user notification of the sync (only once per session) if atomic.CompareAndSwapInt32(&d.notified, 0, 1) { log.Info("Block synchronisation started") + defer log.Info("Block synchronisation finished") } if mode == SnapSync { // Snap sync uses the snapshot namespace to store potentially flakey data until diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 98be012f3326..481909968fd0 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -131,7 +131,7 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state if current = eth.blockchain.GetBlockByNumber(next); current == nil { return nil, fmt.Errorf("block #%d not found", next) } - _, _, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) + _, _, _, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) if err != nil { return nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err) } diff --git a/go.mod b/go.mod index 1956e64450e9..0e3cb402128d 100644 --- a/go.mod +++ b/go.mod @@ -60,6 +60,8 @@ require ( github.com/stretchr/testify v1.7.0 github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 github.com/tyler-smith/go-bip39 v1.0.1-0.20181017060643-dbb3b84ba2ef + github.com/yahoo/coname v0.0.0-20170609175141-84592ddf8673 + github.com/yoseplee/vrf v0.0.0-20210814110709-d1caf509310b go.etcd.io/etcd/api/v3 v3.5.2 go.etcd.io/etcd/client/v3 v3.5.2 go.etcd.io/etcd/server/v3 v3.5.2 @@ -72,8 +74,6 @@ require ( golang.org/x/tools v0.1.8-0.20211029000441-d6a9af8af023 gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/urfave/cli.v1 v1.20.0 - github.com/yoseplee/vrf v0.0.0-20210814110709-d1caf509310b - github.com/yahoo/coname v0.0.0-20170609175141-84592ddf8673 ) require ( diff --git a/params/config.go b/params/config.go index 39d494868726..8847ddfdf93d 100644 --- a/params/config.go +++ b/params/config.go @@ -159,7 +159,13 @@ var ( LondonBlock: big.NewInt(0), PangyoBlock: big.NewInt(0), ApplepieBlock: big.NewInt(20_476_911), + BriocheBlock: big.NewInt(53_557_371), // 24-07-01 00:00:00 (UTC) expected Ethash: new(EthashConfig), + Brioche: &BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalving: big.NewInt(53_557_371), + HalvingPeriod: big.NewInt(63_115_200), + }, } // WemixTestnetChainConfig contains the chain parameters to run a node on the Wemix test network. @@ -180,7 +186,13 @@ var ( LondonBlock: big.NewInt(0), PangyoBlock: big.NewInt(10_000_000), ApplepieBlock: big.NewInt(26_240_268), + BriocheBlock: big.NewInt(60_537_845), // 24-06-17 02:00:00 (UTC) expected Ethash: new(EthashConfig), + Brioche: &BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalving: big.NewInt(60_537_845), + HalvingPeriod: big.NewInt(63_115_200), + }, } // SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network. @@ -303,16 +315,16 @@ var ( // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, new(EthashConfig), nil} + AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, new(EthashConfig), nil, nil} // AllCliqueProtocolChanges contains every protocol change (EIPs) introduced // and accepted by the Ethereum core developers into the Clique consensus. // // This configuration is intentionally not using keyed fields to force anyone // adding flags to the config to also have to set these fields. - AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}} + AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil} - TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, new(EthashConfig), nil} + TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, new(EthashConfig), nil, nil} TestRules = TestChainConfig.Rules(new(big.Int), false) ) @@ -395,19 +407,31 @@ type ChainConfig struct { MergeForkBlock *big.Int `json:"mergeForkBlock,omitempty"` // EIP-3675 (TheMerge) switch block (nil = no fork, 0 = already in merge proceedings) PangyoBlock *big.Int `json:"pangyoBlock,omitempty"` // Pangyo switch block (nil = no fork, 0 = already on pangyo) ApplepieBlock *big.Int `json:"applepieBlock,omitempty"` // Applepie switch block (nil = no fork, 0 = already on applepie) + BriocheBlock *big.Int `json:"briocheBlock,omitempty"` // Brioche switch block (nil = no fork, 0 = already on brioche) // TerminalTotalDifficulty is the amount of total difficulty reached by // the network that triggers the consensus upgrade. TerminalTotalDifficulty *big.Int `json:"terminalTotalDifficulty,omitempty"` // Various consensus engines - Ethash *EthashConfig `json:"ethash,omitempty"` - Clique *CliqueConfig `json:"clique,omitempty"` + Ethash *EthashConfig `json:"ethash,omitempty"` + Clique *CliqueConfig `json:"clique,omitempty"` + Brioche *BriocheConfig `json:"brioche,omitempty"` // if this config is nil, brioche halving is not applied } // EthashConfig is the consensus engine configs for proof-of-work based sealing. type EthashConfig struct{} +// Brioche halving configuration +type BriocheConfig struct { + // if the chain is on brioche hard fork, `RewardAmount` of gov contract is not used rather this `BlockReward` is used + BlockReward *big.Int `json:"blockReward,omitempty"` // if nil, then default block reward is 1e18 (=1 wemix) + FirstHalving *big.Int `json:"firstHalving,omitempty"` // if nil, then halving is not work + HalvingPeriod *big.Int `json:"halvingPeriod,omitempty"` // if nil, then halving is not work + LastHalving *big.Int `json:"lastHalving,omitempty"` // if nil, then halving goes on continuously + ZeroReward *big.Int `json:"zeroReward,omitempty"` // if nil, +} + // String implements the stringer interface, returning the consensus engine details. func (c *EthashConfig) String() string { return "ethash" @@ -435,7 +459,7 @@ func (c *ChainConfig) String() string { default: engine = "unknown" } - return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, MergeFork: %v, PangyoFork: %v, ApplepieFork: %v, Terminal TD: %v, Engine: %v}", + return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, MergeFork: %v, PangyoFork: %v, ApplepieFork: %v, BriocheFork: %v, Terminal TD: %v, Engine: %v}", c.ChainID, c.HomesteadBlock, c.DAOForkBlock, @@ -454,6 +478,7 @@ func (c *ChainConfig) String() string { c.MergeForkBlock, c.PangyoBlock, c.ApplepieBlock, + c.BriocheBlock, c.TerminalTotalDifficulty, engine, ) @@ -537,6 +562,10 @@ func (c *ChainConfig) IsArrowGlacier(num *big.Int) bool { return isForked(c.ArrowGlacierBlock, num) } +func (c *ChainConfig) IsBrioche(num *big.Int) bool { + return isForked(c.BriocheBlock, num) +} + // IsTerminalPoWBlock returns whether the given block is the last block of PoW stage. func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *big.Int) bool { if c.TerminalTotalDifficulty == nil { diff --git a/wemix/admin.go b/wemix/admin.go index 5441dfa14f65..f0470b68c0c5 100644 --- a/wemix/admin.go +++ b/wemix/admin.go @@ -123,11 +123,12 @@ type rewardParameters struct { var ( // "Wemix Registry" - magic, _ = big.NewInt(0).SetString("0x57656d6978205265676973747279", 0) - etcdClusterName = "Wemix" - big0 = big.NewInt(0) - nilAddress = common.Address{} - admin *wemixAdmin + magic, _ = big.NewInt(0).SetString("0x57656d6978205265676973747279", 0) + etcdClusterName = "Wemix" + big0 = big.NewInt(0) + nilAddress = common.Address{} + defaultBriocheBlockReward = int64(1e18) + admin *wemixAdmin ErrAlreadyRunning = errors.New("already running") ErrExists = errors.New("already exists") @@ -1051,7 +1052,7 @@ func handleBlock94Rewards(height *big.Int, rp *rewardParameters, fees *big.Int) // distributeRewards divides the rewardAmount among members according to their // stakes, and allocates rewards to staker, ecoSystem, and maintenance accounts. -func distributeRewards(height *big.Int, rp *rewardParameters, fees *big.Int) ([]reward, error) { +func distributeRewards(height *big.Int, rp *rewardParameters, blockReward *big.Int, fees *big.Int) ([]reward, error) { dm := new(big.Int) for i := 0; i < len(rp.distributionMethod); i++ { dm.Add(dm, rp.distributionMethod[i]) @@ -1061,14 +1062,14 @@ func distributeRewards(height *big.Int, rp *rewardParameters, fees *big.Int) ([] } v10000 := big.NewInt(10000) - minerAmount := new(big.Int).Set(rp.rewardAmount) + minerAmount := new(big.Int).Set(blockReward) minerAmount.Div(minerAmount.Mul(minerAmount, rp.distributionMethod[0]), v10000) - stakerAmount := new(big.Int).Set(rp.rewardAmount) + stakerAmount := new(big.Int).Set(blockReward) stakerAmount.Div(stakerAmount.Mul(stakerAmount, rp.distributionMethod[1]), v10000) - ecoSystemAmount := new(big.Int).Set(rp.rewardAmount) + ecoSystemAmount := new(big.Int).Set(blockReward) ecoSystemAmount.Div(ecoSystemAmount.Mul(ecoSystemAmount, rp.distributionMethod[2]), v10000) // the rest goes to maintenance - maintenanceAmount := new(big.Int).Set(rp.rewardAmount) + maintenanceAmount := new(big.Int).Set(blockReward) maintenanceAmount.Sub(maintenanceAmount, minerAmount) maintenanceAmount.Sub(maintenanceAmount, stakerAmount) maintenanceAmount.Sub(maintenanceAmount, ecoSystemAmount) @@ -1102,7 +1103,7 @@ func distributeRewards(height *big.Int, rp *rewardParameters, fees *big.Int) ([] } d.Mul(d, vn) b.Sub(b, d) - for i, ix := 0, height.Int64()%int64(n); b.Cmp(v0) > 0; i, ix = i+1, (ix+1)%int64(n) { + for ix := height.Int64() % int64(n); b.Cmp(v0) > 0; ix = (ix + 1) % int64(n) { rewards[ix].Reward.Add(rewards[ix].Reward, v1) b.Sub(b, v1) } @@ -1146,7 +1147,7 @@ func distributeRewards(height *big.Int, rp *rewardParameters, fees *big.Int) ([] return rewards, nil } -func (ma *wemixAdmin) calculateRewards(num, blockReward, fees *big.Int, addBalance func(common.Address, *big.Int)) (coinbase *common.Address, rewards []byte, err error) { +func (ma *wemixAdmin) calculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (coinbase *common.Address, rewards []byte, err error) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -1179,7 +1180,32 @@ func (ma *wemixAdmin) calculateRewards(num, blockReward, fees *big.Int, addBalan coinbase.SetBytes(rp.members[mix].Reward.Bytes()) } - rr, errr := distributeRewards(num, rp, fees) + // block reward + // - not brioche chain: use `EnvStorageImp.getBlockRewardAmount()` + // - brioche chain + // - config.Brioche.BlockReward != nil: config.Brioche.BlockReward + // - config.Brioche.BlockReward == nil: 1e18 + // - apply halving for BlockReward + var blockReward *big.Int + if config.IsBrioche(num) { + if config.Brioche != nil && config.Brioche.BlockReward != nil { + blockReward = big.NewInt(0).Set(config.Brioche.BlockReward) + } else { + blockReward = big.NewInt(defaultBriocheBlockReward) // default brioche block reward + } + if config.Brioche != nil && + config.Brioche.FirstHalving != nil && + config.Brioche.HalvingPeriod != nil && + num.Cmp(config.Brioche.FirstHalving) >= 0 { + past := big.NewInt(0).Set(num) + past.Sub(past, config.Brioche.FirstHalving) + blockReward = halveRewards(blockReward, config.Brioche.HalvingPeriod, past) + } + } else { + // if the wemix chain is not on brioche hard fork, use the `rewardAmount` from gov contract + blockReward = big.NewInt(0).Set(rp.rewardAmount) + } + rr, errr := distributeRewards(num, rp, blockReward, fees) if errr != nil { err = errr return @@ -1195,8 +1221,21 @@ func (ma *wemixAdmin) calculateRewards(num, blockReward, fees *big.Int, addBalan return } -func calculateRewards(num, blockReward, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { - return admin.calculateRewards(num, blockReward, fees, addBalance) +func calculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { + return admin.calculateRewards(config, num, fees, addBalance) +} + +func halveRewards(baseReward *big.Int, halvePeriod *big.Int, pastBlocks *big.Int) *big.Int { + result := big.NewInt(0).Set(baseReward) + past := big.NewInt(0).Set(pastBlocks) + for { + result = result.Div(result, big.NewInt(2)) + if past.Cmp(halvePeriod) < 0 { + break + } + past = past.Sub(past, halvePeriod) + } + return result } func verifyRewards(num *big.Int, rewards string) error { diff --git a/wemix/admin_test.go b/wemix/admin_test.go new file mode 100644 index 000000000000..d912dcf667d1 --- /dev/null +++ b/wemix/admin_test.go @@ -0,0 +1,48 @@ +package wemix + +import ( + "math/big" + "testing" +) + +func TestHalveRewards(t *testing.T) { + testcases := []struct { + reward *big.Int + period *big.Int + past *big.Int + expected *big.Int + }{ + // sample test + {big.NewInt(1e18), big.NewInt(100), big.NewInt(0), big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(99), big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(101), big.NewInt(25e16)}, + + // brioche halving test + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(0), big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 - 1), big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200), big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200*2 - 1), big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 2), big.NewInt(125e15)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 3), big.NewInt(625e14)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 4), big.NewInt(3125e13)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 5), big.NewInt(15625e12)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 6), big.NewInt(78125e11)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 7), big.NewInt(390625e10)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 8), big.NewInt(1953125e9)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 9), big.NewInt(9765625e8)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 10), big.NewInt(48828125e7)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 11), big.NewInt(244140625e6)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 12), big.NewInt(1220703125e5)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 13), big.NewInt(6103515625e4)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 14), big.NewInt(30517578125e3)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 15), big.NewInt(152587890625e2)}, + } + + for _, testcase := range testcases { + halved := halveRewards(testcase.reward, testcase.period, testcase.past) + if testcase.expected.Cmp(halved) != 0 { + t.Errorf("halveRewards mismatched (expected=%v, actual=%v)", testcase.expected, halved) + } + } +} diff --git a/wemix/miner/miner.go b/wemix/miner/miner.go index 45abda5a5c59..0b369b3b063c 100644 --- a/wemix/miner/miner.go +++ b/wemix/miner/miner.go @@ -16,7 +16,7 @@ var ( AmPartnerFunc func() bool IsPartnerFunc func(string) bool AmHubFunc func(string) int - CalculateRewardsFunc func(*big.Int, *big.Int, *big.Int, func(common.Address, *big.Int)) (*common.Address, []byte, error) + CalculateRewardsFunc func(*params.ChainConfig, *big.Int, *big.Int, func(common.Address, *big.Int)) (*common.Address, []byte, error) VerifyRewardsFunc func(*big.Int, string) error GetCoinbaseFunc func(height *big.Int) (coinbase common.Address, err error) SignBlockFunc func(height *big.Int, hash common.Hash) (coinbase common.Address, sig []byte, err error) @@ -79,11 +79,11 @@ func IsPoW() bool { return params.ConsensusMethod == params.ConsensusPoW } -func CalculateRewards(num, blockReward, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { +func CalculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { if CalculateRewardsFunc == nil { return nil, nil, ErrNotInitialized } else { - return CalculateRewardsFunc(num, blockReward, fees, addBalance) + return CalculateRewardsFunc(config, num, fees, addBalance) } } diff --git a/wemix/rewards_test.go b/wemix/rewards_test.go index 0737abd492c1..ea90b90f42a0 100644 --- a/wemix/rewards_test.go +++ b/wemix/rewards_test.go @@ -4,12 +4,41 @@ package wemix import ( "encoding/json" + "github.com/ethereum/go-ethereum/common" "math/big" + "strconv" "testing" - - "github.com/ethereum/go-ethereum/common" + "time" ) +func TestBlockMintingQuantity(t *testing.T) { + minted, _ := big.NewInt(0).SetString("379886454000000000000000000", 0) // 379,886,454 wemix + annualReward, _ := big.NewInt(0).SetString("500000000000000000", 0) // 0.5 wemix + t.Logf("initial minted = %d", minted) + t.Logf("reward = %d", annualReward) + for i := 2024; i < 2054; i += 2 { + minted = new(big.Int).Add(minted, new(big.Int).Mul(annualReward, big.NewInt(63115200))) + annualReward = new(big.Int).Div(annualReward, big.NewInt(2)) + t.Logf("minted = %d", minted) + t.Logf("reward = %d", annualReward) + } + for i := 2054; i < 2100; i += 2 { + minted = new(big.Int).Add(minted, new(big.Int).Mul(annualReward, big.NewInt(63115200))) + } + t.Logf("total minted = %d", minted) +} + +func TestHalvesPeriod(t *testing.T) { + halvesTime := big.NewInt(1719792000) // 2024-07-01 00:00:00 (UTC) + blockPeriod := big.NewInt(63_115_200) // 86400 * 730.5 + loc, _ := time.LoadLocation("UTC") + for i := 0; i < 17; i++ { + tm, _ := strconv.ParseInt(halvesTime.String(), 10, 64) + t.Logf("~ %v(%d)", time.Unix(tm, 0).In(loc), halvesTime) + halvesTime.Add(halvesTime, blockPeriod) + } +} + // TestDistributeRewards tests the DistributeRewards function func TestDistributeRewards(t *testing.T) { @@ -135,11 +164,35 @@ func TestDistributeRewards(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Call the distributeRewards function - rewards, err := distributeRewards(tt.height, tt.rp, tt.fees) + rewards, err := distributeRewards(tt.height, tt.rp, big.NewInt(defaultBriocheBlockReward), tt.fees) rewardsString, _ := json.Marshal(rewards) if string(rewardsString) != tt.want { t.Errorf("distributeRewards() failed: %v, %v <-> %v", err, tt.want, string(rewardsString)) } + + distTotal := big.NewInt(0) + for _, dist := range tt.rp.distributionMethod { + distTotal.Add(distTotal, dist) + } + totalRewards := big.NewInt(0) + memberRewards := big.NewInt(0) + for i, reward := range rewards { + totalRewards.Add(totalRewards, reward.Reward) + if i < len(tt.rp.members) { + memberRewards.Add(memberRewards, reward.Reward) + } + } + totalAmount := big.NewInt(0).Set(tt.rp.rewardAmount) + totalAmount.Add(totalAmount, tt.fees) + memberAmount := big.NewInt(0).Set(tt.rp.rewardAmount) + memberAmount = memberAmount.Mul(memberAmount, tt.rp.distributionMethod[0]) + memberAmount = memberAmount.Div(memberAmount, distTotal) + if memberRewards.Cmp(memberAmount) != 0 { + t.Errorf("members reward amount mismatched! sum=%d, rewards=%d", memberRewards, memberAmount) + } + if totalRewards.Cmp(totalAmount) != 0 { + t.Errorf("total reward amount mismatched! sum=%d, rewards=%d", totalRewards, totalAmount) + } }) } } From a1a06a7fce632fd3f1918b628474541b35b8ae79 Mon Sep 17 00:00:00 2001 From: egonspace Date: Thu, 16 May 2024 10:51:35 +0900 Subject: [PATCH 02/51] fix: add more configuration --- params/config.go | 22 +++--- wemix/admin.go | 52 +++++++------ wemix/admin_test.go | 171 +++++++++++++++++++++++++++++++++++------- wemix/rewards_test.go | 30 -------- 4 files changed, 187 insertions(+), 88 deletions(-) diff --git a/params/config.go b/params/config.go index 8847ddfdf93d..34962e69d351 100644 --- a/params/config.go +++ b/params/config.go @@ -162,9 +162,9 @@ var ( BriocheBlock: big.NewInt(53_557_371), // 24-07-01 00:00:00 (UTC) expected Ethash: new(EthashConfig), Brioche: &BriocheConfig{ - BlockReward: big.NewInt(1e18), - FirstHalving: big.NewInt(53_557_371), - HalvingPeriod: big.NewInt(63_115_200), + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(53_557_371), + HalvingPeriod: big.NewInt(63_115_200), }, } @@ -189,9 +189,9 @@ var ( BriocheBlock: big.NewInt(60_537_845), // 24-06-17 02:00:00 (UTC) expected Ethash: new(EthashConfig), Brioche: &BriocheConfig{ - BlockReward: big.NewInt(1e18), - FirstHalving: big.NewInt(60_537_845), - HalvingPeriod: big.NewInt(63_115_200), + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(60_537_845), + HalvingPeriod: big.NewInt(63_115_200), }, } @@ -425,11 +425,11 @@ type EthashConfig struct{} // Brioche halving configuration type BriocheConfig struct { // if the chain is on brioche hard fork, `RewardAmount` of gov contract is not used rather this `BlockReward` is used - BlockReward *big.Int `json:"blockReward,omitempty"` // if nil, then default block reward is 1e18 (=1 wemix) - FirstHalving *big.Int `json:"firstHalving,omitempty"` // if nil, then halving is not work - HalvingPeriod *big.Int `json:"halvingPeriod,omitempty"` // if nil, then halving is not work - LastHalving *big.Int `json:"lastHalving,omitempty"` // if nil, then halving goes on continuously - ZeroReward *big.Int `json:"zeroReward,omitempty"` // if nil, + BlockReward *big.Int `json:"blockReward,omitempty"` // if nil, then default block reward is 1e18 (=1 wemix) + FirstHalvingBlock *big.Int `json:"firstHalvingBlock,omitempty"` // if nil, then halving is not work. including this block + HalvingPeriod *big.Int `json:"halvingPeriod,omitempty"` // if nil, then halving is not work + HalvingTimes uint64 `json:"halvingTimes,omitempty"` // if 0, then no halving + NoRewardHereAfter *big.Int `json:"noRewardHereAfter,omitempty"` // if nil, block reward goes on endlessly } // String implements the stringer interface, returning the consensus engine details. diff --git a/wemix/admin.go b/wemix/admin.go index f0470b68c0c5..e3e86cd450ec 100644 --- a/wemix/admin.go +++ b/wemix/admin.go @@ -1180,31 +1180,20 @@ func (ma *wemixAdmin) calculateRewards(config *params.ChainConfig, num, fees *bi coinbase.SetBytes(rp.members[mix].Reward.Bytes()) } - // block reward - // - not brioche chain: use `EnvStorageImp.getBlockRewardAmount()` - // - brioche chain - // - config.Brioche.BlockReward != nil: config.Brioche.BlockReward - // - config.Brioche.BlockReward == nil: 1e18 - // - apply halving for BlockReward var blockReward *big.Int if config.IsBrioche(num) { - if config.Brioche != nil && config.Brioche.BlockReward != nil { - blockReward = big.NewInt(0).Set(config.Brioche.BlockReward) - } else { - blockReward = big.NewInt(defaultBriocheBlockReward) // default brioche block reward - } - if config.Brioche != nil && - config.Brioche.FirstHalving != nil && - config.Brioche.HalvingPeriod != nil && - num.Cmp(config.Brioche.FirstHalving) >= 0 { - past := big.NewInt(0).Set(num) - past.Sub(past, config.Brioche.FirstHalving) - blockReward = halveRewards(blockReward, config.Brioche.HalvingPeriod, past) - } + blockReward = getBriocheBlockReward(config.Brioche, num) } else { // if the wemix chain is not on brioche hard fork, use the `rewardAmount` from gov contract blockReward = big.NewInt(0).Set(rp.rewardAmount) } + + // block reward + // - not brioche chain: use `EnvStorageImp.getBlockRewardAmount()` + // - brioche chain + // - config.Brioche.BlockReward != nil: config.Brioche.BlockReward + // - config.Brioche.BlockReward == nil: 1e18 + // - apply halving for BlockReward rr, errr := distributeRewards(num, rp, blockReward, fees) if errr != nil { err = errr @@ -1221,14 +1210,35 @@ func (ma *wemixAdmin) calculateRewards(config *params.ChainConfig, num, fees *bi return } +func getBriocheBlockReward(brioche *params.BriocheConfig, num *big.Int) *big.Int { + blockReward := big.NewInt(defaultBriocheBlockReward) // default brioche block reward + if brioche != nil { + if brioche.BlockReward != nil { + blockReward = big.NewInt(0).Set(brioche.BlockReward) + } + if brioche.NoRewardHereAfter != nil && + brioche.NoRewardHereAfter.Cmp(num) <= 0 { + blockReward = big.NewInt(0) + } else if brioche.FirstHalvingBlock != nil && + brioche.HalvingPeriod != nil && + brioche.HalvingTimes > 0 && + num.Cmp(brioche.FirstHalvingBlock) >= 0 { + past := big.NewInt(0).Set(num) + past.Sub(past, brioche.FirstHalvingBlock) + blockReward = halveRewards(blockReward, brioche.HalvingPeriod, past, brioche.HalvingTimes) + } + } + return blockReward +} + func calculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { return admin.calculateRewards(config, num, fees, addBalance) } -func halveRewards(baseReward *big.Int, halvePeriod *big.Int, pastBlocks *big.Int) *big.Int { +func halveRewards(baseReward *big.Int, halvePeriod *big.Int, pastBlocks *big.Int, halvingTimes uint64) *big.Int { result := big.NewInt(0).Set(baseReward) past := big.NewInt(0).Set(pastBlocks) - for { + for ; halvingTimes > 0; halvingTimes-- { result = result.Div(result, big.NewInt(2)) if past.Cmp(halvePeriod) < 0 { break diff --git a/wemix/admin_test.go b/wemix/admin_test.go index d912dcf667d1..d3c466f613e9 100644 --- a/wemix/admin_test.go +++ b/wemix/admin_test.go @@ -1,6 +1,7 @@ package wemix import ( + "github.com/ethereum/go-ethereum/params" "math/big" "testing" ) @@ -10,39 +11,157 @@ func TestHalveRewards(t *testing.T) { reward *big.Int period *big.Int past *big.Int + times uint64 expected *big.Int }{ // sample test - {big.NewInt(1e18), big.NewInt(100), big.NewInt(0), big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(99), big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), big.NewInt(25e16)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(101), big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(0), 4, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(99), 4, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 4, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(101), 4, big.NewInt(25e16)}, + + // times test + {big.NewInt(1e18), big.NewInt(100), big.NewInt(0), 0, big.NewInt(1e18)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 0, big.NewInt(1e18)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 1, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 3, big.NewInt(25e16)}, // brioche halving test - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(0), big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 - 1), big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200), big.NewInt(25e16)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200*2 - 1), big.NewInt(25e16)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 2), big.NewInt(125e15)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 3), big.NewInt(625e14)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 4), big.NewInt(3125e13)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 5), big.NewInt(15625e12)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 6), big.NewInt(78125e11)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 7), big.NewInt(390625e10)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 8), big.NewInt(1953125e9)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 9), big.NewInt(9765625e8)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 10), big.NewInt(48828125e7)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 11), big.NewInt(244140625e6)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 12), big.NewInt(1220703125e5)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 13), big.NewInt(6103515625e4)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 14), big.NewInt(30517578125e3)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 15), big.NewInt(152587890625e2)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(0), 16, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 - 1), 16, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200), 16, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200*2 - 1), 16, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 2), 16, big.NewInt(125e15)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 3), 16, big.NewInt(625e14)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 4), 16, big.NewInt(3125e13)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 5), 16, big.NewInt(15625e12)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 6), 16, big.NewInt(78125e11)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 7), 16, big.NewInt(390625e10)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 8), 16, big.NewInt(1953125e9)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 9), 16, big.NewInt(9765625e8)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 10), 16, big.NewInt(48828125e7)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 11), 16, big.NewInt(244140625e6)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 12), 16, big.NewInt(1220703125e5)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 13), 16, big.NewInt(6103515625e4)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 14), 16, big.NewInt(30517578125e3)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 15), 16, big.NewInt(152587890625e2)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 15), 17, big.NewInt(152587890625e2)}, + } + + for _, tc := range testcases { + halved := halveRewards(tc.reward, tc.period, tc.past, tc.times) + if tc.expected.Cmp(halved) != 0 { + t.Errorf("halveRewards mismatched (expected=%v, actual=%v)", tc.expected, halved) + } + } +} + +func TestGetBriocheBlockReward(t *testing.T) { + testcases := []struct { + briocheConfig *params.BriocheConfig + blockNum *big.Int + expected *big.Int + }{ + // normal case + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + HalvingTimes: 10, + NoRewardHereAfter: big.NewInt(101), + }, + blockNum: big.NewInt(100), + expected: big.NewInt(5e17), + }, + + // base block reward variations + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(7e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + HalvingTimes: 10, + NoRewardHereAfter: big.NewInt(101), + }, + blockNum: big.NewInt(100), + expected: big.NewInt(35e17), + }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(3), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + HalvingTimes: 10, + NoRewardHereAfter: big.NewInt(101), + }, + blockNum: big.NewInt(100), + expected: big.NewInt(1), + }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(1), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + HalvingTimes: 10, + NoRewardHereAfter: big.NewInt(101), + }, + blockNum: big.NewInt(100), + expected: big.NewInt(0), + }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: nil, // it will use the default block reward + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + HalvingTimes: 10, + NoRewardHereAfter: big.NewInt(101), + }, + blockNum: big.NewInt(100), + expected: big.NewInt(5e17), + }, + + // no halving + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: nil, // it will use the default block reward + FirstHalvingBlock: nil, + HalvingPeriod: big.NewInt(100), + HalvingTimes: 10, + NoRewardHereAfter: big.NewInt(101), + }, + blockNum: big.NewInt(100), + expected: big.NewInt(1e18), + }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: nil, + HalvingTimes: 10, + NoRewardHereAfter: big.NewInt(101), + }, + blockNum: big.NewInt(100), + expected: big.NewInt(10), + }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + HalvingTimes: 0, + NoRewardHereAfter: big.NewInt(101), + }, + blockNum: big.NewInt(100), + expected: big.NewInt(10), + }, } - for _, testcase := range testcases { - halved := halveRewards(testcase.reward, testcase.period, testcase.past) - if testcase.expected.Cmp(halved) != 0 { - t.Errorf("halveRewards mismatched (expected=%v, actual=%v)", testcase.expected, halved) + for _, tc := range testcases { + actual := getBriocheBlockReward(tc.briocheConfig, tc.blockNum) + if tc.expected.Cmp(actual) != 0 { + t.Errorf("getBriocheReward mismatched (expected=%v, actual=%v)", tc.expected, actual) } } } diff --git a/wemix/rewards_test.go b/wemix/rewards_test.go index ea90b90f42a0..edd6ba2f9f2d 100644 --- a/wemix/rewards_test.go +++ b/wemix/rewards_test.go @@ -6,39 +6,9 @@ import ( "encoding/json" "github.com/ethereum/go-ethereum/common" "math/big" - "strconv" "testing" - "time" ) -func TestBlockMintingQuantity(t *testing.T) { - minted, _ := big.NewInt(0).SetString("379886454000000000000000000", 0) // 379,886,454 wemix - annualReward, _ := big.NewInt(0).SetString("500000000000000000", 0) // 0.5 wemix - t.Logf("initial minted = %d", minted) - t.Logf("reward = %d", annualReward) - for i := 2024; i < 2054; i += 2 { - minted = new(big.Int).Add(minted, new(big.Int).Mul(annualReward, big.NewInt(63115200))) - annualReward = new(big.Int).Div(annualReward, big.NewInt(2)) - t.Logf("minted = %d", minted) - t.Logf("reward = %d", annualReward) - } - for i := 2054; i < 2100; i += 2 { - minted = new(big.Int).Add(minted, new(big.Int).Mul(annualReward, big.NewInt(63115200))) - } - t.Logf("total minted = %d", minted) -} - -func TestHalvesPeriod(t *testing.T) { - halvesTime := big.NewInt(1719792000) // 2024-07-01 00:00:00 (UTC) - blockPeriod := big.NewInt(63_115_200) // 86400 * 730.5 - loc, _ := time.LoadLocation("UTC") - for i := 0; i < 17; i++ { - tm, _ := strconv.ParseInt(halvesTime.String(), 10, 64) - t.Logf("~ %v(%d)", time.Unix(tm, 0).In(loc), halvesTime) - halvesTime.Add(halvesTime, blockPeriod) - } -} - // TestDistributeRewards tests the DistributeRewards function func TestDistributeRewards(t *testing.T) { From bb64392962a0e10cb43bfe8da9e3252f4c3eb610 Mon Sep 17 00:00:00 2001 From: egonspace Date: Thu, 16 May 2024 14:22:20 +0900 Subject: [PATCH 03/51] fix: apply review; valdiate in consensus --- consensus/ethash/consensus.go | 15 +++++++++++++++ core/block_validator.go | 10 ---------- core/blockchain.go | 8 +------- core/blockchain_test.go | 8 +------- core/state_processor.go | 8 ++++---- core/types.go | 5 +---- eth/state_accessor.go | 2 +- wemix/admin_test.go | 3 ++- wemix/rewards_test.go | 3 ++- 9 files changed, 27 insertions(+), 35 deletions(-) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 4ab4413b8443..47c0aa230220 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -604,10 +604,25 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H // Finalize implements consensus.Engine, accumulating the block and uncle rewards, // setting the final state on the header func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) error { + var proposedReward []byte + if header.Rewards != nil { + // `accumulateRewards` updates `header.Rewards` field, + // so we save `header.Rewards` of proposed block before calling the function + // But if we're a miner and are making a block, the field should be nil. + proposedReward = header.Rewards + } + // Accumulate any block and uncle rewards and commit the final state root if err := accumulateRewards(chain.Config(), state, header, uncles); err != nil { return err } + + if proposedReward != nil { + // validate the rewards from the proposed block with calculated value locally + if !bytes.Equal(header.Rewards, proposedReward) { + return fmt.Errorf("invalid rewards (remote: %x local: %x)", proposedReward, header.Rewards) + } + } header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) return nil } diff --git a/core/block_validator.go b/core/block_validator.go index 7b5f8f8ad518..028beadc491a 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -17,7 +17,6 @@ package core import ( - "bytes" "fmt" "math/big" @@ -109,15 +108,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD return nil } -// ValidateReward validates the reward info of remote block with the reward processed locally -func (v *BlockValidator) ValidateReward(header *types.Header, localHeader *types.Header) error { - // verify rewards info - if !bytes.Equal(header.Rewards, localHeader.Rewards) { - return fmt.Errorf("invalid rewards (remote: %x local: %x)", header.Rewards, localHeader.Rewards) - } - return nil -} - // CalcGasLimit computes the gas limit of the next block after parent. It aims // to keep the baseline gas close to the provided target, and increase it towards // the target if the baseline gas is lower. diff --git a/core/blockchain.go b/core/blockchain.go index 8a570e7fa758..e5a6291ba581 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1636,7 +1636,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) // Process block using the parent state as reference point substart := time.Now() - appliedHeader, receipts, logs, usedGas, fees, err := bc.processor.Process(block, statedb, bc.vmConfig) + receipts, logs, usedGas, fees, err := bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { bc.reportBlock(block, receipts, err) atomic.StoreUint32(&followupInterrupt, 1) @@ -1662,12 +1662,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) atomic.StoreUint32(&followupInterrupt, 1) return it.index, err } - - if err := bc.validator.ValidateReward(block.Header(), appliedHeader); err != nil { - bc.reportBlock(block, receipts, err) - atomic.StoreUint32(&followupInterrupt, 1) - return it.index, err - } proctime := time.Since(start) // Update the metrics touched during block validation diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 568bc677ef29..03b70d26c803 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -159,7 +159,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { if err != nil { return err } - appliedHeader, receipts, _, usedGas, fees, err := blockchain.processor.Process(block, statedb, vm.Config{}) + receipts, _, usedGas, fees, err := blockchain.processor.Process(block, statedb, vm.Config{}) if err != nil { blockchain.reportBlock(block, receipts, err) return err @@ -171,12 +171,6 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { return err } - err = blockchain.validator.ValidateReward(block.Header(), appliedHeader) - if err != nil { - blockchain.reportBlock(block, receipts, err) - return err - } - blockchain.chainmu.MustLock() rawdb.WriteTd(blockchain.db, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTd(block.ParentHash(), block.NumberU64()-1))) rawdb.WriteBlock(blockchain.db, block) diff --git a/core/state_processor.go b/core/state_processor.go index 743d3d6f98ed..e2b2c1fc5efc 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -56,7 +56,7 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen // Process returns the receipts and logs accumulated during the process and // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. -func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*types.Header, types.Receipts, []*types.Log, uint64, *big.Int, error) { +func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, *big.Int, error) { var ( receipts types.Receipts usedGas = new(uint64) @@ -77,12 +77,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg for i, tx := range block.Transactions() { msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee) if err != nil { - return nil, nil, nil, 0, big.NewInt(0), fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) + return nil, nil, 0, big.NewInt(0), fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.Prepare(tx.Hash(), i) receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, fees, vmenv) if err != nil { - return nil, nil, nil, 0, big.NewInt(0), fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) + return nil, nil, 0, big.NewInt(0), fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) @@ -90,7 +90,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) - return header, receipts, allLogs, *usedGas, fees, nil + return receipts, allLogs, *usedGas, fees, nil } func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, fees *big.Int, evm *vm.EVM) (*types.Receipt, error) { diff --git a/core/types.go b/core/types.go index 3c565d1118cf..ae909a48fb1f 100644 --- a/core/types.go +++ b/core/types.go @@ -34,9 +34,6 @@ type Validator interface { // ValidateState validates the given statedb and optionally the receipts and // gas used. ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, fees *big.Int) error - - // ValidateReward validates the reward info of the block header with the reward processed in local - ValidateReward(header *types.Header, localHeader *types.Header) error } // Prefetcher is an interface for pre-caching transaction signatures and state. @@ -52,5 +49,5 @@ type Processor interface { // Process processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb and applying any rewards to both // the processor (coinbase) and any included uncles. - Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (*types.Header, types.Receipts, []*types.Log, uint64, *big.Int, error) + Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, *big.Int, error) } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 481909968fd0..98be012f3326 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -131,7 +131,7 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state if current = eth.blockchain.GetBlockByNumber(next); current == nil { return nil, fmt.Errorf("block #%d not found", next) } - _, _, _, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) + _, _, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) if err != nil { return nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err) } diff --git a/wemix/admin_test.go b/wemix/admin_test.go index d3c466f613e9..98b08f15852a 100644 --- a/wemix/admin_test.go +++ b/wemix/admin_test.go @@ -1,9 +1,10 @@ package wemix import ( - "github.com/ethereum/go-ethereum/params" "math/big" "testing" + + "github.com/ethereum/go-ethereum/params" ) func TestHalveRewards(t *testing.T) { diff --git a/wemix/rewards_test.go b/wemix/rewards_test.go index edd6ba2f9f2d..595be9ee03b4 100644 --- a/wemix/rewards_test.go +++ b/wemix/rewards_test.go @@ -4,9 +4,10 @@ package wemix import ( "encoding/json" - "github.com/ethereum/go-ethereum/common" "math/big" "testing" + + "github.com/ethereum/go-ethereum/common" ) // TestDistributeRewards tests the DistributeRewards function From 098f5e85a14eb46a21e678abd9c354e71fc92bab Mon Sep 17 00:00:00 2001 From: egonspace Date: Thu, 16 May 2024 16:00:58 +0900 Subject: [PATCH 04/51] fix: halving rate, fix ci-lint --- build/checksums.txt | 50 +++++++- build/ci.go | 2 +- consensus/ethash/consensus.go | 2 +- params/config.go | 13 ++- wemix/admin.go | 11 +- wemix/admin_test.go | 214 ++++++++++++++++++++++++++++------ 6 files changed, 241 insertions(+), 51 deletions(-) diff --git a/build/checksums.txt b/build/checksums.txt index 4b7056e119dd..64c7fa70e77c 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -33,4 +33,52 @@ e9cb6f691e62a4d8b28dd52d2eab57cca72acfd5083b3c5417a72d2eb64def09 golangci-lint- d058dfb0c7fbd73be70f285d3f8d4d424192fe9b19760ddbb0b2c4b743b8656c golangci-lint-1.49.0-windows-amd64.zip c049d80297228db7065eabeac5114f77f04415dcd9b944e8d7c6426d9dd6e9dd golangci-lint-1.49.0-windows-arm64.zip ec9164bab7134ddb94f51c17fd37c109b0801ecd5494b6c0e27ca7898fbd7469 golangci-lint-1.49.0-windows-armv6.zip -68fd9e880d98073f436c58b6f6d2c141881ef49b06ca31137bc19da4e4e3b996 golangci-lint-1.49.0-windows-armv7.zip \ No newline at end of file +68fd9e880d98073f436c58b6f6d2c141881ef49b06ca31137bc19da4e4e3b996 golangci-lint-1.49.0-windows-armv7.zip + +01301af199161c5ea33a0350581e1bed43289a56b2fbed7539f99fca2f898278 golangci-lint-1.54.2-freebsd-amd64.tar.gz +03f1962e95066105476b8eb88b5685a95aba8ee0b41f5e986f2a61a4e1834738 golangci-lint-1.54.2-linux-mips64le.tar.gz +0a57b225c621b465bd67b7cab87e9e13063704468eb382653b5c163ec23abaa4 golangci-lint-1.54.2-windows-armv6.zip +1762e02abd5d2d7997c04682d8efe9faaa23760fa73b8a50cffc57e68f1b1173 golangci-lint-1.54.2-linux-386.deb +17c9ca05253efe833d47f38caf670aad2202b5e6515879a99873fabd4c7452b3 golangci-lint-1.54.2-linux-amd64.tar.gz +18172629827a2d595fff6a9933d9d20dc8e8ec140ad00a38e4d5723dcb7ed305 golangci-lint-1.54.2-linux-armv6.deb +19b389bc965b1fc687087dc34f09e7188f582d106c88c6c506b384be1e6656f6 golangci-lint-1.54.2-linux-amd64.rpm +2268895575ac5921633c8dd94844dea5765f1011c7814bcb73429120849a8f67 golangci-lint-1.54.2-linux-mips64le.deb +2e1a11787b08137ba16c3be6ab87de3ef5de470758b7a42441497f259e8e5a1d golangci-lint-1.54.2-windows-386.zip +30e7440fa14e2a9f4a9b9b825c61c1d6858073c74ea0aba3b2d42f08a81f4c4b golangci-lint417421bc38ff51dc18a75aa132df94a67ea078b2af2d973cdf3b1badca4b58bc golangci-lint-1.54.2-linux-ppc64le.tar.gz +42eb5bf1c935eb98f6c9ee1ce282ca0abe48475ea6bc8f682967855bd0bc5bdc golangci-lint-1.54.2-linux-mips64.rpm +50aaf3eb9b51efd2cb8ebab91725fbb1fae55d3399b66b3733118facb5087828 golangci-lint-1.54.2-source.tar.gz +522d26f9f2fefa28cc229d4acdef47e436637b7c5eaec4426217afa9061825c0 golangci-lint-1.54.2-linux-ppc64le.deb +58e0cd3b77cf0d30f59be804796a7fcae96b9fbd80c0ca7c824ec4b09de804c0 golangci-lint-1.54.2-linux-386.rpm +6a324882e39b47939b8bec23f04449c730123c9d2ff771c3f40942ab37a26d8d golangci-lint-1.54.2-windows-arm64.zip +7038b5c5cd477efbb1c828fbdf075704033f96f33598d72765f23aa87c286583 golangci-lint-1.54.2-linux-arm64.rpm +78c9f1acc357b8f9ba2a57dac40d61a091299877b1eeef6d1599f8a8715c023e golangci-lint-1.54.2-linux-loong64.tar.gz +7b11ea9de9aad90e55c66434a8a4cd30da0792b45e12a4bb5fbfd684042176fe golangci-lint-1.54.2-freebsd-armv6.tar.gz +7b33fb1be2f26b7e3d1f3c10ce9b2b5ce6d13bb1d8468a4b2ba794f05b4445e1 golangci-lint-1.54.2-darwin-arm64.tar.gz +7ce3a9e62a8835907300830aa9ac3c2e8e424c2bf98a4dcfe7e5221bd0272a89 golangci-lint-1.54.2-linux-riscv64.rpm +7eda41281f5fd722f4b60c86259bd6ece5eeef08d94c73e55987b45763d5ac9f golangci-lint-1.54.2-freebsd-armv7.tar.gz +8125ce58581d795356a09c71f82ce4fb9368e06b7ce393676907661b62c1c55b golangci-lint-1.54.2-linux-riscv64.tar.gz +839b4b620f75d9d827ec4f7ed1cf592f730a3fc5c6e2bf01f64c03ddd8d4d76c golangci-lint-1.54.2-netbsd-386.tar.gz +85674f50113bb49ffae80733b4ad493c7b58a6031ee7ded3fda2a0ae1bf94c88 golangci-lint-1.54.2-linux-loong64.rpm +860e2ab2453e7fa81d28487b91b6e479d9414baa464abac8ce1bb8f203affeec golangci-lint-1.54.2-linux-s390x.deb +8b3e8c296a9714641961e87403e4865787f16bfdce6e1ea31d46978cfbdb64e7 golangci-lint-1.54.2-linux-arm64.deb +8e42c8204dc2441b5f6873032f1f674b6b6946042d759bc244194d14da8ee7c5 golangci-lint-1.54.2-linux-riscv64.deb +8e8754108de4d8accf6bf209780b8a31ffee0d04eff6393e5a3c84c84991cd39 golangci-lint-1.54.2-linux-s390x.tar.gz +8fc12d9ab18982968a568619290c02c6a9622e29eb475db8b6eac4c1ffc1121a golangci-lint-1.54.2-linux-mips64.deb +9124be2628a93e4d4a65bf48dd049f85c20d1236e66ac321169490745f5de20e golangci-lint-1.54.2-netbsd-armv6.tar.gz +925c4097eae9e035b0b052a66d0a149f861e2ab611a4e677c7ffd2d4e05b9b89 golangci-lint-1.54.2-darwin-amd64.tar.gz +9db1154c2bfdab52822afb7ea8d505ef9e3d519402258f93a9809f4b871b9446 golangci-lint-1.54.2-freebsd-386.tar.gz +9fadc9ed7fe9a2c3abcb9113a580004d3262dbdef0d44d4271d1b7ad89657e7b golangci-lint-1.54.2-linux-s390x.rpm +a0fb8740e9771ff0b96511b04017940ada4c3d1e07b2e3c246a5078514c1be9e golangci-lint-1.54.2-illumos-amd64.tar.gz +a47ed1a6473ff9ccd2cc29d85fc197b6718fad8afcec3ae804070002f5d5f8a8 golangci-lint-1.54.2-netbsd-amd64.tar.gz +a9f14b33473c65fcfbf411ec054b53a87dbb849f4e09ee438f1ee76dbf3f3d4e golangci-lint-1.54.2-linux-arm64.tar.gz +abf8e2164bca508ab68e520ca51e887ca26498ff4c57e904a27cce05b426c81d golangci-lint-1.54.2-lintae6c9e000cdac4f39b64d01b4e8091a1600d97ffccbd1883a342e4693aade68f golangci-lint-1.54.2-linux-mips64le.rpm +b6352e83cc781c5f7e7b74d1e0e6dc137a9a200c3e852bb14009c01b8b19a7b1 golangci-lint-1.54.2-linux-armv6.tar.gz +c3a693f657488a928fc0bdd76ea242b33e2b0e77748b1f31db8a85eb84cf7954 golangci-lint-1.54.2-linux-ppc64le.rpm +c5fd737f6e3c49e168ff764b48ad4c212131d933538aa5973a60d85b8d030926 golangci-lint-1.54.2-linux-armv7.tar.gz +ce17d122f3f93e0a9e52009d2c03cc1c1a1ae28338c2702a1f53eccd10a1afa3 golangci-lint-1.54.2-windows-amd64.zip +d00b58c3fea03e314b5f0f8680606781d3c3a3428e6a4c8645997d537acd1992 golangci-lint-1.54.2-linux-mips64.tar.gz +e3091e11f040a7177f6c227514b61301189fb1bf37f4fb9da2efa041456ab81d golangci-lint-1.54.2-linux-armv7.deb +e4cfe85c6e39b7dab9d8b7f668222d9066ee8f064cd3dbd4153d15b280d636f4 golangci-lint-1.54.2-netbsd-armv7.tar.gz +f0df36248c26e30f8dd516ffc0f2158d450df733f684ddd429e3aa2d5cc23bfb golangci-lint-1.54.2-linux-armv6.rpm +f2b801c93ccfbd3d17132360f632c0281f78e5780f02727115172a33afd0b08e golangci-lint-1.54.2-linux-loong64.deb +f67b8fa171605747da66f93892257337d7ae71be59ca7b07548555f025abe836 golangci-lint-1.54.2-linux-386.tar.gz diff --git a/build/ci.go b/build/ci.go index d6431ecd5fcc..8628af54cf37 100644 --- a/build/ci.go +++ b/build/ci.go @@ -343,7 +343,7 @@ func doLint(cmdline []string) { // downloadLinter downloads and unpacks golangci-lint. func downloadLinter(cachedir string) string { - const version = "1.49.0" + const version = "1.54.2" csdb := build.MustLoadChecksums("build/checksums.txt") arch := runtime.GOARCH diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 47c0aa230220..a2180e9b3e78 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -617,7 +617,7 @@ func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types. return err } - if proposedReward != nil { + if proposedReward != nil && chain.Config().IsBrioche(header.Number) { // validate the rewards from the proposed block with calculated value locally if !bytes.Equal(header.Rewards, proposedReward) { return fmt.Errorf("invalid rewards (remote: %x local: %x)", proposedReward, header.Rewards) diff --git a/params/config.go b/params/config.go index 34962e69d351..2a384d10ce3a 100644 --- a/params/config.go +++ b/params/config.go @@ -424,12 +424,13 @@ type EthashConfig struct{} // Brioche halving configuration type BriocheConfig struct { - // if the chain is on brioche hard fork, `RewardAmount` of gov contract is not used rather this `BlockReward` is used - BlockReward *big.Int `json:"blockReward,omitempty"` // if nil, then default block reward is 1e18 (=1 wemix) - FirstHalvingBlock *big.Int `json:"firstHalvingBlock,omitempty"` // if nil, then halving is not work. including this block - HalvingPeriod *big.Int `json:"halvingPeriod,omitempty"` // if nil, then halving is not work - HalvingTimes uint64 `json:"halvingTimes,omitempty"` // if 0, then no halving - NoRewardHereAfter *big.Int `json:"noRewardHereAfter,omitempty"` // if nil, block reward goes on endlessly + // if the chain is on brioche hard fork, `RewardAmount` of gov contract is not used rather this BlockReward is used + BlockReward *big.Int `json:"blockReward,omitempty"` // nil - use default block reward(1e18) + FirstHalvingBlock *big.Int `json:"firstHalvingBlock,omitempty"` // nil - halving is not work. including this block + HalvingPeriod *big.Int `json:"halvingPeriod,omitempty"` // nil - halving is not work + NoRewardHereafter *big.Int `json:"noRewardHereafter,omitempty"` // nil - block reward goes on endlessly + HalvingTimes uint64 `json:"halvingTimes,omitempty"` // 0 - no halving + HalvingRate uint32 `json:"halvingRate,omitempty"` // 0<=HalvingRate<=100; 0 - no reward on halving; 100 - no halving } // String implements the stringer interface, returning the consensus engine details. diff --git a/wemix/admin.go b/wemix/admin.go index e3e86cd450ec..a763eb1cad19 100644 --- a/wemix/admin.go +++ b/wemix/admin.go @@ -1216,8 +1216,8 @@ func getBriocheBlockReward(brioche *params.BriocheConfig, num *big.Int) *big.Int if brioche.BlockReward != nil { blockReward = big.NewInt(0).Set(brioche.BlockReward) } - if brioche.NoRewardHereAfter != nil && - brioche.NoRewardHereAfter.Cmp(num) <= 0 { + if brioche.NoRewardHereafter != nil && + brioche.NoRewardHereafter.Cmp(num) <= 0 { blockReward = big.NewInt(0) } else if brioche.FirstHalvingBlock != nil && brioche.HalvingPeriod != nil && @@ -1225,7 +1225,7 @@ func getBriocheBlockReward(brioche *params.BriocheConfig, num *big.Int) *big.Int num.Cmp(brioche.FirstHalvingBlock) >= 0 { past := big.NewInt(0).Set(num) past.Sub(past, brioche.FirstHalvingBlock) - blockReward = halveRewards(blockReward, brioche.HalvingPeriod, past, brioche.HalvingTimes) + blockReward = halveRewards(blockReward, brioche.HalvingPeriod, past, brioche.HalvingTimes, brioche.HalvingRate) } } return blockReward @@ -1235,11 +1235,12 @@ func calculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance return admin.calculateRewards(config, num, fees, addBalance) } -func halveRewards(baseReward *big.Int, halvePeriod *big.Int, pastBlocks *big.Int, halvingTimes uint64) *big.Int { +func halveRewards(baseReward *big.Int, halvePeriod *big.Int, pastBlocks *big.Int, halvingTimes uint64, halvingRate uint32) *big.Int { result := big.NewInt(0).Set(baseReward) past := big.NewInt(0).Set(pastBlocks) for ; halvingTimes > 0; halvingTimes-- { - result = result.Div(result, big.NewInt(2)) + result = result.Mul(result, big.NewInt(int64(halvingRate))) + result = result.Div(result, big.NewInt(100)) if past.Cmp(halvePeriod) < 0 { break } diff --git a/wemix/admin_test.go b/wemix/admin_test.go index 98b08f15852a..dcca75724a9a 100644 --- a/wemix/admin_test.go +++ b/wemix/admin_test.go @@ -13,45 +13,53 @@ func TestHalveRewards(t *testing.T) { period *big.Int past *big.Int times uint64 + rate uint32 expected *big.Int }{ // sample test - {big.NewInt(1e18), big.NewInt(100), big.NewInt(0), 4, big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(99), 4, big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 4, big.NewInt(25e16)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(101), 4, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(0), 4, 50, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(99), 4, 50, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 4, 50, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(101), 4, 50, big.NewInt(25e16)}, // times test - {big.NewInt(1e18), big.NewInt(100), big.NewInt(0), 0, big.NewInt(1e18)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 0, big.NewInt(1e18)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 1, big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, big.NewInt(25e16)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 3, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(0), 0, 50, big.NewInt(1e18)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 0, 50, big.NewInt(1e18)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 1, 50, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 50, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 3, 50, big.NewInt(25e16)}, + + // rate test + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 10, big.NewInt(1e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(200), 3, 10, big.NewInt(1e15)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 20, big.NewInt(4e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 30, big.NewInt(9e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 90, big.NewInt(81e16)}, // brioche halving test - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(0), 16, big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 - 1), 16, big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200), 16, big.NewInt(25e16)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200*2 - 1), 16, big.NewInt(25e16)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 2), 16, big.NewInt(125e15)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 3), 16, big.NewInt(625e14)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 4), 16, big.NewInt(3125e13)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 5), 16, big.NewInt(15625e12)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 6), 16, big.NewInt(78125e11)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 7), 16, big.NewInt(390625e10)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 8), 16, big.NewInt(1953125e9)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 9), 16, big.NewInt(9765625e8)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 10), 16, big.NewInt(48828125e7)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 11), 16, big.NewInt(244140625e6)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 12), 16, big.NewInt(1220703125e5)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 13), 16, big.NewInt(6103515625e4)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 14), 16, big.NewInt(30517578125e3)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 15), 16, big.NewInt(152587890625e2)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 15), 17, big.NewInt(152587890625e2)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(0), 16, 50, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 - 1), 16, 50, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200), 16, 50, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200*2 - 1), 16, 50, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 2), 16, 50, big.NewInt(125e15)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 3), 16, 50, big.NewInt(625e14)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 4), 16, 50, big.NewInt(3125e13)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 5), 16, 50, big.NewInt(15625e12)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 6), 16, 50, big.NewInt(78125e11)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 7), 16, 50, big.NewInt(390625e10)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 8), 16, 50, big.NewInt(1953125e9)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 9), 16, 50, big.NewInt(9765625e8)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 10), 16, 50, big.NewInt(48828125e7)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 11), 16, 50, big.NewInt(244140625e6)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 12), 16, 50, big.NewInt(1220703125e5)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 13), 16, 50, big.NewInt(6103515625e4)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 14), 16, 50, big.NewInt(30517578125e3)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 15), 16, 50, big.NewInt(152587890625e2)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 15), 17, 50, big.NewInt(152587890625e2)}, } for _, tc := range testcases { - halved := halveRewards(tc.reward, tc.period, tc.past, tc.times) + halved := halveRewards(tc.reward, tc.period, tc.past, tc.times, tc.rate) if tc.expected.Cmp(halved) != 0 { t.Errorf("halveRewards mismatched (expected=%v, actual=%v)", tc.expected, halved) } @@ -70,12 +78,25 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), HalvingTimes: 10, - NoRewardHereAfter: big.NewInt(101), + HalvingRate: 50, }, blockNum: big.NewInt(100), expected: big.NewInt(5e17), }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(201), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(200), + expected: big.NewInt(25e16), + }, // base block reward variations { @@ -83,8 +104,9 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(7e18), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), HalvingTimes: 10, - NoRewardHereAfter: big.NewInt(101), + HalvingRate: 50, }, blockNum: big.NewInt(100), expected: big.NewInt(35e17), @@ -94,8 +116,9 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(3), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), HalvingTimes: 10, - NoRewardHereAfter: big.NewInt(101), + HalvingRate: 50, }, blockNum: big.NewInt(100), expected: big.NewInt(1), @@ -105,8 +128,9 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(1), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), HalvingTimes: 10, - NoRewardHereAfter: big.NewInt(101), + HalvingRate: 50, }, blockNum: big.NewInt(100), expected: big.NewInt(0), @@ -116,8 +140,9 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: nil, // it will use the default block reward FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), HalvingTimes: 10, - NoRewardHereAfter: big.NewInt(101), + HalvingRate: 50, }, blockNum: big.NewInt(100), expected: big.NewInt(5e17), @@ -129,8 +154,9 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: nil, // it will use the default block reward FirstHalvingBlock: nil, HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), HalvingTimes: 10, - NoRewardHereAfter: big.NewInt(101), + HalvingRate: 50, }, blockNum: big.NewInt(100), expected: big.NewInt(1e18), @@ -140,8 +166,9 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: nil, + NoRewardHereafter: big.NewInt(101), HalvingTimes: 10, - NoRewardHereAfter: big.NewInt(101), + HalvingRate: 50, }, blockNum: big.NewInt(100), expected: big.NewInt(10), @@ -151,12 +178,125 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), HalvingTimes: 0, - NoRewardHereAfter: big.NewInt(101), + HalvingRate: 50, }, blockNum: big.NewInt(100), expected: big.NewInt(10), }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(200), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(99), // not yet halving time + expected: big.NewInt(10), + }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(200), + HalvingTimes: 10, + HalvingRate: 100, // no halving rate + }, + blockNum: big.NewInt(100), + expected: big.NewInt(10), + }, + + // no reward case + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(200), + HalvingTimes: 10, + HalvingRate: 0, // no reward + }, + blockNum: big.NewInt(100), + expected: big.NewInt(0), + }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(200), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(199), + expected: big.NewInt(5), + }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(200), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(200), + expected: big.NewInt(0), + }, + + // halving rate variations + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(1000), + HalvingTimes: 10, + HalvingRate: 10, + }, + blockNum: big.NewInt(100), + expected: big.NewInt(1e17), + }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(1000), + HalvingTimes: 10, + HalvingRate: 10, + }, + blockNum: big.NewInt(200), + expected: big.NewInt(1e16), + }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(1000), + HalvingTimes: 10, + HalvingRate: 1, + }, + blockNum: big.NewInt(300), + expected: big.NewInt(1e12), + }, + { + briocheConfig: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(1000), + HalvingTimes: 10, + HalvingRate: 99, + }, + blockNum: big.NewInt(300), + expected: big.NewInt(970299e12), + }, } for _, tc := range testcases { From c1bed51dcfd75892c1ff0c9862bce860182fb75d Mon Sep 17 00:00:00 2001 From: egonspace Date: Thu, 16 May 2024 18:18:08 +0900 Subject: [PATCH 05/51] fix: move halving logic to BriocheConfig --- core/blockchain_test.go | 26 ---- params/config.go | 43 +++++- params/config_test.go | 315 ++++++++++++++++++++++++++++++++++++++++ wemix/admin.go | 39 +---- wemix/admin_test.go | 308 --------------------------------------- 5 files changed, 359 insertions(+), 372 deletions(-) delete mode 100644 wemix/admin_test.go diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 03b70d26c803..cda30f0f5860 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -164,7 +164,6 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { blockchain.reportBlock(block, receipts, err) return err } - err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, fees) if err != nil { blockchain.reportBlock(block, receipts, err) @@ -3771,28 +3770,3 @@ func TestSetCanonical(t *testing.T) { chain.SetCanonical(canon[DefaultCacheConfig.TriesInMemory-1]) verify(canon[DefaultCacheConfig.TriesInMemory-1]) } - -func TestRewardValidation(t *testing.T) { - // Configure and generate a sample block chain - var ( - db = rawdb.NewMemoryDatabase() - key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - address = crypto.PubkeyToAddress(key.PublicKey) - funds = big.NewInt(1000000000) - deleteAddr = common.Address{1} - gspec = &Genesis{ - Config: ¶ms.ChainConfig{ChainID: big.NewInt(1), EIP150Block: big.NewInt(0), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}, - Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, - } - genesis = gspec.MustCommit(db) - ) - - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) - defer blockchain.Stop() - - blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 1, nil) - - if _, err := blockchain.InsertChain(blocks); err != nil { - t.Fatal(err) - } -} diff --git a/params/config.go b/params/config.go index 2a384d10ce3a..2e7c12fd9754 100644 --- a/params/config.go +++ b/params/config.go @@ -165,6 +165,9 @@ var ( BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(53_557_371), HalvingPeriod: big.NewInt(63_115_200), + NoRewardHereafter: big.NewInt(1_000_000_000), // TODO fix last reward block + HalvingTimes: 16, + HalvingRate: 50, }, } @@ -186,12 +189,15 @@ var ( LondonBlock: big.NewInt(0), PangyoBlock: big.NewInt(10_000_000), ApplepieBlock: big.NewInt(26_240_268), - BriocheBlock: big.NewInt(60_537_845), // 24-06-17 02:00:00 (UTC) expected + BriocheBlock: big.NewInt(60_537_845), // TODO fix hardfork date Ethash: new(EthashConfig), Brioche: &BriocheConfig{ BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(60_537_845), HalvingPeriod: big.NewInt(63_115_200), + NoRewardHereafter: big.NewInt(1_000_000_000), // TODO fix last reward block + HalvingTimes: 16, + HalvingRate: 50, }, } @@ -433,6 +439,41 @@ type BriocheConfig struct { HalvingRate uint32 `json:"halvingRate,omitempty"` // 0<=HalvingRate<=100; 0 - no reward on halving; 100 - no halving } +func (bc *BriocheConfig) GetBriocheBlockReward(defaultReward *big.Int, num *big.Int) *big.Int { + blockReward := big.NewInt(0).Set(defaultReward) // default brioche block reward + if bc != nil { + if bc.BlockReward != nil { + blockReward = big.NewInt(0).Set(bc.BlockReward) + } + if bc.NoRewardHereafter != nil && + bc.NoRewardHereafter.Cmp(num) <= 0 { + blockReward = big.NewInt(0) + } else if bc.FirstHalvingBlock != nil && + bc.HalvingPeriod != nil && + bc.HalvingTimes > 0 && + num.Cmp(bc.FirstHalvingBlock) >= 0 { + blockReward = bc.halveRewards(blockReward, num) + } + } + return blockReward +} + +func (bc *BriocheConfig) halveRewards(baseReward *big.Int, num *big.Int) *big.Int { + result := big.NewInt(0).Set(baseReward) + past := big.NewInt(0).Set(num) + past.Sub(past, bc.FirstHalvingBlock) + halvingTimes := bc.HalvingTimes + for ; halvingTimes > 0; halvingTimes-- { + result = result.Mul(result, big.NewInt(int64(bc.HalvingRate))) + result = result.Div(result, big.NewInt(100)) + if past.Cmp(bc.HalvingPeriod) < 0 { + break + } + past = past.Sub(past, bc.HalvingPeriod) + } + return result +} + // String implements the stringer interface, returning the consensus engine details. func (c *EthashConfig) String() string { return "ethash" diff --git a/params/config_test.go b/params/config_test.go index 3c8ebaf4a511..9e528f3cf0b1 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -96,3 +96,318 @@ func TestCheckCompatible(t *testing.T) { } } } + +func TestHalveRewards(t *testing.T) { + testcases := []struct { + reward *big.Int + period *big.Int + past *big.Int + times uint64 + rate uint32 + expected *big.Int + }{ + // sample test + {big.NewInt(1e18), big.NewInt(100), big.NewInt(0), 4, 50, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(99), 4, 50, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 4, 50, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(101), 4, 50, big.NewInt(25e16)}, + + // times test + {big.NewInt(1e18), big.NewInt(100), big.NewInt(0), 0, 50, big.NewInt(1e18)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 0, 50, big.NewInt(1e18)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 1, 50, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 50, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 3, 50, big.NewInt(25e16)}, + + // rate test + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 10, big.NewInt(1e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(200), 3, 10, big.NewInt(1e15)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 20, big.NewInt(4e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 30, big.NewInt(9e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 90, big.NewInt(81e16)}, + + // brioche halving test + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(0), 16, 50, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 - 1), 16, 50, big.NewInt(5e17)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200), 16, 50, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200*2 - 1), 16, 50, big.NewInt(25e16)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 2), 16, 50, big.NewInt(125e15)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 3), 16, 50, big.NewInt(625e14)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 4), 16, 50, big.NewInt(3125e13)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 5), 16, 50, big.NewInt(15625e12)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 6), 16, 50, big.NewInt(78125e11)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 7), 16, 50, big.NewInt(390625e10)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 8), 16, 50, big.NewInt(1953125e9)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 9), 16, 50, big.NewInt(9765625e8)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 10), 16, 50, big.NewInt(48828125e7)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 11), 16, 50, big.NewInt(244140625e6)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 12), 16, 50, big.NewInt(1220703125e5)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 13), 16, 50, big.NewInt(6103515625e4)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 14), 16, 50, big.NewInt(30517578125e3)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 15), 16, 50, big.NewInt(152587890625e2)}, + {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 15), 17, 50, big.NewInt(152587890625e2)}, + } + + for _, tc := range testcases { + brioche := &BriocheConfig{ + BlockReward: tc.reward, + FirstHalvingBlock: big.NewInt(0), + HalvingPeriod: tc.period, + HalvingTimes: tc.times, + HalvingRate: tc.rate, + } + halved := brioche.halveRewards(tc.reward, tc.period) + if tc.expected.Cmp(halved) != 0 { + t.Errorf("halveRewards mismatched (expected=%v, actual=%v)", tc.expected, halved) + } + } +} + +func TestGetBriocheBlockReward(t *testing.T) { + defaultBlockReward := big.NewInt(1234e14) + testcases := []struct { + briocheConfig *BriocheConfig + blockNum *big.Int + expected *big.Int + }{ + // nil case + { + briocheConfig: nil, + blockNum: big.NewInt(100), + expected: defaultBlockReward, + }, + + // normal case + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(100), + expected: big.NewInt(5e17), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(201), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(200), + expected: big.NewInt(25e16), + }, + + // base block reward variations + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(7e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(100), + expected: big.NewInt(35e17), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(3), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(100), + expected: big.NewInt(1), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(1), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(100), + expected: big.NewInt(0), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: nil, // it will use the default block reward + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(100), + expected: big.NewInt(5e17), + }, + + // no halving + { + briocheConfig: &BriocheConfig{ + BlockReward: nil, // it will use the default block reward + FirstHalvingBlock: nil, + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(100), + expected: big.NewInt(1e18), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: nil, + NoRewardHereafter: big.NewInt(101), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(100), + expected: big.NewInt(10), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(101), + HalvingTimes: 0, + HalvingRate: 50, + }, + blockNum: big.NewInt(100), + expected: big.NewInt(10), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(200), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(99), // not yet halving time + expected: big.NewInt(10), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(200), + HalvingTimes: 10, + HalvingRate: 100, // no halving rate + }, + blockNum: big.NewInt(100), + expected: big.NewInt(10), + }, + + // no reward case + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(200), + HalvingTimes: 10, + HalvingRate: 0, // no reward + }, + blockNum: big.NewInt(100), + expected: big.NewInt(0), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(200), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(199), + expected: big.NewInt(5), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(10), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(200), + HalvingTimes: 10, + HalvingRate: 50, + }, + blockNum: big.NewInt(200), + expected: big.NewInt(0), + }, + + // halving rate variations + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(1000), + HalvingTimes: 10, + HalvingRate: 10, + }, + blockNum: big.NewInt(100), + expected: big.NewInt(1e17), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(1000), + HalvingTimes: 10, + HalvingRate: 10, + }, + blockNum: big.NewInt(200), + expected: big.NewInt(1e16), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(1000), + HalvingTimes: 10, + HalvingRate: 1, + }, + blockNum: big.NewInt(300), + expected: big.NewInt(1e12), + }, + { + briocheConfig: &BriocheConfig{ + BlockReward: big.NewInt(1e18), + FirstHalvingBlock: big.NewInt(100), + HalvingPeriod: big.NewInt(100), + NoRewardHereafter: big.NewInt(1000), + HalvingTimes: 10, + HalvingRate: 99, + }, + blockNum: big.NewInt(300), + expected: big.NewInt(970299e12), + }, + } + + for _, tc := range testcases { + actual := tc.briocheConfig.GetBriocheBlockReward(defaultBlockReward, tc.blockNum) + if tc.expected.Cmp(actual) != 0 { + t.Errorf("getBriocheReward mismatched (expected=%v, actual=%v)", tc.expected, actual) + } + } +} diff --git a/wemix/admin.go b/wemix/admin.go index a763eb1cad19..65fbb4e3920a 100644 --- a/wemix/admin.go +++ b/wemix/admin.go @@ -127,7 +127,7 @@ var ( etcdClusterName = "Wemix" big0 = big.NewInt(0) nilAddress = common.Address{} - defaultBriocheBlockReward = int64(1e18) + defaultBriocheBlockReward = big.NewInt(1e18) admin *wemixAdmin ErrAlreadyRunning = errors.New("already running") @@ -1182,7 +1182,7 @@ func (ma *wemixAdmin) calculateRewards(config *params.ChainConfig, num, fees *bi var blockReward *big.Int if config.IsBrioche(num) { - blockReward = getBriocheBlockReward(config.Brioche, num) + blockReward = config.Brioche.GetBriocheBlockReward(defaultBriocheBlockReward, num) } else { // if the wemix chain is not on brioche hard fork, use the `rewardAmount` from gov contract blockReward = big.NewInt(0).Set(rp.rewardAmount) @@ -1210,45 +1210,10 @@ func (ma *wemixAdmin) calculateRewards(config *params.ChainConfig, num, fees *bi return } -func getBriocheBlockReward(brioche *params.BriocheConfig, num *big.Int) *big.Int { - blockReward := big.NewInt(defaultBriocheBlockReward) // default brioche block reward - if brioche != nil { - if brioche.BlockReward != nil { - blockReward = big.NewInt(0).Set(brioche.BlockReward) - } - if brioche.NoRewardHereafter != nil && - brioche.NoRewardHereafter.Cmp(num) <= 0 { - blockReward = big.NewInt(0) - } else if brioche.FirstHalvingBlock != nil && - brioche.HalvingPeriod != nil && - brioche.HalvingTimes > 0 && - num.Cmp(brioche.FirstHalvingBlock) >= 0 { - past := big.NewInt(0).Set(num) - past.Sub(past, brioche.FirstHalvingBlock) - blockReward = halveRewards(blockReward, brioche.HalvingPeriod, past, brioche.HalvingTimes, brioche.HalvingRate) - } - } - return blockReward -} - func calculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { return admin.calculateRewards(config, num, fees, addBalance) } -func halveRewards(baseReward *big.Int, halvePeriod *big.Int, pastBlocks *big.Int, halvingTimes uint64, halvingRate uint32) *big.Int { - result := big.NewInt(0).Set(baseReward) - past := big.NewInt(0).Set(pastBlocks) - for ; halvingTimes > 0; halvingTimes-- { - result = result.Mul(result, big.NewInt(int64(halvingRate))) - result = result.Div(result, big.NewInt(100)) - if past.Cmp(halvePeriod) < 0 { - break - } - past = past.Sub(past, halvePeriod) - } - return result -} - func verifyRewards(num *big.Int, rewards string) error { return nil //return admin.verifyRewards(num, rewards) diff --git a/wemix/admin_test.go b/wemix/admin_test.go deleted file mode 100644 index dcca75724a9a..000000000000 --- a/wemix/admin_test.go +++ /dev/null @@ -1,308 +0,0 @@ -package wemix - -import ( - "math/big" - "testing" - - "github.com/ethereum/go-ethereum/params" -) - -func TestHalveRewards(t *testing.T) { - testcases := []struct { - reward *big.Int - period *big.Int - past *big.Int - times uint64 - rate uint32 - expected *big.Int - }{ - // sample test - {big.NewInt(1e18), big.NewInt(100), big.NewInt(0), 4, 50, big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(99), 4, 50, big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 4, 50, big.NewInt(25e16)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(101), 4, 50, big.NewInt(25e16)}, - - // times test - {big.NewInt(1e18), big.NewInt(100), big.NewInt(0), 0, 50, big.NewInt(1e18)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 0, 50, big.NewInt(1e18)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 1, 50, big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 50, big.NewInt(25e16)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 3, 50, big.NewInt(25e16)}, - - // rate test - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 10, big.NewInt(1e16)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(200), 3, 10, big.NewInt(1e15)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 20, big.NewInt(4e16)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 30, big.NewInt(9e16)}, - {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 90, big.NewInt(81e16)}, - - // brioche halving test - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(0), 16, 50, big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 - 1), 16, 50, big.NewInt(5e17)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200), 16, 50, big.NewInt(25e16)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200*2 - 1), 16, 50, big.NewInt(25e16)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 2), 16, 50, big.NewInt(125e15)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 3), 16, 50, big.NewInt(625e14)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 4), 16, 50, big.NewInt(3125e13)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 5), 16, 50, big.NewInt(15625e12)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 6), 16, 50, big.NewInt(78125e11)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 7), 16, 50, big.NewInt(390625e10)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 8), 16, 50, big.NewInt(1953125e9)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 9), 16, 50, big.NewInt(9765625e8)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 10), 16, 50, big.NewInt(48828125e7)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 11), 16, 50, big.NewInt(244140625e6)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 12), 16, 50, big.NewInt(1220703125e5)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 13), 16, 50, big.NewInt(6103515625e4)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 14), 16, 50, big.NewInt(30517578125e3)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 15), 16, 50, big.NewInt(152587890625e2)}, - {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(63115200 * 15), 17, 50, big.NewInt(152587890625e2)}, - } - - for _, tc := range testcases { - halved := halveRewards(tc.reward, tc.period, tc.past, tc.times, tc.rate) - if tc.expected.Cmp(halved) != 0 { - t.Errorf("halveRewards mismatched (expected=%v, actual=%v)", tc.expected, halved) - } - } -} - -func TestGetBriocheBlockReward(t *testing.T) { - testcases := []struct { - briocheConfig *params.BriocheConfig - blockNum *big.Int - expected *big.Int - }{ - // normal case - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(1e18), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), - HalvingTimes: 10, - HalvingRate: 50, - }, - blockNum: big.NewInt(100), - expected: big.NewInt(5e17), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(1e18), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(201), - HalvingTimes: 10, - HalvingRate: 50, - }, - blockNum: big.NewInt(200), - expected: big.NewInt(25e16), - }, - - // base block reward variations - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(7e18), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), - HalvingTimes: 10, - HalvingRate: 50, - }, - blockNum: big.NewInt(100), - expected: big.NewInt(35e17), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(3), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), - HalvingTimes: 10, - HalvingRate: 50, - }, - blockNum: big.NewInt(100), - expected: big.NewInt(1), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(1), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), - HalvingTimes: 10, - HalvingRate: 50, - }, - blockNum: big.NewInt(100), - expected: big.NewInt(0), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: nil, // it will use the default block reward - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), - HalvingTimes: 10, - HalvingRate: 50, - }, - blockNum: big.NewInt(100), - expected: big.NewInt(5e17), - }, - - // no halving - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: nil, // it will use the default block reward - FirstHalvingBlock: nil, - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), - HalvingTimes: 10, - HalvingRate: 50, - }, - blockNum: big.NewInt(100), - expected: big.NewInt(1e18), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(10), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: nil, - NoRewardHereafter: big.NewInt(101), - HalvingTimes: 10, - HalvingRate: 50, - }, - blockNum: big.NewInt(100), - expected: big.NewInt(10), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(10), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), - HalvingTimes: 0, - HalvingRate: 50, - }, - blockNum: big.NewInt(100), - expected: big.NewInt(10), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(10), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(200), - HalvingTimes: 10, - HalvingRate: 50, - }, - blockNum: big.NewInt(99), // not yet halving time - expected: big.NewInt(10), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(10), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(200), - HalvingTimes: 10, - HalvingRate: 100, // no halving rate - }, - blockNum: big.NewInt(100), - expected: big.NewInt(10), - }, - - // no reward case - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(10), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(200), - HalvingTimes: 10, - HalvingRate: 0, // no reward - }, - blockNum: big.NewInt(100), - expected: big.NewInt(0), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(10), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(200), - HalvingTimes: 10, - HalvingRate: 50, - }, - blockNum: big.NewInt(199), - expected: big.NewInt(5), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(10), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(200), - HalvingTimes: 10, - HalvingRate: 50, - }, - blockNum: big.NewInt(200), - expected: big.NewInt(0), - }, - - // halving rate variations - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(1e18), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(1000), - HalvingTimes: 10, - HalvingRate: 10, - }, - blockNum: big.NewInt(100), - expected: big.NewInt(1e17), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(1e18), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(1000), - HalvingTimes: 10, - HalvingRate: 10, - }, - blockNum: big.NewInt(200), - expected: big.NewInt(1e16), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(1e18), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(1000), - HalvingTimes: 10, - HalvingRate: 1, - }, - blockNum: big.NewInt(300), - expected: big.NewInt(1e12), - }, - { - briocheConfig: ¶ms.BriocheConfig{ - BlockReward: big.NewInt(1e18), - FirstHalvingBlock: big.NewInt(100), - HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(1000), - HalvingTimes: 10, - HalvingRate: 99, - }, - blockNum: big.NewInt(300), - expected: big.NewInt(970299e12), - }, - } - - for _, tc := range testcases { - actual := getBriocheBlockReward(tc.briocheConfig, tc.blockNum) - if tc.expected.Cmp(actual) != 0 { - t.Errorf("getBriocheReward mismatched (expected=%v, actual=%v)", tc.expected, actual) - } - } -} From 8402eed731778ae336b9a8955adf684e404757f2 Mon Sep 17 00:00:00 2001 From: egonspace Date: Thu, 16 May 2024 18:43:29 +0900 Subject: [PATCH 06/51] fix: fix test --- params/config.go | 7 ++++--- params/config_test.go | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/params/config.go b/params/config.go index 2e7c12fd9754..b29acc9370f0 100644 --- a/params/config.go +++ b/params/config.go @@ -436,7 +436,7 @@ type BriocheConfig struct { HalvingPeriod *big.Int `json:"halvingPeriod,omitempty"` // nil - halving is not work NoRewardHereafter *big.Int `json:"noRewardHereafter,omitempty"` // nil - block reward goes on endlessly HalvingTimes uint64 `json:"halvingTimes,omitempty"` // 0 - no halving - HalvingRate uint32 `json:"halvingRate,omitempty"` // 0<=HalvingRate<=100; 0 - no reward on halving; 100 - no halving + HalvingRate uint32 `json:"halvingRate,omitempty"` // 0 - no reward on halving; 100 - no halving; >100 - increasing reward } func (bc *BriocheConfig) GetBriocheBlockReward(defaultReward *big.Int, num *big.Int) *big.Int { @@ -464,7 +464,7 @@ func (bc *BriocheConfig) halveRewards(baseReward *big.Int, num *big.Int) *big.In past.Sub(past, bc.FirstHalvingBlock) halvingTimes := bc.HalvingTimes for ; halvingTimes > 0; halvingTimes-- { - result = result.Mul(result, big.NewInt(int64(bc.HalvingRate))) + result = result.Mul(result, big.NewInt(int64(bc.HalvingRate))) // `HalvingRate` may be greater than 100 theoretically result = result.Div(result, big.NewInt(100)) if past.Cmp(bc.HalvingPeriod) < 0 { break @@ -807,7 +807,7 @@ type Rules struct { IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsBerlin, IsLondon bool IsMerge bool - IsPangyo, IsApplepie bool + IsPangyo, IsApplepie, IsBrioche bool } // Rules ensures c's ChainID is not nil. @@ -831,5 +831,6 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool) Rules { IsMerge: isMerge, IsPangyo: c.IsPangyo(num), IsApplepie: c.IsApplepie(num), + IsBrioche: c.IsBrioche(num), } } diff --git a/params/config_test.go b/params/config_test.go index 9e528f3cf0b1..db09c2ec700d 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -125,6 +125,7 @@ func TestHalveRewards(t *testing.T) { {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 20, big.NewInt(4e16)}, {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 30, big.NewInt(9e16)}, {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 90, big.NewInt(81e16)}, + {big.NewInt(1e18), big.NewInt(100), big.NewInt(100), 2, 200, big.NewInt(4e18)}, // brioche halving test {big.NewInt(1e18), big.NewInt(63115200), big.NewInt(0), 16, 50, big.NewInt(5e17)}, @@ -156,7 +157,7 @@ func TestHalveRewards(t *testing.T) { HalvingTimes: tc.times, HalvingRate: tc.rate, } - halved := brioche.halveRewards(tc.reward, tc.period) + halved := brioche.halveRewards(tc.reward, tc.past) if tc.expected.Cmp(halved) != 0 { t.Errorf("halveRewards mismatched (expected=%v, actual=%v)", tc.expected, halved) } From 1bddf95445179ef2032127b9c19fd3483cf7ff83 Mon Sep 17 00:00:00 2001 From: egonspace Date: Thu, 16 May 2024 18:48:54 +0900 Subject: [PATCH 07/51] fix: fix lint error --- wemix/rewards_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wemix/rewards_test.go b/wemix/rewards_test.go index 595be9ee03b4..69c8954d28a0 100644 --- a/wemix/rewards_test.go +++ b/wemix/rewards_test.go @@ -135,7 +135,7 @@ func TestDistributeRewards(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Call the distributeRewards function - rewards, err := distributeRewards(tt.height, tt.rp, big.NewInt(defaultBriocheBlockReward), tt.fees) + rewards, err := distributeRewards(tt.height, tt.rp, defaultBriocheBlockReward, tt.fees) rewardsString, _ := json.Marshal(rewards) if string(rewardsString) != tt.want { t.Errorf("distributeRewards() failed: %v, %v <-> %v", err, tt.want, string(rewardsString)) From 24c9a5a38f537cacc4a77419ec9a52dcce92ab21 Mon Sep 17 00:00:00 2001 From: egonspace Date: Fri, 17 May 2024 14:49:28 +0900 Subject: [PATCH 08/51] fix: refactoring reward validation --- consensus/beacon/consensus.go | 10 ++-- consensus/clique/clique.go | 8 ++- consensus/consensus.go | 6 ++- consensus/ethash/consensus.go | 40 ++++++++------- consensus/ethash/ethash.go | 4 ++ core/block_validator.go | 8 ++- core/blockchain.go | 4 +- core/blockchain_test.go | 4 +- core/chain_makers.go | 3 +- core/state_processor.go | 10 ++-- core/types.go | 4 +- eth/state_accessor.go | 2 +- params/config.go | 21 ++++---- params/config_test.go | 26 ++++++++-- wemix/admin.go | 26 +++++----- wemix/rewards_test.go | 94 ++++++++++++++++++++++++++++++++--- 16 files changed, 191 insertions(+), 79 deletions(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 3611093423bc..5f2b26d45b0a 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -167,6 +167,10 @@ func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Blo return nil } +func (beacon *Beacon) ValidateEngineSpecific(*params.ChainConfig, *types.Header, *big.Int, interface{}) error { + return nil +} + // verifyHeader checks whether a header conforms to the consensus rules of the // stock Ethereum consensus engine. The difference between the beacon and classic is // (a) The following fields are expected to be constants: @@ -265,17 +269,17 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H } // Finalize implements consensus.Engine, setting the final state on the header -func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) error { +func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) (interface{}, error) { // Finalize is different with Prepare, it can be used in both block generation // and verification. So determine the consensus rules by header type. if !beacon.IsPoSHeader(header) { beacon.ethone.Finalize(chain, header, state, txs, uncles) - return nil + return nil, nil } // The block reward is no longer handled here. It's done by the // external consensus engine. header.Root = state.IntermediateRoot(true) - return nil + return nil, nil } // FinalizeAndAssemble implements consensus.Engine, setting the final state and diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 5e9b27eb2503..81f72acdbf75 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -561,11 +561,11 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header // Finalize implements consensus.Engine, ensuring no uncles are set, nor block // rewards given. -func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) error { +func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) (interface{}, error) { // No block rewards in PoA, so the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) header.UncleHash = types.CalcUncleHash(nil) - return nil + return nil, nil } // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, @@ -578,6 +578,10 @@ func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header * return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), nil } +func (c *Clique) ValidateEngineSpecific(*params.ChainConfig, *types.Header, *big.Int, interface{}) error { + return nil +} + // Authorize injects a private key into the consensus engine to mint new blocks // with. func (c *Clique) Authorize(signer common.Address, signFn SignerFn) { diff --git a/consensus/consensus.go b/consensus/consensus.go index 482c280cce04..6098eb88ad7a 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -89,8 +89,9 @@ type Engine interface { // // Note: The block header and state database might be updated to reflect any // consensus rules that happen at finalization (e.g. block rewards). + // Finalize returns engine specific output which can be validated by ValidateEngineSpecific Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, - uncles []*types.Header) error + uncles []*types.Header) (interface{}, error) // FinalizeAndAssemble runs any post-transaction state modifications (e.g. block // rewards) and assembles the final block. @@ -100,6 +101,9 @@ type Engine interface { FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) + // ValidateEngineSpecific validates some header fields with processed output + ValidateEngineSpecific(config *params.ChainConfig, header *types.Header, blockFees *big.Int, output interface{}) error + // Seal generates a new sealing request for the given input block and pushes // the result into the given channel. // diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index a2180e9b3e78..82cb2e430938 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -603,35 +603,21 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H // Finalize implements consensus.Engine, accumulating the block and uncle rewards, // setting the final state on the header -func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) error { - var proposedReward []byte - if header.Rewards != nil { - // `accumulateRewards` updates `header.Rewards` field, - // so we save `header.Rewards` of proposed block before calling the function - // But if we're a miner and are making a block, the field should be nil. - proposedReward = header.Rewards - } - +func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) (interface{}, error) { // Accumulate any block and uncle rewards and commit the final state root if err := accumulateRewards(chain.Config(), state, header, uncles); err != nil { - return err + return nil, err } - if proposedReward != nil && chain.Config().IsBrioche(header.Number) { - // validate the rewards from the proposed block with calculated value locally - if !bytes.Equal(header.Rewards, proposedReward) { - return fmt.Errorf("invalid rewards (remote: %x local: %x)", proposedReward, header.Rewards) - } - } header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) - return nil + return &FinalizedOutput{reward: header.Rewards}, nil } // FinalizeAndAssemble implements consensus.Engine, accumulating the block and // uncle rewards, setting the final state and assembling the block. func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { // Finalize block - if err := ethash.Finalize(chain, header, state, txs, uncles); err != nil { + if _, err := ethash.Finalize(chain, header, state, txs, uncles); err != nil { return nil, err } @@ -650,6 +636,24 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil } +func (ethash *Ethash) ValidateEngineSpecific(config *params.ChainConfig, header *types.Header, blockFees *big.Int, output interface{}) error { + if !wemixminer.IsPoW() && header.Fees.Cmp(blockFees) != 0 { + return fmt.Errorf("invalid fees collected (remote: %v local: %v)", header.Fees, blockFees) + } + + if !wemixminer.IsPoW() && config.IsBrioche(header.Number) { + if out, ok := output.(*FinalizedOutput); ok { + // validate the rewards from the proposed block with calculated value locally + if !bytes.Equal(header.Rewards, out.reward) { + return fmt.Errorf("invalid rewards (remote: %x local: %x)", header.Rewards, out.reward) + } + } else { + return fmt.Errorf("invalid finalized output (%v)", output) + } + } + return nil +} + // SealHash returns the hash of a block prior to it being sealed. func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) { hasher := sha3.NewLegacyKeccak256() diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index c196ad062170..98c57f636f33 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -431,6 +431,10 @@ type Config struct { Log log.Logger `toml:"-"` } +type FinalizedOutput struct { + reward []byte +} + // Ethash is a consensus engine based on proof-of-work implementing the ethash // algorithm. type Ethash struct { diff --git a/core/block_validator.go b/core/block_validator.go index 028beadc491a..dff3e8dc1f1e 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -80,14 +80,11 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // transition, such as amount of used gas, the receipt roots and the state root // itself. ValidateState returns a database batch if the validation was a success // otherwise nil and an error is returned. -func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, fees *big.Int) error { +func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, fees *big.Int, finalizedOutput interface{}) error { header := block.Header() if block.GasUsed() != usedGas { return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) } - if !wemixminer.IsPoW() && block.Fees().Cmp(fees) != 0 { - return fmt.Errorf("invalid fees collected (remote: %v local: %v)", block.Fees(), fees) - } // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. @@ -105,7 +102,8 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root) } - return nil + + return v.engine.ValidateEngineSpecific(v.bc.chainConfig, header, fees, finalizedOutput) } // CalcGasLimit computes the gas limit of the next block after parent. It aims diff --git a/core/blockchain.go b/core/blockchain.go index e5a6291ba581..79bb7d3d065e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1636,7 +1636,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) // Process block using the parent state as reference point substart := time.Now() - receipts, logs, usedGas, fees, err := bc.processor.Process(block, statedb, bc.vmConfig) + receipts, logs, usedGas, fees, fo, err := bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { bc.reportBlock(block, receipts, err) atomic.StoreUint32(&followupInterrupt, 1) @@ -1657,7 +1657,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) // Validate the state using the default validator substart = time.Now() - if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, fees); err != nil { + if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, fees, fo); err != nil { bc.reportBlock(block, receipts, err) atomic.StoreUint32(&followupInterrupt, 1) return it.index, err diff --git a/core/blockchain_test.go b/core/blockchain_test.go index cda30f0f5860..eda7bbb30fba 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -159,12 +159,12 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { if err != nil { return err } - receipts, _, usedGas, fees, err := blockchain.processor.Process(block, statedb, vm.Config{}) + receipts, _, usedGas, fees, fo, err := blockchain.processor.Process(block, statedb, vm.Config{}) if err != nil { blockchain.reportBlock(block, receipts, err) return err } - err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, fees) + err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, fees, fo) if err != nil { blockchain.reportBlock(block, receipts, err) return err diff --git a/core/chain_makers.go b/core/chain_makers.go index db059c6e5071..a8a0437b9f7c 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -104,8 +104,7 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { b.SetCoinbase(common.Address{}) } b.statedb.Prepare(tx.Hash(), len(b.txs)) - fees := new(big.Int) - receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, fees, vm.Config{}) + receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, b.header.Fees, vm.Config{}) if err != nil { panic(err) } diff --git a/core/state_processor.go b/core/state_processor.go index e2b2c1fc5efc..42c0fc1615c5 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -56,7 +56,7 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen // Process returns the receipts and logs accumulated during the process and // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. -func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, *big.Int, error) { +func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, *big.Int, interface{}, error) { var ( receipts types.Receipts usedGas = new(uint64) @@ -77,20 +77,20 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg for i, tx := range block.Transactions() { msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee) if err != nil { - return nil, nil, 0, big.NewInt(0), fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) + return nil, nil, 0, big.NewInt(0), nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.Prepare(tx.Hash(), i) receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, fees, vmenv) if err != nil { - return nil, nil, 0, big.NewInt(0), fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) + return nil, nil, 0, big.NewInt(0), nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) + fo, err := p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) - return receipts, allLogs, *usedGas, fees, nil + return receipts, allLogs, *usedGas, fees, fo, err } func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, fees *big.Int, evm *vm.EVM) (*types.Receipt, error) { diff --git a/core/types.go b/core/types.go index ae909a48fb1f..2aa4fc15fb5a 100644 --- a/core/types.go +++ b/core/types.go @@ -33,7 +33,7 @@ type Validator interface { // ValidateState validates the given statedb and optionally the receipts and // gas used. - ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, fees *big.Int) error + ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, fees *big.Int, finalizedOutput interface{}) error } // Prefetcher is an interface for pre-caching transaction signatures and state. @@ -49,5 +49,5 @@ type Processor interface { // Process processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb and applying any rewards to both // the processor (coinbase) and any included uncles. - Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, *big.Int, error) + Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, *big.Int, interface{}, error) } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 98be012f3326..481909968fd0 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -131,7 +131,7 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state if current = eth.blockchain.GetBlockByNumber(next); current == nil { return nil, fmt.Errorf("block #%d not found", next) } - _, _, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) + _, _, _, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) if err != nil { return nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err) } diff --git a/params/config.go b/params/config.go index b29acc9370f0..27310d53256e 100644 --- a/params/config.go +++ b/params/config.go @@ -459,19 +459,16 @@ func (bc *BriocheConfig) GetBriocheBlockReward(defaultReward *big.Int, num *big. } func (bc *BriocheConfig) halveRewards(baseReward *big.Int, num *big.Int) *big.Int { - result := big.NewInt(0).Set(baseReward) - past := big.NewInt(0).Set(num) - past.Sub(past, bc.FirstHalvingBlock) - halvingTimes := bc.HalvingTimes - for ; halvingTimes > 0; halvingTimes-- { - result = result.Mul(result, big.NewInt(int64(bc.HalvingRate))) // `HalvingRate` may be greater than 100 theoretically - result = result.Div(result, big.NewInt(100)) - if past.Cmp(bc.HalvingPeriod) < 0 { - break - } - past = past.Sub(past, bc.HalvingPeriod) + elapsed := new(big.Int).Sub(num, bc.FirstHalvingBlock) + times := new(big.Int).Add(common.Big1, new(big.Int).Div(elapsed, bc.HalvingPeriod)) + if times.Uint64() > bc.HalvingTimes { + times = big.NewInt(int64(bc.HalvingTimes)) } - return result + + reward := new(big.Int).Set(baseReward) + numerator := new(big.Int).Exp(big.NewInt(int64(bc.HalvingRate)), times, nil) + denominator := new(big.Int).Exp(big.NewInt(100), times, nil) + return reward.Div(reward.Mul(reward, numerator), denominator) } // String implements the stringer interface, returning the consensus engine details. diff --git a/params/config_test.go b/params/config_test.go index db09c2ec700d..0db609be3209 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -167,12 +167,14 @@ func TestHalveRewards(t *testing.T) { func TestGetBriocheBlockReward(t *testing.T) { defaultBlockReward := big.NewInt(1234e14) testcases := []struct { + id int32 briocheConfig *BriocheConfig blockNum *big.Int expected *big.Int }{ // nil case { + id: 1, briocheConfig: nil, blockNum: big.NewInt(100), expected: defaultBlockReward, @@ -180,6 +182,7 @@ func TestGetBriocheBlockReward(t *testing.T) { // normal case { + id: 2, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), @@ -192,6 +195,7 @@ func TestGetBriocheBlockReward(t *testing.T) { expected: big.NewInt(5e17), }, { + id: 3, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), @@ -206,6 +210,7 @@ func TestGetBriocheBlockReward(t *testing.T) { // base block reward variations { + id: 4, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(7e18), FirstHalvingBlock: big.NewInt(100), @@ -218,6 +223,7 @@ func TestGetBriocheBlockReward(t *testing.T) { expected: big.NewInt(35e17), }, { + id: 5, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(3), FirstHalvingBlock: big.NewInt(100), @@ -230,6 +236,7 @@ func TestGetBriocheBlockReward(t *testing.T) { expected: big.NewInt(1), }, { + id: 6, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(1), FirstHalvingBlock: big.NewInt(100), @@ -242,6 +249,7 @@ func TestGetBriocheBlockReward(t *testing.T) { expected: big.NewInt(0), }, { + id: 7, briocheConfig: &BriocheConfig{ BlockReward: nil, // it will use the default block reward FirstHalvingBlock: big.NewInt(100), @@ -251,11 +259,12 @@ func TestGetBriocheBlockReward(t *testing.T) { HalvingRate: 50, }, blockNum: big.NewInt(100), - expected: big.NewInt(5e17), + expected: big.NewInt(0).Div(defaultBlockReward, big.NewInt(2)), }, // no halving { + id: 8, briocheConfig: &BriocheConfig{ BlockReward: nil, // it will use the default block reward FirstHalvingBlock: nil, @@ -265,9 +274,10 @@ func TestGetBriocheBlockReward(t *testing.T) { HalvingRate: 50, }, blockNum: big.NewInt(100), - expected: big.NewInt(1e18), + expected: defaultBlockReward, }, { + id: 9, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), @@ -280,6 +290,7 @@ func TestGetBriocheBlockReward(t *testing.T) { expected: big.NewInt(10), }, { + id: 10, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), @@ -292,6 +303,7 @@ func TestGetBriocheBlockReward(t *testing.T) { expected: big.NewInt(10), }, { + id: 11, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), @@ -304,6 +316,7 @@ func TestGetBriocheBlockReward(t *testing.T) { expected: big.NewInt(10), }, { + id: 12, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), @@ -318,6 +331,7 @@ func TestGetBriocheBlockReward(t *testing.T) { // no reward case { + id: 13, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), @@ -330,6 +344,7 @@ func TestGetBriocheBlockReward(t *testing.T) { expected: big.NewInt(0), }, { + id: 14, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), @@ -342,6 +357,7 @@ func TestGetBriocheBlockReward(t *testing.T) { expected: big.NewInt(5), }, { + id: 15, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), @@ -356,6 +372,7 @@ func TestGetBriocheBlockReward(t *testing.T) { // halving rate variations { + id: 16, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), @@ -368,6 +385,7 @@ func TestGetBriocheBlockReward(t *testing.T) { expected: big.NewInt(1e17), }, { + id: 17, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), @@ -380,6 +398,7 @@ func TestGetBriocheBlockReward(t *testing.T) { expected: big.NewInt(1e16), }, { + id: 18, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), @@ -392,6 +411,7 @@ func TestGetBriocheBlockReward(t *testing.T) { expected: big.NewInt(1e12), }, { + id: 19, briocheConfig: &BriocheConfig{ BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), @@ -408,7 +428,7 @@ func TestGetBriocheBlockReward(t *testing.T) { for _, tc := range testcases { actual := tc.briocheConfig.GetBriocheBlockReward(defaultBlockReward, tc.blockNum) if tc.expected.Cmp(actual) != 0 { - t.Errorf("getBriocheReward mismatched (expected=%v, actual=%v)", tc.expected, actual) + t.Errorf("getBriocheReward mismatched (id=%d, expected=%v, actual=%v)", tc.id, tc.expected, actual) } } } diff --git a/wemix/admin.go b/wemix/admin.go index 65fbb4e3920a..b3b0a92e1191 100644 --- a/wemix/admin.go +++ b/wemix/admin.go @@ -1147,17 +1147,7 @@ func distributeRewards(height *big.Int, rp *rewardParameters, blockReward *big.I return rewards, nil } -func (ma *wemixAdmin) calculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (coinbase *common.Address, rewards []byte, err error) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - rp, err := ma.getRewardParams(ctx, big.NewInt(num.Int64()-1)) - if err != nil { - // all goes to the coinbase - err = wemixminer.ErrNotInitialized - return - } - +func calculateRewardsWithParams(config *params.ChainConfig, rp *rewardParameters, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (coinbase *common.Address, rewards []byte, err error) { if (rp.staker == nil && rp.ecoSystem == nil && rp.maintenance == nil) || len(rp.members) == 0 { // handle testnet block 94 rewards if rewards94 := handleBlock94Rewards(num, rp, fees); rewards94 != nil { @@ -1175,7 +1165,7 @@ func (ma *wemixAdmin) calculateRewards(config *params.ChainConfig, num, fees *bi // determine coinbase if len(rp.members) > 0 { - mix := int(num.Int64()/ma.blocksPer) % len(rp.members) + mix := int(num.Int64()/rp.blocksPer) % len(rp.members) coinbase = &common.Address{} coinbase.SetBytes(rp.members[mix].Reward.Bytes()) } @@ -1211,7 +1201,17 @@ func (ma *wemixAdmin) calculateRewards(config *params.ChainConfig, num, fees *bi } func calculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { - return admin.calculateRewards(config, num, fees, addBalance) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + rp, err := admin.getRewardParams(ctx, big.NewInt(num.Int64()-1)) + if err != nil { + // all goes to the coinbase + err = wemixminer.ErrNotInitialized + return nil, nil, err + } + + return calculateRewardsWithParams(config, rp, num, fees, addBalance) } func verifyRewards(num *big.Int, rewards string) error { diff --git a/wemix/rewards_test.go b/wemix/rewards_test.go index 69c8954d28a0..3b4d33e4c47e 100644 --- a/wemix/rewards_test.go +++ b/wemix/rewards_test.go @@ -8,8 +8,23 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/consensus/ethash" + "github.com/ethereum/go-ethereum/core" + "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" + wemixminer "github.com/ethereum/go-ethereum/wemix/miner" ) +func hexToBigInt(hexNum string) *big.Int { + if num, ok := new(big.Int).SetString(hexNum[2:], 16); ok { + return num + } else { + return nil + } +} + // TestDistributeRewards tests the DistributeRewards function func TestDistributeRewards(t *testing.T) { @@ -18,14 +33,6 @@ func TestDistributeRewards(t *testing.T) { return &address } - hexToBigInt := func(hexNum string) *big.Int { - if num, ok := new(big.Int).SetString(hexNum[2:], 16); ok { - return num - } else { - return nil - } - } - // Test cases tests := []struct { name string @@ -168,4 +175,75 @@ func TestDistributeRewards(t *testing.T) { } } +func calculateRewardsForTest(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { + rp := &rewardParameters{ + rewardAmount: big.NewInt(1e18), + staker: &common.Address{0x11}, + ecoSystem: &common.Address{0x22}, + maintenance: &common.Address{0x33}, + feeCollector: &common.Address{0x44}, + members: []*wemixMember{ + { + Staker: common.HexToAddress("0x02b4b2d83786c8ee315db2ddac704794850d2149"), + Reward: common.HexToAddress("0x02b4b2d83786c8ee315db2ddac704794850d2149"), + Stake: hexToBigInt("0x1a784379d99db42000000"), + }, + { + Staker: common.HexToAddress("0xb16d2494fddfa4c000deaf642d47673e5ca74e07"), + Reward: common.HexToAddress("0xb16d2494fddfa4c000deaf642d47673e5ca74e07"), + Stake: hexToBigInt("0xe8ef1e96ae3897800000"), + }, + { + Staker: common.HexToAddress("0x452893ed818c0e3ea6f415aeab8ef08778087fc6"), + Reward: common.HexToAddress("0x452893ed818c0e3ea6f415aeab8ef08778087fc6"), + Stake: hexToBigInt("0xc92b9a6adc4825c00000"), + }, + }, + blocksPer: 1, + distributionMethod: []*big.Int{big.NewInt(4000), big.NewInt(1000), big.NewInt(2500), big.NewInt(2500)}, + } + + return calculateRewardsWithParams(config, rp, num, fees, addBalance) +} + +func TestRewardValidation(t *testing.T) { + // use wemix consensus + params.ConsensusMethod = params.ConsensusPoA + wemixminer.CalculateRewardsFunc = calculateRewardsForTest + + var ( + db = rawdb.NewMemoryDatabase() + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(1000000000) + deleteAddr = common.Address{1} + gspec = &core.Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + Brioche: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(100), + FirstHalvingBlock: big.NewInt(0), + HalvingPeriod: big.NewInt(10), + NoRewardHereafter: big.NewInt(30), + HalvingTimes: 3, + HalvingRate: 50, + }}, + Alloc: core.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: big.NewInt(0)}}, + } + genesis = gspec.MustCommit(db) + ) + + blockchain, _ := core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + defer blockchain.Stop() + + gspec.Config.Brioche.BlockReward = big.NewInt(200) + // TODO: core.GenerateChain does not make a wemix block including Fees, Rewards etc. + // TODO: implement wemix.GenerateChain function + blocks, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 1, nil) + + if _, err := blockchain.InsertChain(blocks); err != nil { + t.Fatal(err) + } +} + // EOF From 4fb0f5be0296648d10a7682aacafe5441807756d Mon Sep 17 00:00:00 2001 From: egonspace Date: Fri, 17 May 2024 17:13:50 +0900 Subject: [PATCH 09/51] test: reward validation --- core/block_validator.go | 9 ++- core/chain_makers.go | 9 ++- wemix/rewards_test.go | 123 ++++++++++++++++++++++++++++------------ 3 files changed, 104 insertions(+), 37 deletions(-) diff --git a/core/block_validator.go b/core/block_validator.go index dff3e8dc1f1e..fa01fa8e1a9f 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -97,13 +97,20 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD if receiptSha != header.ReceiptHash { return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) } + + // validate engine specific; ethash.engine validate the fees and rewards + err := v.engine.ValidateEngineSpecific(v.bc.chainConfig, header, fees, finalizedOutput) + if err != nil { + return err + } + // Validate the state root against the received state root and throw // an error if they don't match. if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { return fmt.Errorf("invalid merkle root (remote: %x local: %x)", header.Root, root) } - return v.engine.ValidateEngineSpecific(v.bc.chainConfig, header, fees, finalizedOutput) + return nil } // CalcGasLimit computes the gas limit of the next block after parent. It aims diff --git a/core/chain_makers.go b/core/chain_makers.go index a8a0437b9f7c..0f4dea2c9b06 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -104,7 +104,13 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { b.SetCoinbase(common.Address{}) } b.statedb.Prepare(tx.Hash(), len(b.txs)) - receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, b.header.Fees, vm.Config{}) + var fees *big.Int + if b.header.Fees != nil { + fees = b.header.Fees // wemix block has `Fees` field + } else { + fees = new(big.Int) + } + receipt, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, fees, vm.Config{}) if err != nil { panic(err) } @@ -303,6 +309,7 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S }), GasLimit: parent.GasLimit(), Number: new(big.Int).Add(parent.Number(), common.Big1), + Fees: new(big.Int), Time: time, } if chain.Config().IsLondon(header.Number) { diff --git a/wemix/rewards_test.go b/wemix/rewards_test.go index 3b4d33e4c47e..f8a6fff8c133 100644 --- a/wemix/rewards_test.go +++ b/wemix/rewards_test.go @@ -3,14 +3,18 @@ package wemix import ( + "bytes" + "crypto/ecdsa" "encoding/json" "math/big" + "strings" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/ethash" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" @@ -175,51 +179,51 @@ func TestDistributeRewards(t *testing.T) { } } -func calculateRewardsForTest(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { - rp := &rewardParameters{ - rewardAmount: big.NewInt(1e18), - staker: &common.Address{0x11}, - ecoSystem: &common.Address{0x22}, - maintenance: &common.Address{0x33}, - feeCollector: &common.Address{0x44}, - members: []*wemixMember{ - { - Staker: common.HexToAddress("0x02b4b2d83786c8ee315db2ddac704794850d2149"), - Reward: common.HexToAddress("0x02b4b2d83786c8ee315db2ddac704794850d2149"), - Stake: hexToBigInt("0x1a784379d99db42000000"), - }, - { - Staker: common.HexToAddress("0xb16d2494fddfa4c000deaf642d47673e5ca74e07"), - Reward: common.HexToAddress("0xb16d2494fddfa4c000deaf642d47673e5ca74e07"), - Stake: hexToBigInt("0xe8ef1e96ae3897800000"), - }, - { - Staker: common.HexToAddress("0x452893ed818c0e3ea6f415aeab8ef08778087fc6"), - Reward: common.HexToAddress("0x452893ed818c0e3ea6f415aeab8ef08778087fc6"), - Stake: hexToBigInt("0xc92b9a6adc4825c00000"), - }, - }, - blocksPer: 1, - distributionMethod: []*big.Int{big.NewInt(4000), big.NewInt(1000), big.NewInt(2500), big.NewInt(2500)}, +func makeCalculateRewardFunc(rp *rewardParameters) func(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { + return func(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { + return calculateRewardsWithParams(config, rp, num, fees, addBalance) } +} - return calculateRewardsWithParams(config, rp, num, fees, addBalance) +func makeSignBlockFunc(privateKey *ecdsa.PrivateKey) func(height *big.Int, hash common.Hash) (common.Address, []byte, error) { + return func(height *big.Int, hash common.Hash) (coinbase common.Address, sig []byte, err error) { + data := append(height.Bytes(), hash.Bytes()...) + data = crypto.Keccak256(data) + sig, _ = crypto.Sign(data, privateKey) + return crypto.PubkeyToAddress(privateKey.PublicKey), sig, nil + } +} + +func verifyBlockSigForTest(height *big.Int, coinbase common.Address, nodeId []byte, hash common.Hash, sig []byte, checkMinerLimit bool) bool { + var data []byte + data = append(height.Bytes(), hash.Bytes()...) + data = crypto.Keccak256(data) + pubKey, err := crypto.SigToPub(data, sig) + if err != nil { + return false + } + signer := crypto.PubkeyToAddress(*pubKey) + if err != nil || !bytes.Equal(coinbase.Bytes(), signer.Bytes()) { + return false + } + return true } func TestRewardValidation(t *testing.T) { // use wemix consensus params.ConsensusMethod = params.ConsensusPoA - wemixminer.CalculateRewardsFunc = calculateRewardsForTest var ( db = rawdb.NewMemoryDatabase() key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") address = crypto.PubkeyToAddress(key.PublicKey) - funds = big.NewInt(1000000000) + funds = big.NewInt(100000000000000) deleteAddr = common.Address{1} gspec = &core.Genesis{ Config: ¶ms.ChainConfig{ - ChainID: big.NewInt(1), + ChainID: big.NewInt(1), + LondonBlock: common.Big0, + BriocheBlock: common.Big0, Brioche: ¶ms.BriocheConfig{ BlockReward: big.NewInt(100), FirstHalvingBlock: big.NewInt(0), @@ -231,18 +235,67 @@ func TestRewardValidation(t *testing.T) { Alloc: core.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: big.NewInt(0)}}, } genesis = gspec.MustCommit(db) + signer = types.LatestSigner(gspec.Config) ) + rp := &rewardParameters{ + rewardAmount: big.NewInt(1e18), + staker: &common.Address{0x11}, + ecoSystem: &common.Address{0x22}, + maintenance: &common.Address{0x33}, + feeCollector: &common.Address{0x44}, + members: []*wemixMember{ + { + Staker: common.HexToAddress("0x02b4b2d83786c8ee315db2ddac704794850d2149"), + Reward: common.HexToAddress("0x02b4b2d83786c8ee315db2ddac704794850d2149"), + Stake: hexToBigInt("0x1a784379d99db42000000"), + }, + { + Staker: common.HexToAddress("0xb16d2494fddfa4c000deaf642d47673e5ca74e07"), + Reward: common.HexToAddress("0xb16d2494fddfa4c000deaf642d47673e5ca74e07"), + Stake: hexToBigInt("0xe8ef1e96ae3897800000"), + }, + { + Staker: common.HexToAddress("0x452893ed818c0e3ea6f415aeab8ef08778087fc6"), + Reward: common.HexToAddress("0x452893ed818c0e3ea6f415aeab8ef08778087fc6"), + Stake: hexToBigInt("0xc92b9a6adc4825c00000"), + }, + }, + blocksPer: 1, + distributionMethod: []*big.Int{big.NewInt(4000), big.NewInt(1000), big.NewInt(2500), big.NewInt(2500)}, + } + + wemixminer.CalculateRewardsFunc = makeCalculateRewardFunc(rp) + wemixminer.SignBlockFunc = makeSignBlockFunc(key) + wemixminer.VerifyBlockSigFunc = verifyBlockSigForTest + blockchain, _ := core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) defer blockchain.Stop() - gspec.Config.Brioche.BlockReward = big.NewInt(200) - // TODO: core.GenerateChain does not make a wemix block including Fees, Rewards etc. - // TODO: implement wemix.GenerateChain function - blocks, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 1, nil) + byzantineConfig := ¶ms.ChainConfig{ + ChainID: gspec.Config.ChainID, + LondonBlock: gspec.Config.LondonBlock, + BriocheBlock: gspec.Config.BriocheBlock, + Brioche: ¶ms.BriocheConfig{ + BlockReward: big.NewInt(200), // different reward!! + FirstHalvingBlock: gspec.Config.Brioche.FirstHalvingBlock, + HalvingPeriod: gspec.Config.Brioche.HalvingPeriod, + NoRewardHereafter: gspec.Config.Brioche.NoRewardHereafter, + HalvingTimes: gspec.Config.Brioche.HalvingTimes, + HalvingRate: gspec.Config.Brioche.HalvingRate, + }} + blocks, _ := core.GenerateChain(byzantineConfig, genesis, ethash.NewFaker(), db, 1, func(i int, gen *core.BlockGen) { + tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1), params.TxGas, gen.BaseFee(), nil), signer, key) + if err != nil { + panic(err) + } + gen.AddTx(tx) + }) if _, err := blockchain.InsertChain(blocks); err != nil { - t.Fatal(err) + if !strings.HasPrefix(err.Error(), "invalid rewards") { + t.Fatal(err) + } } } From ff062d2024d3f9b319e6f54a8f774fa67871ec95 Mon Sep 17 00:00:00 2001 From: egonspace Date: Mon, 20 May 2024 16:30:15 +0900 Subject: [PATCH 10/51] test: add hardfork test --- consensus/beacon/consensus.go | 6 +- consensus/clique/clique.go | 4 +- consensus/consensus.go | 5 +- consensus/ethash/consensus.go | 31 ++------- consensus/ethash/ethash.go | 4 -- core/block_validator.go | 9 +-- core/blockchain.go | 4 +- core/blockchain_test.go | 4 +- core/state_processor.go | 16 +++-- core/types.go | 6 +- eth/state_accessor.go | 2 +- wemix/rewards_test.go | 124 +++++++++++++++++++++++++++++++++- 12 files changed, 153 insertions(+), 62 deletions(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index 5f2b26d45b0a..aaac10652c03 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -269,17 +269,17 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H } // Finalize implements consensus.Engine, setting the final state on the header -func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) (interface{}, error) { +func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) error { // Finalize is different with Prepare, it can be used in both block generation // and verification. So determine the consensus rules by header type. if !beacon.IsPoSHeader(header) { beacon.ethone.Finalize(chain, header, state, txs, uncles) - return nil, nil + return nil } // The block reward is no longer handled here. It's done by the // external consensus engine. header.Root = state.IntermediateRoot(true) - return nil, nil + return nil } // FinalizeAndAssemble implements consensus.Engine, setting the final state and diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 81f72acdbf75..86164b3067a3 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -561,11 +561,11 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header // Finalize implements consensus.Engine, ensuring no uncles are set, nor block // rewards given. -func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) (interface{}, error) { +func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) error { // No block rewards in PoA, so the state remains as is and uncles are dropped header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) header.UncleHash = types.CalcUncleHash(nil) - return nil, nil + return nil } // FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set, diff --git a/consensus/consensus.go b/consensus/consensus.go index 6098eb88ad7a..43d5f29661eb 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -91,7 +91,7 @@ type Engine interface { // consensus rules that happen at finalization (e.g. block rewards). // Finalize returns engine specific output which can be validated by ValidateEngineSpecific Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, - uncles []*types.Header) (interface{}, error) + uncles []*types.Header) error // FinalizeAndAssemble runs any post-transaction state modifications (e.g. block // rewards) and assembles the final block. @@ -101,9 +101,6 @@ type Engine interface { FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) - // ValidateEngineSpecific validates some header fields with processed output - ValidateEngineSpecific(config *params.ChainConfig, header *types.Header, blockFees *big.Int, output interface{}) error - // Seal generates a new sealing request for the given input block and pushes // the result into the given channel. // diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 82cb2e430938..72a25ff51c42 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -603,21 +603,21 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H // Finalize implements consensus.Engine, accumulating the block and uncle rewards, // setting the final state on the header -func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) (interface{}, error) { +func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) error { // Accumulate any block and uncle rewards and commit the final state root if err := accumulateRewards(chain.Config(), state, header, uncles); err != nil { - return nil, err + return err } header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) - return &FinalizedOutput{reward: header.Rewards}, nil + return nil } // FinalizeAndAssemble implements consensus.Engine, accumulating the block and // uncle rewards, setting the final state and assembling the block. func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { // Finalize block - if _, err := ethash.Finalize(chain, header, state, txs, uncles); err != nil { + if err := ethash.Finalize(chain, header, state, txs, uncles); err != nil { return nil, err } @@ -636,24 +636,6 @@ func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea return types.NewBlock(header, txs, uncles, receipts, trie.NewStackTrie(nil)), nil } -func (ethash *Ethash) ValidateEngineSpecific(config *params.ChainConfig, header *types.Header, blockFees *big.Int, output interface{}) error { - if !wemixminer.IsPoW() && header.Fees.Cmp(blockFees) != 0 { - return fmt.Errorf("invalid fees collected (remote: %v local: %v)", header.Fees, blockFees) - } - - if !wemixminer.IsPoW() && config.IsBrioche(header.Number) { - if out, ok := output.(*FinalizedOutput); ok { - // validate the rewards from the proposed block with calculated value locally - if !bytes.Equal(header.Rewards, out.reward) { - return fmt.Errorf("invalid rewards (remote: %x local: %x)", header.Rewards, out.reward) - } - } else { - return fmt.Errorf("invalid finalized output (%v)", output) - } - } - return nil -} - // SealHash returns the hash of a block prior to it being sealed. func (ethash *Ethash) SealHash(header *types.Header) (hash common.Hash) { hasher := sha3.NewLegacyKeccak256() @@ -716,16 +698,13 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header } state.AddBalance(header.Coinbase, reward) } else { - coinbase, rewards, err := wemixminer.CalculateRewards( + _, rewards, err := wemixminer.CalculateRewards( config, header.Number, header.Fees, func(addr common.Address, amt *big.Int) { state.AddBalance(addr, amt) }) if err == nil { header.Rewards = rewards - if coinbase != nil { - header.Coinbase = *coinbase - } } else { if err == wemixminer.ErrNotInitialized { reward := new(big.Int) diff --git a/consensus/ethash/ethash.go b/consensus/ethash/ethash.go index 98c57f636f33..c196ad062170 100644 --- a/consensus/ethash/ethash.go +++ b/consensus/ethash/ethash.go @@ -431,10 +431,6 @@ type Config struct { Log log.Logger `toml:"-"` } -type FinalizedOutput struct { - reward []byte -} - // Ethash is a consensus engine based on proof-of-work implementing the ethash // algorithm. type Ethash struct { diff --git a/core/block_validator.go b/core/block_validator.go index fa01fa8e1a9f..1bc13d8a2694 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -18,7 +18,6 @@ package core import ( "fmt" - "math/big" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" @@ -80,7 +79,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // transition, such as amount of used gas, the receipt roots and the state root // itself. ValidateState returns a database batch if the validation was a success // otherwise nil and an error is returned. -func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64, fees *big.Int, finalizedOutput interface{}) error { +func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error { header := block.Header() if block.GasUsed() != usedGas { return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) @@ -98,12 +97,6 @@ func (v *BlockValidator) ValidateState(block *types.Block, statedb *state.StateD return fmt.Errorf("invalid receipt root hash (remote: %x local: %x)", header.ReceiptHash, receiptSha) } - // validate engine specific; ethash.engine validate the fees and rewards - err := v.engine.ValidateEngineSpecific(v.bc.chainConfig, header, fees, finalizedOutput) - if err != nil { - return err - } - // Validate the state root against the received state root and throw // an error if they don't match. if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root { diff --git a/core/blockchain.go b/core/blockchain.go index 79bb7d3d065e..14e9ba61a6f8 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1636,7 +1636,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) // Process block using the parent state as reference point substart := time.Now() - receipts, logs, usedGas, fees, fo, err := bc.processor.Process(block, statedb, bc.vmConfig) + receipts, logs, usedGas, err := bc.processor.Process(block, statedb, bc.vmConfig) if err != nil { bc.reportBlock(block, receipts, err) atomic.StoreUint32(&followupInterrupt, 1) @@ -1657,7 +1657,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals, setHead bool) // Validate the state using the default validator substart = time.Now() - if err := bc.validator.ValidateState(block, statedb, receipts, usedGas, fees, fo); err != nil { + if err := bc.validator.ValidateState(block, statedb, receipts, usedGas); err != nil { bc.reportBlock(block, receipts, err) atomic.StoreUint32(&followupInterrupt, 1) return it.index, err diff --git a/core/blockchain_test.go b/core/blockchain_test.go index eda7bbb30fba..6842049880ab 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -159,12 +159,12 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { if err != nil { return err } - receipts, _, usedGas, fees, fo, err := blockchain.processor.Process(block, statedb, vm.Config{}) + receipts, _, usedGas, err := blockchain.processor.Process(block, statedb, vm.Config{}) if err != nil { blockchain.reportBlock(block, receipts, err) return err } - err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas, fees, fo) + err = blockchain.validator.ValidateState(block, statedb, receipts, usedGas) if err != nil { blockchain.reportBlock(block, receipts, err) return err diff --git a/core/state_processor.go b/core/state_processor.go index 42c0fc1615c5..676b98a5f49a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,6 +17,7 @@ package core import ( + "bytes" "fmt" "math/big" @@ -56,7 +57,7 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen // Process returns the receipts and logs accumulated during the process and // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. -func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, *big.Int, interface{}, error) { +func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) { var ( receipts types.Receipts usedGas = new(uint64) @@ -77,20 +78,25 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg for i, tx := range block.Transactions() { msg, err := tx.AsMessage(types.MakeSigner(p.config, header.Number), header.BaseFee) if err != nil { - return nil, nil, 0, big.NewInt(0), nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) + return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.Prepare(tx.Hash(), i) receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, fees, vmenv) if err != nil { - return nil, nil, 0, big.NewInt(0), nil, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) + return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) - fo, err := p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) + err := p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) + header.Fees = fees - return receipts, allLogs, *usedGas, fees, fo, err + if !bytes.Equal(block.Header().Hash().Bytes(), header.Hash().Bytes()) { + return nil, nil, 0, fmt.Errorf("Remote block hash is different from being processed one locally (remote=%v, local=%v)", block.Header().Hash(), header.Hash()) + } + + return receipts, allLogs, *usedGas, err } func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, fees *big.Int, evm *vm.EVM) (*types.Receipt, error) { diff --git a/core/types.go b/core/types.go index 2aa4fc15fb5a..4c5b74a49865 100644 --- a/core/types.go +++ b/core/types.go @@ -17,8 +17,6 @@ package core import ( - "math/big" - "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -33,7 +31,7 @@ type Validator interface { // ValidateState validates the given statedb and optionally the receipts and // gas used. - ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64, fees *big.Int, finalizedOutput interface{}) error + ValidateState(block *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error } // Prefetcher is an interface for pre-caching transaction signatures and state. @@ -49,5 +47,5 @@ type Processor interface { // Process processes the state changes according to the Ethereum rules by running // the transaction messages using the statedb and applying any rewards to both // the processor (coinbase) and any included uncles. - Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, *big.Int, interface{}, error) + Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index 481909968fd0..70969c3e1424 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -131,7 +131,7 @@ func (eth *Ethereum) StateAtBlock(block *types.Block, reexec uint64, base *state if current = eth.blockchain.GetBlockByNumber(next); current == nil { return nil, fmt.Errorf("block #%d not found", next) } - _, _, _, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) + _, _, _, err := eth.blockchain.Processor().Process(current, statedb, vm.Config{}) if err != nil { return nil, fmt.Errorf("processing block %d failed: %v", current.NumberU64(), err) } diff --git a/wemix/rewards_test.go b/wemix/rewards_test.go index f8a6fff8c133..8d76f58d48a1 100644 --- a/wemix/rewards_test.go +++ b/wemix/rewards_test.go @@ -293,9 +293,131 @@ func TestRewardValidation(t *testing.T) { }) if _, err := blockchain.InsertChain(blocks); err != nil { - if !strings.HasPrefix(err.Error(), "invalid rewards") { + if !strings.HasPrefix(err.Error(), "Remote block hash is different") { t.Fatal(err) } + } else { + t.Fatal("Reward validation failed") + } +} + +func TestBriocheHardFork(t *testing.T) { + // use wemix consensus + params.ConsensusMethod = params.ConsensusPoA + + var ( + db = rawdb.NewMemoryDatabase() + key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + address = crypto.PubkeyToAddress(key.PublicKey) + funds = big.NewInt(100000000000000000) + deleteAddr = common.Address{1} + gspec = &core.Genesis{ + Config: ¶ms.ChainConfig{ + ChainID: big.NewInt(1), + LondonBlock: common.Big0, + BriocheBlock: big.NewInt(2), + Brioche: ¶ms.BriocheConfig{ + // 1 block reward: 1e18 + // 2 block reward: 4e17 (brioche start) + // 3 block reward: 4e17 + // 4 block reward: 2e17 (first halving) + // 5 block reward: 2e17 + // 6 block reward: 1e17 (second halving) + // 7~ block reward: 0 + BlockReward: big.NewInt(4e17), + FirstHalvingBlock: big.NewInt(4), + HalvingPeriod: big.NewInt(2), + NoRewardHereafter: big.NewInt(7), + HalvingTimes: 2, + HalvingRate: 50, + }}, + Alloc: core.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: big.NewInt(0)}}, + } + genesis = gspec.MustCommit(db) + signer = types.LatestSigner(gspec.Config) + ) + + expectedBlockReward := []*big.Int{ + big.NewInt(0), // zero block reward; not used + big.NewInt(1e18), + big.NewInt(4e17), + big.NewInt(4e17), + big.NewInt(2e17), + big.NewInt(2e17), + big.NewInt(1e17), + big.NewInt(0), + } + + miners := []common.Address{ + common.HexToAddress("0x02b4b2d83786c8ee315db2ddac704794850d2149"), + common.HexToAddress("0xb16d2494fddfa4c000deaf642d47673e5ca74e07"), + } + rp := &rewardParameters{ + rewardAmount: big.NewInt(1e18), + staker: &common.Address{0x11}, + ecoSystem: &common.Address{0x22}, + maintenance: &common.Address{0x33}, + feeCollector: &common.Address{0x44}, + members: []*wemixMember{ + { + Staker: miners[0], + Reward: miners[0], + Stake: hexToBigInt("0xFE1C215E8F838E00000"), // 75e21 (75%) + }, + { + Staker: miners[1], + Reward: miners[1], + Stake: hexToBigInt("0x54B40B1F852BDA00000"), // 25e21 (25%) + }, + }, + blocksPer: 1, + distributionMethod: []*big.Int{big.NewInt(5000), big.NewInt(0), big.NewInt(2500), big.NewInt(2500)}, // miner, staker, eco, maintenance + } + + wemixminer.CalculateRewardsFunc = makeCalculateRewardFunc(rp) + wemixminer.SignBlockFunc = makeSignBlockFunc(key) + wemixminer.VerifyBlockSigFunc = verifyBlockSigForTest + + blockchain, _ := core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}, nil, nil) + defer blockchain.Stop() + + parent := genesis + for i := 1; i <= 7; i++ { + statedb, _ := blockchain.State() + miner0Bal := statedb.GetBalance(miners[0]) + miner1Bal := statedb.GetBalance(miners[1]) + + blocks, _ := core.GenerateChain(gspec.Config, parent, ethash.NewFaker(), db, 1, func(i int, gen *core.BlockGen) { + tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1), params.TxGas, gen.BaseFee(), nil), signer, key) + if err != nil { + panic(err) + } + gen.AddTx(tx) + }) + + if _, err := blockchain.InsertChain(blocks); err != nil { + t.Fatal(err) + } + statedb, _ = blockchain.State() + + miner0Reward := new(big.Int).Div(expectedBlockReward[i], big.NewInt(2)) + miner0Reward = miner0Reward.Mul(miner0Reward, big.NewInt(3)) + miner0Reward = miner0Reward.Div(miner0Reward, big.NewInt(4)) + + miner1Reward := new(big.Int).Div(expectedBlockReward[i], big.NewInt(2)) + miner1Reward = miner1Reward.Div(miner1Reward, big.NewInt(4)) + + miner0Bal = new(big.Int).Add(miner0Bal, miner0Reward) + miner1Bal = new(big.Int).Add(miner1Bal, miner1Reward) + if statedb.GetBalance(miners[0]).Cmp(miner0Bal) != 0 { + t.Logf("miner bal = %v, expected = %v", statedb.GetBalance(miners[0]), miner0Bal) + t.Fatal("block reward mismatched for miner0") + } + if statedb.GetBalance(miners[1]).Cmp(miner1Bal) != 0 { + t.Fatal("block reward mismatched for miner1") + } + + parent = blocks[0] } } From 638743190f45e0af1a9f58d705456bf0b8d3ab75 Mon Sep 17 00:00:00 2001 From: egonspace Date: Mon, 20 May 2024 17:19:47 +0900 Subject: [PATCH 11/51] fix: test failure --- consensus/beacon/consensus.go | 4 ---- consensus/clique/clique.go | 4 ---- consensus/consensus.go | 1 - core/chain_makers.go | 4 +++- 4 files changed, 3 insertions(+), 10 deletions(-) diff --git a/consensus/beacon/consensus.go b/consensus/beacon/consensus.go index aaac10652c03..3611093423bc 100644 --- a/consensus/beacon/consensus.go +++ b/consensus/beacon/consensus.go @@ -167,10 +167,6 @@ func (beacon *Beacon) VerifyUncles(chain consensus.ChainReader, block *types.Blo return nil } -func (beacon *Beacon) ValidateEngineSpecific(*params.ChainConfig, *types.Header, *big.Int, interface{}) error { - return nil -} - // verifyHeader checks whether a header conforms to the consensus rules of the // stock Ethereum consensus engine. The difference between the beacon and classic is // (a) The following fields are expected to be constants: diff --git a/consensus/clique/clique.go b/consensus/clique/clique.go index 86164b3067a3..5e9b27eb2503 100644 --- a/consensus/clique/clique.go +++ b/consensus/clique/clique.go @@ -578,10 +578,6 @@ func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header * return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)), nil } -func (c *Clique) ValidateEngineSpecific(*params.ChainConfig, *types.Header, *big.Int, interface{}) error { - return nil -} - // Authorize injects a private key into the consensus engine to mint new blocks // with. func (c *Clique) Authorize(signer common.Address, signFn SignerFn) { diff --git a/consensus/consensus.go b/consensus/consensus.go index 43d5f29661eb..482c280cce04 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -89,7 +89,6 @@ type Engine interface { // // Note: The block header and state database might be updated to reflect any // consensus rules that happen at finalization (e.g. block rewards). - // Finalize returns engine specific output which can be validated by ValidateEngineSpecific Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header) error diff --git a/core/chain_makers.go b/core/chain_makers.go index 0f4dea2c9b06..4db017f3d621 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -309,9 +309,11 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S }), GasLimit: parent.GasLimit(), Number: new(big.Int).Add(parent.Number(), common.Big1), - Fees: new(big.Int), Time: time, } + if !wemixminer.IsPoW() { + header.Fees = new(big.Int) + } if chain.Config().IsLondon(header.Number) { header.BaseFee = misc.CalcBaseFee(chain.Config(), parent.Header()) if !chain.Config().IsLondon(parent.Number()) { From 393fc741afa347a64506918a37200ccc49e01665 Mon Sep 17 00:00:00 2001 From: egonspace Date: Mon, 20 May 2024 17:27:00 +0900 Subject: [PATCH 12/51] fix: apply comment --- core/state_processor.go | 5 ++--- core/types/block.go | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index 676b98a5f49a..7550f71f2827 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,7 +17,6 @@ package core import ( - "bytes" "fmt" "math/big" @@ -92,8 +91,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg err := p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) header.Fees = fees - if !bytes.Equal(block.Header().Hash().Bytes(), header.Hash().Bytes()) { - return nil, nil, 0, fmt.Errorf("Remote block hash is different from being processed one locally (remote=%v, local=%v)", block.Header().Hash(), header.Hash()) + if block.Header().Hash() != header.Hash() { + return nil, nil, 0, fmt.Errorf("remote block hash is different from being processed one locally (remote=%v, local=%v)", block.Header().Hash(), header.Hash()) } return receipts, allLogs, *usedGas, err diff --git a/core/types/block.go b/core/types/block.go index f55a0ad127ff..cb61514a931d 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -324,6 +324,9 @@ func CopyHeader(h *Header) *Header { cpy.Rewards = make([]byte, len(h.Rewards)) copy(cpy.Rewards, h.Rewards) } + if h.Fees != nil { + cpy.Fees = new(big.Int).Set(h.Fees) + } return &cpy } From fe76fa841a229808e0ff6df6c9ef4bc0eda1adda Mon Sep 17 00:00:00 2001 From: egonspace Date: Tue, 21 May 2024 08:12:09 +0900 Subject: [PATCH 13/51] fix: apaply comment and fix test failure --- params/config.go | 14 +++++++------- params/config_test.go | 40 ++++++++++++++++++++-------------------- wemix/rewards_test.go | 12 ++++++------ 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/params/config.go b/params/config.go index 27310d53256e..1bdd1807064c 100644 --- a/params/config.go +++ b/params/config.go @@ -165,7 +165,7 @@ var ( BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(53_557_371), HalvingPeriod: big.NewInt(63_115_200), - NoRewardHereafter: big.NewInt(1_000_000_000), // TODO fix last reward block + FinishRewardBlock: big.NewInt(1_000_000_000), // TODO fix last reward block HalvingTimes: 16, HalvingRate: 50, }, @@ -195,7 +195,7 @@ var ( BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(60_537_845), HalvingPeriod: big.NewInt(63_115_200), - NoRewardHereafter: big.NewInt(1_000_000_000), // TODO fix last reward block + FinishRewardBlock: big.NewInt(1_000_000_000), // TODO fix last reward block HalvingTimes: 16, HalvingRate: 50, }, @@ -434,7 +434,7 @@ type BriocheConfig struct { BlockReward *big.Int `json:"blockReward,omitempty"` // nil - use default block reward(1e18) FirstHalvingBlock *big.Int `json:"firstHalvingBlock,omitempty"` // nil - halving is not work. including this block HalvingPeriod *big.Int `json:"halvingPeriod,omitempty"` // nil - halving is not work - NoRewardHereafter *big.Int `json:"noRewardHereafter,omitempty"` // nil - block reward goes on endlessly + FinishRewardBlock *big.Int `json:"finishRewardBlock,omitempty"` // nil - block reward goes on endlessly HalvingTimes uint64 `json:"halvingTimes,omitempty"` // 0 - no halving HalvingRate uint32 `json:"halvingRate,omitempty"` // 0 - no reward on halving; 100 - no halving; >100 - increasing reward } @@ -445,20 +445,20 @@ func (bc *BriocheConfig) GetBriocheBlockReward(defaultReward *big.Int, num *big. if bc.BlockReward != nil { blockReward = big.NewInt(0).Set(bc.BlockReward) } - if bc.NoRewardHereafter != nil && - bc.NoRewardHereafter.Cmp(num) <= 0 { + if bc.FinishRewardBlock != nil && + bc.FinishRewardBlock.Cmp(num) <= 0 { blockReward = big.NewInt(0) } else if bc.FirstHalvingBlock != nil && bc.HalvingPeriod != nil && bc.HalvingTimes > 0 && num.Cmp(bc.FirstHalvingBlock) >= 0 { - blockReward = bc.halveRewards(blockReward, num) + blockReward = bc.calcHalvedReward(blockReward, num) } } return blockReward } -func (bc *BriocheConfig) halveRewards(baseReward *big.Int, num *big.Int) *big.Int { +func (bc *BriocheConfig) calcHalvedReward(baseReward *big.Int, num *big.Int) *big.Int { elapsed := new(big.Int).Sub(num, bc.FirstHalvingBlock) times := new(big.Int).Add(common.Big1, new(big.Int).Div(elapsed, bc.HalvingPeriod)) if times.Uint64() > bc.HalvingTimes { diff --git a/params/config_test.go b/params/config_test.go index 0db609be3209..07395ec1a017 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -157,9 +157,9 @@ func TestHalveRewards(t *testing.T) { HalvingTimes: tc.times, HalvingRate: tc.rate, } - halved := brioche.halveRewards(tc.reward, tc.past) + halved := brioche.calcHalvedReward(tc.reward, tc.past) if tc.expected.Cmp(halved) != 0 { - t.Errorf("halveRewards mismatched (expected=%v, actual=%v)", tc.expected, halved) + t.Errorf("halved reward mismatched (expected=%v, actual=%v)", tc.expected, halved) } } } @@ -187,7 +187,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), + FinishRewardBlock: big.NewInt(101), HalvingTimes: 10, HalvingRate: 50, }, @@ -200,7 +200,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(201), + FinishRewardBlock: big.NewInt(201), HalvingTimes: 10, HalvingRate: 50, }, @@ -215,7 +215,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(7e18), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), + FinishRewardBlock: big.NewInt(101), HalvingTimes: 10, HalvingRate: 50, }, @@ -228,7 +228,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(3), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), + FinishRewardBlock: big.NewInt(101), HalvingTimes: 10, HalvingRate: 50, }, @@ -241,7 +241,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(1), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), + FinishRewardBlock: big.NewInt(101), HalvingTimes: 10, HalvingRate: 50, }, @@ -254,7 +254,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: nil, // it will use the default block reward FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), + FinishRewardBlock: big.NewInt(101), HalvingTimes: 10, HalvingRate: 50, }, @@ -269,7 +269,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: nil, // it will use the default block reward FirstHalvingBlock: nil, HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), + FinishRewardBlock: big.NewInt(101), HalvingTimes: 10, HalvingRate: 50, }, @@ -282,7 +282,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: nil, - NoRewardHereafter: big.NewInt(101), + FinishRewardBlock: big.NewInt(101), HalvingTimes: 10, HalvingRate: 50, }, @@ -295,7 +295,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(101), + FinishRewardBlock: big.NewInt(101), HalvingTimes: 0, HalvingRate: 50, }, @@ -308,7 +308,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(200), + FinishRewardBlock: big.NewInt(200), HalvingTimes: 10, HalvingRate: 50, }, @@ -321,7 +321,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(200), + FinishRewardBlock: big.NewInt(200), HalvingTimes: 10, HalvingRate: 100, // no halving rate }, @@ -336,7 +336,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(200), + FinishRewardBlock: big.NewInt(200), HalvingTimes: 10, HalvingRate: 0, // no reward }, @@ -349,7 +349,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(200), + FinishRewardBlock: big.NewInt(200), HalvingTimes: 10, HalvingRate: 50, }, @@ -362,7 +362,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(10), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(200), + FinishRewardBlock: big.NewInt(200), HalvingTimes: 10, HalvingRate: 50, }, @@ -377,7 +377,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(1000), + FinishRewardBlock: big.NewInt(1000), HalvingTimes: 10, HalvingRate: 10, }, @@ -390,7 +390,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(1000), + FinishRewardBlock: big.NewInt(1000), HalvingTimes: 10, HalvingRate: 10, }, @@ -403,7 +403,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(1000), + FinishRewardBlock: big.NewInt(1000), HalvingTimes: 10, HalvingRate: 1, }, @@ -416,7 +416,7 @@ func TestGetBriocheBlockReward(t *testing.T) { BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(100), HalvingPeriod: big.NewInt(100), - NoRewardHereafter: big.NewInt(1000), + FinishRewardBlock: big.NewInt(1000), HalvingTimes: 10, HalvingRate: 99, }, diff --git a/wemix/rewards_test.go b/wemix/rewards_test.go index 8d76f58d48a1..b26279d507ad 100644 --- a/wemix/rewards_test.go +++ b/wemix/rewards_test.go @@ -146,7 +146,7 @@ func TestDistributeRewards(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // Call the distributeRewards function - rewards, err := distributeRewards(tt.height, tt.rp, defaultBriocheBlockReward, tt.fees) + rewards, err := distributeRewards(tt.height, tt.rp, tt.rp.rewardAmount, tt.fees) rewardsString, _ := json.Marshal(rewards) if string(rewardsString) != tt.want { t.Errorf("distributeRewards() failed: %v, %v <-> %v", err, tt.want, string(rewardsString)) @@ -228,7 +228,7 @@ func TestRewardValidation(t *testing.T) { BlockReward: big.NewInt(100), FirstHalvingBlock: big.NewInt(0), HalvingPeriod: big.NewInt(10), - NoRewardHereafter: big.NewInt(30), + FinishRewardBlock: big.NewInt(30), HalvingTimes: 3, HalvingRate: 50, }}, @@ -280,7 +280,7 @@ func TestRewardValidation(t *testing.T) { BlockReward: big.NewInt(200), // different reward!! FirstHalvingBlock: gspec.Config.Brioche.FirstHalvingBlock, HalvingPeriod: gspec.Config.Brioche.HalvingPeriod, - NoRewardHereafter: gspec.Config.Brioche.NoRewardHereafter, + FinishRewardBlock: gspec.Config.Brioche.FinishRewardBlock, HalvingTimes: gspec.Config.Brioche.HalvingTimes, HalvingRate: gspec.Config.Brioche.HalvingRate, }} @@ -293,11 +293,11 @@ func TestRewardValidation(t *testing.T) { }) if _, err := blockchain.InsertChain(blocks); err != nil { - if !strings.HasPrefix(err.Error(), "Remote block hash is different") { + if !strings.HasPrefix(err.Error(), "remote block hash is different") { t.Fatal(err) } } else { - t.Fatal("Reward validation failed") + t.Fatal("reward validation failed") } } @@ -327,7 +327,7 @@ func TestBriocheHardFork(t *testing.T) { BlockReward: big.NewInt(4e17), FirstHalvingBlock: big.NewInt(4), HalvingPeriod: big.NewInt(2), - NoRewardHereafter: big.NewInt(7), + FinishRewardBlock: big.NewInt(7), HalvingTimes: 2, HalvingRate: 50, }}, From 1fd5ec7dd4dc2436b85dc6d7ab64c331e84baeb7 Mon Sep 17 00:00:00 2001 From: egonspace Date: Tue, 21 May 2024 09:54:27 +0900 Subject: [PATCH 14/51] fix: remove needless coinbase setting --- consensus/ethash/consensus.go | 2 +- wemix/admin.go | 13 +++---------- wemix/miner/miner.go | 6 +++--- wemix/rewards_test.go | 4 ++-- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 72a25ff51c42..535d5b6c344e 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -698,7 +698,7 @@ func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header } state.AddBalance(header.Coinbase, reward) } else { - _, rewards, err := wemixminer.CalculateRewards( + rewards, err := wemixminer.CalculateRewards( config, header.Number, header.Fees, func(addr common.Address, amt *big.Int) { state.AddBalance(addr, amt) diff --git a/wemix/admin.go b/wemix/admin.go index b3b0a92e1191..b2a3b0b9e52c 100644 --- a/wemix/admin.go +++ b/wemix/admin.go @@ -1147,7 +1147,7 @@ func distributeRewards(height *big.Int, rp *rewardParameters, blockReward *big.I return rewards, nil } -func calculateRewardsWithParams(config *params.ChainConfig, rp *rewardParameters, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (coinbase *common.Address, rewards []byte, err error) { +func calculateRewardsWithParams(config *params.ChainConfig, rp *rewardParameters, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (rewards []byte, err error) { if (rp.staker == nil && rp.ecoSystem == nil && rp.maintenance == nil) || len(rp.members) == 0 { // handle testnet block 94 rewards if rewards94 := handleBlock94Rewards(num, rp, fees); rewards94 != nil { @@ -1163,13 +1163,6 @@ func calculateRewardsWithParams(config *params.ChainConfig, rp *rewardParameters return } - // determine coinbase - if len(rp.members) > 0 { - mix := int(num.Int64()/rp.blocksPer) % len(rp.members) - coinbase = &common.Address{} - coinbase.SetBytes(rp.members[mix].Reward.Bytes()) - } - var blockReward *big.Int if config.IsBrioche(num) { blockReward = config.Brioche.GetBriocheBlockReward(defaultBriocheBlockReward, num) @@ -1200,7 +1193,7 @@ func calculateRewardsWithParams(config *params.ChainConfig, rp *rewardParameters return } -func calculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { +func calculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) ([]byte, error) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() @@ -1208,7 +1201,7 @@ func calculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance if err != nil { // all goes to the coinbase err = wemixminer.ErrNotInitialized - return nil, nil, err + return nil, err } return calculateRewardsWithParams(config, rp, num, fees, addBalance) diff --git a/wemix/miner/miner.go b/wemix/miner/miner.go index 0b369b3b063c..339cb9f0e57c 100644 --- a/wemix/miner/miner.go +++ b/wemix/miner/miner.go @@ -16,7 +16,7 @@ var ( AmPartnerFunc func() bool IsPartnerFunc func(string) bool AmHubFunc func(string) int - CalculateRewardsFunc func(*params.ChainConfig, *big.Int, *big.Int, func(common.Address, *big.Int)) (*common.Address, []byte, error) + CalculateRewardsFunc func(*params.ChainConfig, *big.Int, *big.Int, func(common.Address, *big.Int)) ([]byte, error) VerifyRewardsFunc func(*big.Int, string) error GetCoinbaseFunc func(height *big.Int) (coinbase common.Address, err error) SignBlockFunc func(height *big.Int, hash common.Hash) (coinbase common.Address, sig []byte, err error) @@ -79,9 +79,9 @@ func IsPoW() bool { return params.ConsensusMethod == params.ConsensusPoW } -func CalculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { +func CalculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) ([]byte, error) { if CalculateRewardsFunc == nil { - return nil, nil, ErrNotInitialized + return nil, ErrNotInitialized } else { return CalculateRewardsFunc(config, num, fees, addBalance) } diff --git a/wemix/rewards_test.go b/wemix/rewards_test.go index b26279d507ad..d989116e79ab 100644 --- a/wemix/rewards_test.go +++ b/wemix/rewards_test.go @@ -179,8 +179,8 @@ func TestDistributeRewards(t *testing.T) { } } -func makeCalculateRewardFunc(rp *rewardParameters) func(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { - return func(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) (*common.Address, []byte, error) { +func makeCalculateRewardFunc(rp *rewardParameters) func(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) ([]byte, error) { + return func(config *params.ChainConfig, num, fees *big.Int, addBalance func(common.Address, *big.Int)) ([]byte, error) { return calculateRewardsWithParams(config, rp, num, fees, addBalance) } } From 439c8426d6c694f17cd3a8da0520922374d823c0 Mon Sep 17 00:00:00 2001 From: egonspace Date: Tue, 21 May 2024 11:03:57 +0900 Subject: [PATCH 15/51] fix: remove unsued arguments --- core/state_processor.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index 7550f71f2827..2f7dd6627b38 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -80,7 +80,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } statedb.Prepare(tx.Hash(), i) - receipt, err := applyTransaction(msg, p.config, p.bc, nil, gp, statedb, blockNumber, blockHash, tx, usedGas, fees, vmenv) + receipt, err := applyTransaction(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, fees, vmenv) if err != nil { return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err) } @@ -98,7 +98,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg return receipts, allLogs, *usedGas, err } -func applyTransaction(msg types.Message, config *params.ChainConfig, bc ChainContext, author *common.Address, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, fees *big.Int, evm *vm.EVM) (*types.Receipt, error) { +func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, fees *big.Int, evm *vm.EVM) (*types.Receipt, error) { // Create a new context to be used in the EVM environment. txContext := NewEVMTxContext(msg) evm.Reset(txContext, statedb) @@ -156,5 +156,5 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo // Create a new context to be used in the EVM environment blockContext := NewEVMBlockContext(header, bc, author) vmenv := vm.NewEVM(blockContext, vm.TxContext{}, statedb, config, cfg) - return applyTransaction(msg, config, bc, author, gp, statedb, header.Number, header.Hash(), tx, usedGas, fees, vmenv) + return applyTransaction(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, fees, vmenv) } From 39f6894785d855049e3e579f749c42c8ae01890f Mon Sep 17 00:00:00 2001 From: egonspace Date: Tue, 21 May 2024 17:25:05 +0900 Subject: [PATCH 16/51] fix: configure loading for testnet --- core/genesis.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/genesis.go b/core/genesis.go index b4a318727a69..f98aa8966071 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -302,7 +302,10 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override // chain config as that would be AllProtocolChanges (applying any new fork // on top of an existing private network genesis block). In that case, only // apply the overrides. - if genesis == nil && !(stored == params.MainnetGenesisHash || stored == params.WemixMainnetGenesisHash) { + if genesis == nil && + !(stored == params.MainnetGenesisHash || + stored == params.WemixMainnetGenesisHash || + stored == params.WemixTestnetGenesisHash) { newcfg = storedcfg if overrideArrowGlacier != nil { newcfg.ArrowGlacierBlock = overrideArrowGlacier From 39c46c1a1469e0f38a0428986157ada1b99749e1 Mon Sep 17 00:00:00 2001 From: egonspace Date: Tue, 21 May 2024 18:41:54 +0900 Subject: [PATCH 17/51] fix: add checking hard fork order, compatibility --- params/config.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/params/config.go b/params/config.go index 1bdd1807064c..1cc89dd6d7b2 100644 --- a/params/config.go +++ b/params/config.go @@ -498,7 +498,7 @@ func (c *ChainConfig) String() string { default: engine = "unknown" } - return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, MergeFork: %v, PangyoFork: %v, ApplepieFork: %v, BriocheFork: %v, Terminal TD: %v, Engine: %v}", + return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, MergeFork: %v, PangyoFork: %v, ApplepieFork: %v, BriocheFork: %v, Terminal TD: %v, Engine: %v, BriocheConfig: %v}", c.ChainID, c.HomesteadBlock, c.DAOForkBlock, @@ -520,6 +520,7 @@ func (c *ChainConfig) String() string { c.BriocheBlock, c.TerminalTotalDifficulty, engine, + c.Brioche, ) } @@ -660,6 +661,9 @@ func (c *ChainConfig) CheckConfigForkOrder() error { {name: "londonBlock", block: c.LondonBlock}, {name: "arrowGlacierBlock", block: c.ArrowGlacierBlock, optional: true}, {name: "mergeStartBlock", block: c.MergeForkBlock, optional: true}, + {name: "pangyoBlock", block: c.PangyoBlock, optional: true}, + {name: "applepieBlock", block: c.ApplepieBlock, optional: true}, + {name: "briocheBlock", block: c.BriocheBlock, optional: true}, } { if lastFork.name != "" { // Next one must be higher number @@ -735,6 +739,15 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi if isForkIncompatible(c.MergeForkBlock, newcfg.MergeForkBlock, head) { return newCompatError("Merge Start fork block", c.MergeForkBlock, newcfg.MergeForkBlock) } + if isForkIncompatible(c.PangyoBlock, newcfg.PangyoBlock, head) { + return newCompatError("Pangyo fork block", c.PangyoBlock, newcfg.PangyoBlock) + } + if isForkIncompatible(c.ApplepieBlock, newcfg.ApplepieBlock, head) { + return newCompatError("Applepie fork block", c.ApplepieBlock, newcfg.ApplepieBlock) + } + if isForkIncompatible(c.BriocheBlock, newcfg.BriocheBlock, head) { + return newCompatError("Brioche fork block", c.BriocheBlock, newcfg.BriocheBlock) + } return nil } From 54963bd59880b709ab7d093b0b62cc9eb4c1b52d Mon Sep 17 00:00:00 2001 From: egonspace Date: Wed, 22 May 2024 16:16:28 +0900 Subject: [PATCH 18/51] fix: apply comment --- params/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/params/config.go b/params/config.go index 1cc89dd6d7b2..ee00dd125862 100644 --- a/params/config.go +++ b/params/config.go @@ -498,7 +498,7 @@ func (c *ChainConfig) String() string { default: engine = "unknown" } - return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, MergeFork: %v, PangyoFork: %v, ApplepieFork: %v, BriocheFork: %v, Terminal TD: %v, Engine: %v, BriocheConfig: %v}", + return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Petersburg: %v Istanbul: %v, Muir Glacier: %v, Berlin: %v, London: %v, Arrow Glacier: %v, MergeFork: %v, PangyoFork: %v, ApplepieFork: %v, BriocheFork: %v, Terminal TD: %v, BriocheConfig: %v, Engine: %v}", c.ChainID, c.HomesteadBlock, c.DAOForkBlock, @@ -519,8 +519,8 @@ func (c *ChainConfig) String() string { c.ApplepieBlock, c.BriocheBlock, c.TerminalTotalDifficulty, - engine, c.Brioche, + engine, ) } From 5e6eddfc392427529c2bd3cebe8acc0644872694 Mon Sep 17 00:00:00 2001 From: egonspace Date: Wed, 22 May 2024 16:46:40 +0900 Subject: [PATCH 19/51] fix: apply comment --- wemix/admin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wemix/admin.go b/wemix/admin.go index b2a3b0b9e52c..3b0f4d07d75e 100644 --- a/wemix/admin.go +++ b/wemix/admin.go @@ -1168,7 +1168,7 @@ func calculateRewardsWithParams(config *params.ChainConfig, rp *rewardParameters blockReward = config.Brioche.GetBriocheBlockReward(defaultBriocheBlockReward, num) } else { // if the wemix chain is not on brioche hard fork, use the `rewardAmount` from gov contract - blockReward = big.NewInt(0).Set(rp.rewardAmount) + blockReward = new(big.Int).Set(rp.rewardAmount) } // block reward From 3b9ae394a1c60a9ce7f075c5e1b7e8ca4c1b548c Mon Sep 17 00:00:00 2001 From: egonspace Date: Thu, 23 May 2024 08:08:51 +0900 Subject: [PATCH 20/51] fix: stringify brioch config --- ethclient/ethclient_test.go | 2 +- params/config.go | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/ethclient/ethclient_test.go b/ethclient/ethclient_test.go index dd01c08f539e..b475feba2c3f 100644 --- a/ethclient/ethclient_test.go +++ b/ethclient/ethclient_test.go @@ -401,7 +401,7 @@ func testTransactionInBlockInterrupted(t *testing.T, client *rpc.Client) { t.Fatalf("unexpected error: %v", err) } - // Test tx in block interupted. + // Test tx in block interrupted. ctx, cancel := context.WithCancel(context.Background()) cancel() tx, err := ec.TransactionInBlock(ctx, block.Hash(), 0) diff --git a/params/config.go b/params/config.go index ee00dd125862..fa323cf58746 100644 --- a/params/config.go +++ b/params/config.go @@ -471,6 +471,17 @@ func (bc *BriocheConfig) calcHalvedReward(baseReward *big.Int, num *big.Int) *bi return reward.Div(reward.Mul(reward, numerator), denominator) } +func (bc *BriocheConfig) String() string { + return fmt.Sprintf("{BlockReward: %v FirstHalvingBlock: %v HalvingPeriod: %v FinishRewardBlock: %v HalvingTimes: %v HalvingRate: %v}", + bc.BlockReward, + bc.FirstHalvingBlock, + bc.HalvingPeriod, + bc.FinishRewardBlock, + bc.HalvingTimes, + bc.HalvingRate, + ) +} + // String implements the stringer interface, returning the consensus engine details. func (c *EthashConfig) String() string { return "ethash" From 81c6ca004a89287c00de61fca97f9c554f6bb68a Mon Sep 17 00:00:00 2001 From: felix-shin-wt Date: Mon, 20 May 2024 17:05:10 +0900 Subject: [PATCH 21/51] feat : impl BriocheConfigAPI --- eth/api.go | 36 ++++++++++++++++ eth/backend.go | 9 ++++ internal/web3ext/web3ext.go | 41 +++++++++++++++++++ .../openzeppelin/openzeppelin-contracts | 1 + .../openzeppelin-contracts-upgradeable | 1 + 5 files changed, 88 insertions(+) create mode 160000 wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts create mode 160000 wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts-upgradeable diff --git a/eth/api.go b/eth/api.go index 4ebd7231e162..daa90f7ba57a 100644 --- a/eth/api.go +++ b/eth/api.go @@ -678,3 +678,39 @@ func (api *PrivateDebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64 } return 0, fmt.Errorf("No state found") } + +type BriocheConfigAPI struct { + cfg *params.BriocheConfig +} + +func NewBriocheConfigAPI(cfg *params.BriocheConfig) *BriocheConfigAPI { + return &BriocheConfigAPI{cfg} +} + +func (api *BriocheConfigAPI) BlockReward() *big.Int { + return api.cfg.BlockReward +} + +func (api *BriocheConfigAPI) FirstHalvingBlock() *big.Int { + return api.cfg.FirstHalvingBlock +} + +func (api *BriocheConfigAPI) HalvingPeriod() *big.Int { + return api.cfg.HalvingPeriod +} + +func (api *BriocheConfigAPI) NoRewardHereafter() *big.Int { + return api.cfg.NoRewardHereafter +} + +func (api *BriocheConfigAPI) HalvingTimes() uint64 { + return api.cfg.HalvingTimes +} + +func (api *BriocheConfigAPI) HalvingRate() uint32 { + return api.cfg.HalvingRate +} + +func (api *BriocheConfigAPI) GetBriocheBlockReward(height *big.Int) (*big.Int, error) { + return api.cfg.GetBriocheBlockReward(api.cfg.BlockReward, height), nil +} diff --git a/eth/backend.go b/eth/backend.go index 30809545e97b..4c15697282ac 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -292,6 +292,15 @@ func (s *Ethereum) APIs() []rpc.API { // Append any APIs exposed explicitly by the consensus engine apis = append(apis, s.engine.APIs(s.BlockChain())...) + if brioche := s.blockchain.Config().Brioche; brioche != nil { + apis = append(apis, rpc.API{ + Namespace: "brioche", + Version: "1.0", + Service: NewBriocheConfigAPI(brioche), + Public: true, + }) + } + // Append all the local APIs and return return append(apis, []rpc.API{ { diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index a50eb615ead0..a368e10f52f8 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -30,6 +30,7 @@ var Modules = map[string]string{ "txpool": TxpoolJs, "les": LESJs, "vflux": VfluxJs, + "brioche": BriocheJS, } const CliqueJs = ` @@ -1004,3 +1005,43 @@ web3._extend({ ] }); ` + +const BriocheJS = ` +web3._extend({ + property: 'brioche', + methods: [ + new web3._extend.Method({ + name: 'getBriocheBlockReward', + call: 'brioche_getBriocheBlockReward', + params: 1 + }) + ], + properties: + [ + new web3._extend.Property({ + name: 'blockReward', + getter: 'brioche_blockReward' + }), + new web3._extend.Property({ + name: 'firstHalvingBlock', + getter: 'brioche_firstHalvingBlock' + }), + new web3._extend.Property({ + name: 'halvingPeriod', + getter: 'brioche_halvingPeriod' + }), + new web3._extend.Property({ + name: 'noRewardHereafter', + getter: 'brioche_noRewardHereafter' + }), + new web3._extend.Property({ + name: 'halvingTimes', + getter: 'brioche_halvingTimes' + }), + new web3._extend.Property({ + name: 'halvingRate', + getter: 'brioche_halvingRate' + }), + ] +}); +` diff --git a/wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts b/wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts new file mode 160000 index 000000000000..49c0e4370d0c --- /dev/null +++ b/wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts @@ -0,0 +1 @@ +Subproject commit 49c0e4370d0cc50ea6090709e3835a3091e33ee2 diff --git a/wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts-upgradeable b/wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts-upgradeable new file mode 160000 index 000000000000..65420cb9c943 --- /dev/null +++ b/wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts-upgradeable @@ -0,0 +1 @@ +Subproject commit 65420cb9c943c32eb7e8c9da60183a413d90067a From 7352305c537756ab032ca69a8910e3415730a36a Mon Sep 17 00:00:00 2001 From: eomti-wm Date: Thu, 23 May 2024 09:53:28 +0900 Subject: [PATCH 22/51] feat: add rpc method for inquiry halving schedule --- eth/api.go | 62 +++++++++++++------ eth/backend.go | 2 +- internal/web3ext/web3ext.go | 33 +++------- wemix/admin.go | 37 +++++------ .../openzeppelin/openzeppelin-contracts | 1 - .../openzeppelin-contracts-upgradeable | 1 - 6 files changed, 71 insertions(+), 65 deletions(-) delete mode 160000 wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts delete mode 160000 wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts-upgradeable diff --git a/eth/api.go b/eth/api.go index daa90f7ba57a..613c008d54f7 100644 --- a/eth/api.go +++ b/eth/api.go @@ -680,37 +680,59 @@ func (api *PrivateDebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64 } type BriocheConfigAPI struct { - cfg *params.BriocheConfig + e *Ethereum } -func NewBriocheConfigAPI(cfg *params.BriocheConfig) *BriocheConfigAPI { - return &BriocheConfigAPI{cfg} +func NewBriocheConfigAPI(e *Ethereum) *BriocheConfigAPI { + return &BriocheConfigAPI{e} } -func (api *BriocheConfigAPI) BlockReward() *big.Int { - return api.cfg.BlockReward +func (api *BriocheConfigAPI) BriocheConfig() *params.BriocheConfig { + return api.e.BlockChain().Config().Brioche } -func (api *BriocheConfigAPI) FirstHalvingBlock() *big.Int { - return api.cfg.FirstHalvingBlock +type HalvingInfo struct { + HalvingTimes uint64 `json:"halvingTimes"` + StartBlock *big.Int `json:"startBlock"` + EndBlock *big.Int `json:"endBlock"` + BlockReward *big.Int `json:"blockReward"` } -func (api *BriocheConfigAPI) HalvingPeriod() *big.Int { - return api.cfg.HalvingPeriod -} +func (api *BriocheConfigAPI) HalvingSchedule() []*HalvingInfo { + bc := api.BriocheConfig() + if bc.FirstHalvingBlock == nil || bc.HalvingPeriod == nil { + return nil + } -func (api *BriocheConfigAPI) NoRewardHereafter() *big.Int { - return api.cfg.NoRewardHereafter -} + result := make([]*HalvingInfo, 0) + for i := uint64(1); i <= bc.HalvingTimes; i++ { + startBlock := new(big.Int).Add(bc.FirstHalvingBlock, new(big.Int).Mul(bc.HalvingPeriod, new(big.Int).SetUint64(i))) + result = append(result, &HalvingInfo{ + HalvingTimes: i + 1, + StartBlock: startBlock, + EndBlock: new(big.Int).Sub(new(big.Int).Add(startBlock, bc.HalvingPeriod), common.Big1), + BlockReward: api.GetBriocheBlockReward(startBlock), + }) + } + result[len(result)-1].EndBlock = bc.FinishRewardBlock -func (api *BriocheConfigAPI) HalvingTimes() uint64 { - return api.cfg.HalvingTimes + return result } -func (api *BriocheConfigAPI) HalvingRate() uint32 { - return api.cfg.HalvingRate -} +func (api *BriocheConfigAPI) GetBriocheBlockReward(height *big.Int) *big.Int { + if wemixapi.Info == nil { + return nil + } + config := api.e.BlockChain().Config() + wemixInfo := *(wemixapi.Info().(*map[string]interface{})) + + if height == nil { + height = api.e.blockchain.CurrentHeader().Number + } -func (api *BriocheConfigAPI) GetBriocheBlockReward(height *big.Int) (*big.Int, error) { - return api.cfg.GetBriocheBlockReward(api.cfg.BlockReward, height), nil + if config.IsBrioche(height) { + return config.Brioche.GetBriocheBlockReward(wemixInfo["defaultBriocheBlockReward"].(*big.Int), height) + } else { + return wemixInfo["blockReward"].(*big.Int) + } } diff --git a/eth/backend.go b/eth/backend.go index 4c15697282ac..b45883ed140e 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -296,7 +296,7 @@ func (s *Ethereum) APIs() []rpc.API { apis = append(apis, rpc.API{ Namespace: "brioche", Version: "1.0", - Service: NewBriocheConfigAPI(brioche), + Service: NewBriocheConfigAPI(s), Public: true, }) } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index a368e10f52f8..006741a25a51 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -30,7 +30,7 @@ var Modules = map[string]string{ "txpool": TxpoolJs, "les": LESJs, "vflux": VfluxJs, - "brioche": BriocheJS, + "brioche": BriocheJs, } const CliqueJs = ` @@ -1006,42 +1006,27 @@ web3._extend({ }); ` -const BriocheJS = ` +const BriocheJs = ` web3._extend({ property: 'brioche', methods: [ new web3._extend.Method({ name: 'getBriocheBlockReward', call: 'brioche_getBriocheBlockReward', - params: 1 + params: 1, + inputFormatter: [null] }) ], properties: [ new web3._extend.Property({ - name: 'blockReward', - getter: 'brioche_blockReward' - }), - new web3._extend.Property({ - name: 'firstHalvingBlock', - getter: 'brioche_firstHalvingBlock' - }), - new web3._extend.Property({ - name: 'halvingPeriod', - getter: 'brioche_halvingPeriod' + name: 'briocheConfig', + getter: 'brioche_briocheConfig' }), new web3._extend.Property({ - name: 'noRewardHereafter', - getter: 'brioche_noRewardHereafter' - }), - new web3._extend.Property({ - name: 'halvingTimes', - getter: 'brioche_halvingTimes' - }), - new web3._extend.Property({ - name: 'halvingRate', - getter: 'brioche_halvingRate' - }), + name: 'halvingSchedule', + getter: 'brioche_halvingSchedule' + }) ] }); ` diff --git a/wemix/admin.go b/wemix/admin.go index 3b0f4d07d75e..ec214872d062 100644 --- a/wemix/admin.go +++ b/wemix/admin.go @@ -1554,24 +1554,25 @@ func Info() interface{} { }) info := &map[string]interface{}{ - "consensus": params.ConsensusMethod, - "registry": admin.registry.To, - "governance": admin.gov.To, - "staking": admin.staking.To, - "modifiedblock": admin.modifiedBlock, - "blocksPer": admin.blocksPer, - "blockInterval": admin.blockInterval, - "blockReward": admin.blockReward, - "maxPriorityFeePerGas": admin.maxPriorityFeePerGas, - "blockGasLimit": admin.gasLimit, - "maxBaseFee": admin.maxBaseFee, - "baseFeeMaxChangeRate": admin.baseFeeMaxChangeRate, - "gasTargetPercentage": admin.gasTargetPercentage, - "self": self, - "nodes": nodes, - "miners": admin.miners(), - "etcd": admin.etcdInfo(), - "maxIdle": params.MaxIdleBlockInterval, + "consensus": params.ConsensusMethod, + "registry": admin.registry.To, + "governance": admin.gov.To, + "staking": admin.staking.To, + "modifiedblock": admin.modifiedBlock, + "blocksPer": admin.blocksPer, + "blockInterval": admin.blockInterval, + "blockReward": admin.blockReward, + "maxPriorityFeePerGas": admin.maxPriorityFeePerGas, + "blockGasLimit": admin.gasLimit, + "maxBaseFee": admin.maxBaseFee, + "baseFeeMaxChangeRate": admin.baseFeeMaxChangeRate, + "gasTargetPercentage": admin.gasTargetPercentage, + "self": self, + "nodes": nodes, + "miners": admin.miners(), + "etcd": admin.etcdInfo(), + "maxIdle": params.MaxIdleBlockInterval, + "defaultBriocheBlockReward": defaultBriocheBlockReward, } return info } diff --git a/wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts b/wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts deleted file mode 160000 index 49c0e4370d0c..000000000000 --- a/wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 49c0e4370d0cc50ea6090709e3835a3091e33ee2 diff --git a/wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts-upgradeable b/wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts-upgradeable deleted file mode 160000 index 65420cb9c943..000000000000 --- a/wemix/governance-contract/contracts/openzeppelin/openzeppelin-contracts-upgradeable +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 65420cb9c943c32eb7e8c9da60183a413d90067a From 502847775253eea829c4adcd43b22982910d226a Mon Sep 17 00:00:00 2001 From: paul-ahn-wm Date: Thu, 23 May 2024 10:30:26 +0900 Subject: [PATCH 23/51] Fix: replace deprecated syscall pkg to golang.org/x/sys/unix pkg --- cmd/geth/dbcmd.go | 6 +++--- cmd/geth/main.go | 6 +++--- cmd/geth/wemixcmd.go | 10 +++++----- cmd/utils/cmd.go | 10 +++++----- common/fdlimit/fdlimit_bsd.go | 18 +++++++++--------- common/fdlimit/fdlimit_darwin.go | 18 +++++++++--------- common/fdlimit/fdlimit_unix.go | 18 +++++++++--------- console/console.go | 4 ++-- internal/cmdtest/test_cmd.go | 4 ++-- metrics/cputime_unix.go | 7 +++---- node/errors.go | 5 +++-- p2p/netutil/toobig_windows.go | 5 +++-- p2p/simulations/adapters/exec.go | 6 +++--- 13 files changed, 59 insertions(+), 58 deletions(-) diff --git a/cmd/geth/dbcmd.go b/cmd/geth/dbcmd.go index ace2849c9f06..871b8002fe18 100644 --- a/cmd/geth/dbcmd.go +++ b/cmd/geth/dbcmd.go @@ -25,7 +25,6 @@ import ( "sort" "strconv" "strings" - "syscall" "time" "github.com/ethereum/go-ethereum/cmd/utils" @@ -40,6 +39,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/trie" "github.com/olekukonko/tablewriter" + "golang.org/x/sys/unix" "gopkg.in/urfave/cli.v1" ) @@ -597,7 +597,7 @@ func importLDBdata(ctx *cli.Context) error { stop = make(chan struct{}) ) defer stack.Close() - signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM) + signal.Notify(interrupt, unix.SIGINT, unix.SIGTERM) defer signal.Stop(interrupt) defer close(interrupt) go func() { @@ -693,7 +693,7 @@ func exportChaindata(ctx *cli.Context) error { stop = make(chan struct{}) ) defer stack.Close() - signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM) + signal.Notify(interrupt, unix.SIGINT, unix.SIGTERM) defer signal.Stop(interrupt) defer close(interrupt) go func() { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 1cdbfe866863..cdbff4d8ff1a 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -26,7 +26,6 @@ import ( "sort" "strconv" "strings" - "syscall" "time" "github.com/elastic/gosigar" @@ -45,6 +44,7 @@ import ( "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/wemix" + "golang.org/x/sys/unix" // Force-load the tracer engines to trigger registration _ "github.com/ethereum/go-ethereum/eth/tracers/js" @@ -514,8 +514,8 @@ func limitMaxRss(max int64) { timer := time.NewTimer(interval) for { <-timer.C - rusage := syscall.Rusage{} - err := syscall.Getrusage(syscall.RUSAGE_SELF, &rusage) + rusage := unix.Rusage{} + err := unix.Getrusage(unix.RUSAGE_SELF, &rusage) if err != nil { log.Error("Getrusage() failed:", "reason", err) } else { diff --git a/cmd/geth/wemixcmd.go b/cmd/geth/wemixcmd.go index 632ac93f51b3..d301dd9c6a9e 100644 --- a/cmd/geth/wemixcmd.go +++ b/cmd/geth/wemixcmd.go @@ -17,7 +17,6 @@ import ( "path/filepath" "strconv" "strings" - "syscall" "github.com/charlanxcc/logrot" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -29,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/wemix/metclient" + "golang.org/x/sys/unix" "gopkg.in/urfave/cli.v1" ) @@ -667,10 +667,10 @@ func logrota(ctx *cli.Context) error { if err != nil { return err } - syscall.Close(syscall.Stdout) - syscall.Close(syscall.Stdout) - syscall.Dup2(int(w.Fd()), syscall.Stdout) - syscall.Dup2(int(w.Fd()), syscall.Stderr) + unix.Close(unix.Stdout) + unix.Close(unix.Stdout) + unix.Dup2(int(w.Fd()), unix.Stdout) + unix.Dup2(int(w.Fd()), unix.Stderr) go logrot.LogRotate(r, logFile, logSize, logCount) diff --git a/cmd/utils/cmd.go b/cmd/utils/cmd.go index 47ad3b22c8dd..d9d8e605b15f 100644 --- a/cmd/utils/cmd.go +++ b/cmd/utils/cmd.go @@ -27,7 +27,6 @@ import ( "os/signal" "runtime" "strings" - "syscall" "time" "github.com/ethereum/go-ethereum/common" @@ -41,6 +40,7 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/rlp" + "golang.org/x/sys/unix" "gopkg.in/urfave/cli.v1" ) @@ -74,7 +74,7 @@ func StartNode(ctx *cli.Context, stack *node.Node, isConsole bool) { } go func() { sigc := make(chan os.Signal, 1) - signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM) + signal.Notify(sigc, unix.SIGINT, unix.SIGTERM) defer signal.Stop(sigc) minFreeDiskSpace := 2 * ethconfig.Defaults.TrieDirtyCache // Default 2 * 256Mb @@ -105,7 +105,7 @@ func StartNode(ctx *cli.Context, stack *node.Node, isConsole bool) { // However, SIGTERM still shuts down the node. for { sig := <-sigc - if sig == syscall.SIGTERM { + if sig == unix.SIGTERM { shutdown() return } @@ -126,7 +126,7 @@ func monitorFreeDiskSpace(sigc chan os.Signal, path string, freeDiskSpaceCritica } if freeSpace < freeDiskSpaceCritical { log.Error("Low disk space. Gracefully shutting down Geth to prevent database corruption.", "available", common.StorageSize(freeSpace)) - sigc <- syscall.SIGTERM + sigc <- unix.SIGTERM break } else if freeSpace < 2*freeDiskSpaceCritical { log.Warn("Disk space is running low. Geth will shutdown if disk space runs below critical level.", "available", common.StorageSize(freeSpace), "critical_level", common.StorageSize(freeDiskSpaceCritical)) @@ -140,7 +140,7 @@ func ImportChain(chain *core.BlockChain, fn string) error { // If a signal is received, the import will stop at the next batch. interrupt := make(chan os.Signal, 1) stop := make(chan struct{}) - signal.Notify(interrupt, syscall.SIGINT, syscall.SIGTERM) + signal.Notify(interrupt, unix.SIGINT, unix.SIGTERM) defer signal.Stop(interrupt) defer close(interrupt) go func() { diff --git a/common/fdlimit/fdlimit_bsd.go b/common/fdlimit/fdlimit_bsd.go index a3a6902c0925..abe73b96197a 100644 --- a/common/fdlimit/fdlimit_bsd.go +++ b/common/fdlimit/fdlimit_bsd.go @@ -19,7 +19,7 @@ package fdlimit -import "syscall" +import "golang.org/x/sys/unix" // This file is largely identical to fdlimit_unix.go, // but Rlimit fields have type int64 on *BSD so it needs @@ -29,8 +29,8 @@ import "syscall" // to the maximum hard-limit allowed by the OS. func Raise(max uint64) (uint64, error) { // Get the current limit - var limit syscall.Rlimit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + var limit unix.Rlimit + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } // Try to update the limit to the max allowance @@ -38,10 +38,10 @@ func Raise(max uint64) (uint64, error) { if limit.Cur > int64(max) { limit.Cur = int64(max) } - if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + if err := unix.Setrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } return uint64(limit.Cur), nil @@ -50,8 +50,8 @@ func Raise(max uint64) (uint64, error) { // Current retrieves the number of file descriptors allowed to be opened by this // process. func Current() (int, error) { - var limit syscall.Rlimit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + var limit unix.Rlimit + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } return int(limit.Cur), nil @@ -60,8 +60,8 @@ func Current() (int, error) { // Maximum retrieves the maximum number of file descriptors this process is // allowed to request for itself. func Maximum() (int, error) { - var limit syscall.Rlimit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + var limit unix.Rlimit + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } return int(limit.Max), nil diff --git a/common/fdlimit/fdlimit_darwin.go b/common/fdlimit/fdlimit_darwin.go index 6b26fa00f12c..dc932238eae7 100644 --- a/common/fdlimit/fdlimit_darwin.go +++ b/common/fdlimit/fdlimit_darwin.go @@ -16,7 +16,7 @@ package fdlimit -import "syscall" +import "golang.org/x/sys/unix" // hardlimit is the number of file descriptors allowed at max by the kernel. const hardlimit = 10240 @@ -26,8 +26,8 @@ const hardlimit = 10240 // Returns the size it was set to (may differ from the desired 'max') func Raise(max uint64) (uint64, error) { // Get the current limit - var limit syscall.Rlimit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + var limit unix.Rlimit + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } // Try to update the limit to the max allowance @@ -35,11 +35,11 @@ func Raise(max uint64) (uint64, error) { if limit.Cur > max { limit.Cur = max } - if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + if err := unix.Setrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } // MacOS can silently apply further caps, so retrieve the actually set limit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } return limit.Cur, nil @@ -48,8 +48,8 @@ func Raise(max uint64) (uint64, error) { // Current retrieves the number of file descriptors allowed to be opened by this // process. func Current() (int, error) { - var limit syscall.Rlimit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + var limit unix.Rlimit + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } return int(limit.Cur), nil @@ -59,8 +59,8 @@ func Current() (int, error) { // allowed to request for itself. func Maximum() (int, error) { // Retrieve the maximum allowed by dynamic OS limits - var limit syscall.Rlimit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + var limit unix.Rlimit + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } // Cap it to OPEN_MAX (10240) because macos is a special snowflake diff --git a/common/fdlimit/fdlimit_unix.go b/common/fdlimit/fdlimit_unix.go index a1f388ebb78d..ce6bd41bceb2 100644 --- a/common/fdlimit/fdlimit_unix.go +++ b/common/fdlimit/fdlimit_unix.go @@ -19,15 +19,15 @@ package fdlimit -import "syscall" +import "golang.org/x/sys/unix" // Raise tries to maximize the file descriptor allowance of this process // to the maximum hard-limit allowed by the OS. // Returns the size it was set to (may differ from the desired 'max') func Raise(max uint64) (uint64, error) { // Get the current limit - var limit syscall.Rlimit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + var limit unix.Rlimit + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } // Try to update the limit to the max allowance @@ -35,11 +35,11 @@ func Raise(max uint64) (uint64, error) { if limit.Cur > max { limit.Cur = max } - if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + if err := unix.Setrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } // MacOS can silently apply further caps, so retrieve the actually set limit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } return limit.Cur, nil @@ -48,8 +48,8 @@ func Raise(max uint64) (uint64, error) { // Current retrieves the number of file descriptors allowed to be opened by this // process. func Current() (int, error) { - var limit syscall.Rlimit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + var limit unix.Rlimit + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } return int(limit.Cur), nil @@ -58,8 +58,8 @@ func Current() (int, error) { // Maximum retrieves the maximum number of file descriptors this process is // allowed to request for itself. func Maximum() (int, error) { - var limit syscall.Rlimit - if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &limit); err != nil { + var limit unix.Rlimit + if err := unix.Getrlimit(unix.RLIMIT_NOFILE, &limit); err != nil { return 0, err } return int(limit.Max), nil diff --git a/console/console.go b/console/console.go index 78706860e0cb..0b1b21165183 100644 --- a/console/console.go +++ b/console/console.go @@ -27,7 +27,6 @@ import ( "sort" "strings" "sync" - "syscall" "github.com/dop251/goja" "github.com/ethereum/go-ethereum/console/prompt" @@ -37,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/rpc" "github.com/mattn/go-colorable" "github.com/peterh/liner" + "golang.org/x/sys/unix" ) var ( @@ -371,7 +371,7 @@ func (c *Console) interruptHandler() { // Unfortunately, it is not possible to abort the prompt in this case and // the c.readLines goroutine leaks. sig := make(chan os.Signal, 1) - signal.Notify(sig, syscall.SIGINT) + signal.Notify(sig, unix.SIGINT) defer signal.Stop(sig) for { diff --git a/internal/cmdtest/test_cmd.go b/internal/cmdtest/test_cmd.go index fd7a4a8b7f4c..3abdb1fe8b5d 100644 --- a/internal/cmdtest/test_cmd.go +++ b/internal/cmdtest/test_cmd.go @@ -27,12 +27,12 @@ import ( "strings" "sync" "sync/atomic" - "syscall" "testing" "text/template" "time" "github.com/docker/docker/pkg/reexec" + "golang.org/x/sys/unix" ) func NewTestCmd(t *testing.T, data interface{}) *TestCmd { @@ -208,7 +208,7 @@ func (tt *TestCmd) ExitStatus() int { if tt.Err != nil { exitErr := tt.Err.(*exec.ExitError) if exitErr != nil { - if status, ok := exitErr.Sys().(syscall.WaitStatus); ok { + if status, ok := exitErr.Sys().(unix.WaitStatus); ok { return status.ExitStatus() } } diff --git a/metrics/cputime_unix.go b/metrics/cputime_unix.go index 3c56a75d0077..3948ef6f8882 100644 --- a/metrics/cputime_unix.go +++ b/metrics/cputime_unix.go @@ -20,15 +20,14 @@ package metrics import ( - syscall "golang.org/x/sys/unix" - "github.com/ethereum/go-ethereum/log" + "golang.org/x/sys/unix" ) // getProcessCPUTime retrieves the process' CPU time since program startup. func getProcessCPUTime() int64 { - var usage syscall.Rusage - if err := syscall.Getrusage(syscall.RUSAGE_SELF, &usage); err != nil { + var usage unix.Rusage + if err := unix.Getrusage(unix.RUSAGE_SELF, &usage); err != nil { log.Warn("Failed to retrieve CPU time", "err", err) return 0 } diff --git a/node/errors.go b/node/errors.go index 67547bf691f1..6855c8ad6103 100644 --- a/node/errors.go +++ b/node/errors.go @@ -20,7 +20,8 @@ import ( "errors" "fmt" "reflect" - "syscall" + + "golang.org/x/sys/unix" ) var ( @@ -33,7 +34,7 @@ var ( ) func convertFileLockError(err error) error { - if errno, ok := err.(syscall.Errno); ok && datadirInUseErrnos[uint(errno)] { + if errno, ok := err.(unix.Errno); ok && datadirInUseErrnos[uint(errno)] { return ErrDatadirUsed } return err diff --git a/p2p/netutil/toobig_windows.go b/p2p/netutil/toobig_windows.go index 652903e83c30..128150f7bd1f 100644 --- a/p2p/netutil/toobig_windows.go +++ b/p2p/netutil/toobig_windows.go @@ -22,10 +22,11 @@ package netutil import ( "net" "os" - "syscall" + + "golang.org/x/sys/unix" ) -const _WSAEMSGSIZE = syscall.Errno(10040) +const _WSAEMSGSIZE = unix.Errno(10040) // isPacketTooBig reports whether err indicates that a UDP packet didn't // fit the receive buffer. On Windows, WSARecvFrom returns diff --git a/p2p/simulations/adapters/exec.go b/p2p/simulations/adapters/exec.go index 35ccdfb06882..d6d8de89fc69 100644 --- a/p2p/simulations/adapters/exec.go +++ b/p2p/simulations/adapters/exec.go @@ -31,7 +31,6 @@ import ( "path/filepath" "strings" "sync" - "syscall" "time" "github.com/docker/docker/pkg/reexec" @@ -41,6 +40,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/enode" "github.com/ethereum/go-ethereum/rpc" "github.com/gorilla/websocket" + "golang.org/x/sys/unix" ) func init() { @@ -295,7 +295,7 @@ func (n *ExecNode) Stop() error { n.Info = nil } - if err := n.Cmd.Process.Signal(syscall.SIGTERM); err != nil { + if err := n.Cmd.Process.Signal(unix.SIGTERM); err != nil { return n.Cmd.Process.Kill() } waitErr := make(chan error, 1) @@ -438,7 +438,7 @@ func execP2PNode() { // Stop the stack if we get a SIGTERM signal. go func() { sigc := make(chan os.Signal, 1) - signal.Notify(sigc, syscall.SIGTERM) + signal.Notify(sigc, unix.SIGTERM) defer signal.Stop(sigc) <-sigc log.Info("Received SIGTERM, shutting down...") From 3cb78be799e66cacb908244dd7d62e4d2712122b Mon Sep 17 00:00:00 2001 From: eomti-wm Date: Thu, 23 May 2024 10:46:31 +0900 Subject: [PATCH 24/51] fix: add checking brioche config --- eth/api.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/api.go b/eth/api.go index 613c008d54f7..9795a75a6e4f 100644 --- a/eth/api.go +++ b/eth/api.go @@ -700,7 +700,7 @@ type HalvingInfo struct { func (api *BriocheConfigAPI) HalvingSchedule() []*HalvingInfo { bc := api.BriocheConfig() - if bc.FirstHalvingBlock == nil || bc.HalvingPeriod == nil { + if bc.FirstHalvingBlock == nil || bc.HalvingPeriod == nil || bc.HalvingTimes == 0 { return nil } From 18c3921865cbc6b77caa3af5b4dc10ee7fb854d5 Mon Sep 17 00:00:00 2001 From: paul-ahn-wm Date: Thu, 23 May 2024 14:36:01 +0900 Subject: [PATCH 25/51] Fix: fix DockerFiles --- Dockerfile.wemix | 102 +++++++++++++++++++++++----- containers/docker/wemix/Dockerfile | 105 ++++++++++++++++++++++++----- 2 files changed, 172 insertions(+), 35 deletions(-) diff --git a/Dockerfile.wemix b/Dockerfile.wemix index 632e6ce193e0..c130bd9529b8 100644 --- a/Dockerfile.wemix +++ b/Dockerfile.wemix @@ -1,24 +1,92 @@ -# builder image +# Stage 1: Build stage +FROM golang:1.19 as builder -FROM ubuntu:focal as base +# Set environment variables +ENV PATH=/usr/local/go/bin:$PATH -SHELL ["/bin/bash", "-c"] +# Update and upgrade the package list +RUN apt-get update && \ + apt-get upgrade -q -y -RUN apt-get update -q -y && apt-get upgrade -q -y -RUN DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata -RUN DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends build-essential ca-certificates curl libjemalloc-dev liblz4-dev libsnappy-dev libzstd-dev libudev-dev git +# Install required packages +RUN apt-get install -y --no-install-recommends \ + git \ + ca-certificates \ + openssl \ + make && \ + rm -rf /var/lib/apt/lists/* -# golang -RUN curl -sL -o /tmp/go.tar.gz https://dl.google.com/go/$(curl -sL https://golang.org/VERSION?m=text | head -1).linux-amd64.tar.gz && \ - pushd /usr/local/ && \ - tar xfz /tmp/go.tar.gz && \ - cd /usr/local/bin/ && \ - ln -sf ../go/bin/* . && \ - popd && \ - rm /tmp/go.tar.gz +# Define the location for custom certificates +ARG cert_location=/usr/local/share/ca-certificates -RUN apt autoremove && apt autoclean +# Fetch and install certificates for github.com and proxy.golang.org +RUN openssl s_client -showcerts -connect github.com:443 /dev/null | \ + openssl x509 -outform PEM > ${cert_location}/github.crt && \ + openssl s_client -showcerts -connect proxy.golang.org:443 /dev/null | \ + openssl x509 -outform PEM > ${cert_location}/proxy.golang.crt && \ + update-ca-certificates -ENTRYPOINT ["/bin/bash", "-c"] +# Clone the repository, install dependencies, and build the project +RUN git clone https://github.com/wemixarchive/go-wemix.git /go-wemix && \ + cd /go-wemix && \ + go mod download && \ + make -# EOF +# Clean up unnecessary packages and files after building +RUN apt-get remove -y \ + git \ + ca-certificates \ + openssl \ + make && \ + apt autoremove -y && \ + apt-get clean + +# Stage 2: Runtime stage +FROM ubuntu:22.04 + +# Set environment variables +ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + +# Update and upgrade the package list +RUN apt-get update && \ + apt-get upgrade -q -y + +# Install required runtime packages +RUN apt-get install -y --no-install-recommends \ + g++ \ + libc-dev \ + ca-certificates \ + bash \ + wget && \ + update-ca-certificates && \ + rm -rf /var/lib/apt/lists/* + +# Create directories for wemix +RUN mkdir -p /usr/local/wemix /usr/local/wemix/keystore + +# Copy the built binaries and configuration files from the builder stage +COPY --from=builder /go-wemix/build /usr/local/wemix/ + +# Download and install solc +RUN wget -nv -O /usr/local/bin/solc https://github.com/ethereum/solidity/releases/download/v0.4.24/solc-static-linux && \ + chmod a+x /usr/local/bin/solc + +# Create new accounts for wemix +RUN bash -c 'for i in 1 2 3 4; do \ + /usr/local/wemix/bin/gwemix wemix new-account --password <(echo demo) --out /usr/local/wemix/keystore/account-$i; \ +done' + +# Clean up unnecessary packages +RUN apt-get remove -y \ + g++ \ + libc-dev \ + wget && \ + apt autoremove -y && \ + apt-get clean + +# Expose necessary ports +EXPOSE 10009 +EXPOSE 10010 + +# Set the entrypoint +ENTRYPOINT ["/usr/local/wemix/bin/gwemix"] \ No newline at end of file diff --git a/containers/docker/wemix/Dockerfile b/containers/docker/wemix/Dockerfile index 662ec9c997ab..c130bd9529b8 100644 --- a/containers/docker/wemix/Dockerfile +++ b/containers/docker/wemix/Dockerfile @@ -1,23 +1,92 @@ -FROM ubuntu:xenial - -ENV PATH=/usr/lib/go-1.9/bin:$PATH - -RUN /bin/bash -c '\ - apt-get update && apt-get upgrade -q -y && \ - apt-get install -y --no-install-recommends golang-1.9 git make gcc libc-dev ca-certificates wget && \ - git clone https://github.com/wemix3/go-wemix && \ - (cd go-wemix && make) && \ - mkdir -p /usr/local/wemix /usr/local/wemix/keystore && \ - cp -r go-wemix/build/bin go-wemix/build/conf /usr/local/wemix/ && \ - /usr/bin/wget -nv -O /usr/local/bin/solc https://github.com/ethereum/solidity/releases/download/v0.4.24/solc-static-linux && \ - chmod a+x /usr/local/bin/solc && \ - for i in 1 2 3 4; do \ +# Stage 1: Build stage +FROM golang:1.19 as builder + +# Set environment variables +ENV PATH=/usr/local/go/bin:$PATH + +# Update and upgrade the package list +RUN apt-get update && \ + apt-get upgrade -q -y + +# Install required packages +RUN apt-get install -y --no-install-recommends \ + git \ + ca-certificates \ + openssl \ + make && \ + rm -rf /var/lib/apt/lists/* + +# Define the location for custom certificates +ARG cert_location=/usr/local/share/ca-certificates + +# Fetch and install certificates for github.com and proxy.golang.org +RUN openssl s_client -showcerts -connect github.com:443 /dev/null | \ + openssl x509 -outform PEM > ${cert_location}/github.crt && \ + openssl s_client -showcerts -connect proxy.golang.org:443 /dev/null | \ + openssl x509 -outform PEM > ${cert_location}/proxy.golang.crt && \ + update-ca-certificates + +# Clone the repository, install dependencies, and build the project +RUN git clone https://github.com/wemixarchive/go-wemix.git /go-wemix && \ + cd /go-wemix && \ + go mod download && \ + make + +# Clean up unnecessary packages and files after building +RUN apt-get remove -y \ + git \ + ca-certificates \ + openssl \ + make && \ + apt autoremove -y && \ + apt-get clean + +# Stage 2: Runtime stage +FROM ubuntu:22.04 + +# Set environment variables +ENV SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt + +# Update and upgrade the package list +RUN apt-get update && \ + apt-get upgrade -q -y + +# Install required runtime packages +RUN apt-get install -y --no-install-recommends \ + g++ \ + libc-dev \ + ca-certificates \ + bash \ + wget && \ + update-ca-certificates && \ + rm -rf /var/lib/apt/lists/* + +# Create directories for wemix +RUN mkdir -p /usr/local/wemix /usr/local/wemix/keystore + +# Copy the built binaries and configuration files from the builder stage +COPY --from=builder /go-wemix/build /usr/local/wemix/ + +# Download and install solc +RUN wget -nv -O /usr/local/bin/solc https://github.com/ethereum/solidity/releases/download/v0.4.24/solc-static-linux && \ + chmod a+x /usr/local/bin/solc + +# Create new accounts for wemix +RUN bash -c 'for i in 1 2 3 4; do \ /usr/local/wemix/bin/gwemix wemix new-account --password <(echo demo) --out /usr/local/wemix/keystore/account-$i; \ - done && \ - apt-get remove -y golang-1.9 git make gcc libc-dev wget && apt autoremove -y && apt-get clean && \ - rm -rf /go-wemix' +done' + +# Clean up unnecessary packages +RUN apt-get remove -y \ + g++ \ + libc-dev \ + wget && \ + apt autoremove -y && \ + apt-get clean +# Expose necessary ports EXPOSE 10009 EXPOSE 10010 -ENTRYPOINT ["/bin/bash"] +# Set the entrypoint +ENTRYPOINT ["/usr/local/wemix/bin/gwemix"] \ No newline at end of file From c1f32fc96e0a4a65782724d5d37ac633e90b6ac6 Mon Sep 17 00:00:00 2001 From: eomti-wm Date: Thu, 23 May 2024 14:56:36 +0900 Subject: [PATCH 26/51] fix: fix incorrect condition --- eth/api.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/eth/api.go b/eth/api.go index 9795a75a6e4f..5248a430aaee 100644 --- a/eth/api.go +++ b/eth/api.go @@ -705,7 +705,7 @@ func (api *BriocheConfigAPI) HalvingSchedule() []*HalvingInfo { } result := make([]*HalvingInfo, 0) - for i := uint64(1); i <= bc.HalvingTimes; i++ { + for i := uint64(0); i < bc.HalvingTimes; i++ { startBlock := new(big.Int).Add(bc.FirstHalvingBlock, new(big.Int).Mul(bc.HalvingPeriod, new(big.Int).SetUint64(i))) result = append(result, &HalvingInfo{ HalvingTimes: i + 1, @@ -727,7 +727,7 @@ func (api *BriocheConfigAPI) GetBriocheBlockReward(height *big.Int) *big.Int { wemixInfo := *(wemixapi.Info().(*map[string]interface{})) if height == nil { - height = api.e.blockchain.CurrentHeader().Number + height = api.e.BlockChain().CurrentHeader().Number } if config.IsBrioche(height) { From 757f641c0a354f05ab41a5eb4221f797208b5eb8 Mon Sep 17 00:00:00 2001 From: egonspace Date: Thu, 23 May 2024 15:27:12 +0900 Subject: [PATCH 27/51] fix: remove unused functions --- wemix/admin.go | 31 ------------------------------- wemix/miner/miner.go | 9 --------- 2 files changed, 40 deletions(-) diff --git a/wemix/admin.go b/wemix/admin.go index 3b0f4d07d75e..677e9ce6c30f 100644 --- a/wemix/admin.go +++ b/wemix/admin.go @@ -1014,31 +1014,6 @@ type reward struct { Reward *big.Int `json:"reward"` } -func (ma *wemixAdmin) verifyRewards(r1, r2 []byte) error { - var err error - var a, b []reward - - if err = json.Unmarshal(r1, &a); err != nil { - return err - } - if err = json.Unmarshal(r2, &b); err != nil { - return err - } - - err = fmt.Errorf("Incorrect Rewards") - if len(a) != len(b) { - return err - } - for i := 0; i < len(a); i++ { - if !bytes.Equal(a[i].Addr.Bytes(), b[i].Addr.Bytes()) || - a[i].Reward != b[i].Reward { - return err - } - } - - return nil -} - // handles rewards in testnet block 94 func handleBlock94Rewards(height *big.Int, rp *rewardParameters, fees *big.Int) []reward { if height.Int64() != 94 || len(rp.members) != 0 || @@ -1207,11 +1182,6 @@ func calculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance return calculateRewardsWithParams(config, rp, num, fees, addBalance) } -func verifyRewards(num *big.Int, rewards string) error { - return nil - //return admin.verifyRewards(num, rewards) -} - func getCoinbase(height *big.Int) (coinbase common.Address, err error) { if admin == nil { err = wemixminer.ErrNotInitialized @@ -1824,7 +1794,6 @@ func init() { wemixminer.AmHubFunc = AmHub wemixminer.SuggestGasPriceFunc = suggestGasPrice wemixminer.CalculateRewardsFunc = calculateRewards - wemixminer.VerifyRewardsFunc = verifyRewards wemixminer.GetCoinbaseFunc = getCoinbase wemixminer.SignBlockFunc = signBlock wemixminer.VerifyBlockSigFunc = verifyBlockSig diff --git a/wemix/miner/miner.go b/wemix/miner/miner.go index 339cb9f0e57c..f0ba1bd35db8 100644 --- a/wemix/miner/miner.go +++ b/wemix/miner/miner.go @@ -17,7 +17,6 @@ var ( IsPartnerFunc func(string) bool AmHubFunc func(string) int CalculateRewardsFunc func(*params.ChainConfig, *big.Int, *big.Int, func(common.Address, *big.Int)) ([]byte, error) - VerifyRewardsFunc func(*big.Int, string) error GetCoinbaseFunc func(height *big.Int) (coinbase common.Address, err error) SignBlockFunc func(height *big.Int, hash common.Hash) (coinbase common.Address, sig []byte, err error) VerifyBlockSigFunc func(height *big.Int, coinbase common.Address, nodeId []byte, hash common.Hash, sig []byte, checkMinerLimit bool) bool @@ -87,14 +86,6 @@ func CalculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance } } -func VerifyRewards(num *big.Int, rewards string) error { - if VerifyRewardsFunc == nil { - return ErrNotInitialized - } else { - return VerifyRewardsFunc(num, rewards) - } -} - func GetCoinbase(height *big.Int) (coinbase common.Address, err error) { if GetCoinbaseFunc == nil { err = ErrNotInitialized From 1067c615a9cc99b62f7f195b28409f11fd613daa Mon Sep 17 00:00:00 2001 From: paul-ahn-wm Date: Thu, 23 May 2024 16:03:21 +0900 Subject: [PATCH 28/51] Fix: fix exitstatus fn --- internal/cmdtest/test_cmd.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/internal/cmdtest/test_cmd.go b/internal/cmdtest/test_cmd.go index 3abdb1fe8b5d..b9942e2e5a26 100644 --- a/internal/cmdtest/test_cmd.go +++ b/internal/cmdtest/test_cmd.go @@ -32,7 +32,6 @@ import ( "time" "github.com/docker/docker/pkg/reexec" - "golang.org/x/sys/unix" ) func NewTestCmd(t *testing.T, data interface{}) *TestCmd { @@ -208,9 +207,7 @@ func (tt *TestCmd) ExitStatus() int { if tt.Err != nil { exitErr := tt.Err.(*exec.ExitError) if exitErr != nil { - if status, ok := exitErr.Sys().(unix.WaitStatus); ok { - return status.ExitStatus() - } + return exitErr.ProcessState.ExitCode() } } return 0 From 3e13bd8aeda50c6d94d12731272f159cc899d0e4 Mon Sep 17 00:00:00 2001 From: kai-yu-wm Date: Thu, 23 May 2024 16:52:15 +0900 Subject: [PATCH 29/51] Fix: fix docker-compose.yml --- Dockerfile.wemix | 6 +- containers/docker/wemix/Dockerfile | 6 +- containers/docker/wemix/docker-compose.yml | 81 +++- containers/docker/wemix/testdata/.rc | 2 + containers/docker/wemix/testdata/bootnode.sh | 25 ++ containers/docker/wemix/testdata/config.json | 69 +++ .../wemix/testdata/deploy-governance.js | 420 ++++++++++++++++++ containers/docker/wemix/testdata/genesis.json | 42 ++ containers/docker/wemix/testdata/gwemix.sh | 349 +++++++++++++++ .../docker/wemix/testdata/keystore/account1 | 1 + .../docker/wemix/testdata/keystore/account2 | 1 + .../docker/wemix/testdata/keystore/account3 | 1 + .../wemix/testdata/keystore/maintenance | 1 + .../docker/wemix/testdata/nodekey/nodekey1 | 1 + .../docker/wemix/testdata/nodekey/nodekey2 | 1 + .../docker/wemix/testdata/nodekey/nodekey3 | 1 + 16 files changed, 984 insertions(+), 23 deletions(-) create mode 100644 containers/docker/wemix/testdata/.rc create mode 100755 containers/docker/wemix/testdata/bootnode.sh create mode 100644 containers/docker/wemix/testdata/config.json create mode 100644 containers/docker/wemix/testdata/deploy-governance.js create mode 100644 containers/docker/wemix/testdata/genesis.json create mode 100755 containers/docker/wemix/testdata/gwemix.sh create mode 100644 containers/docker/wemix/testdata/keystore/account1 create mode 100644 containers/docker/wemix/testdata/keystore/account2 create mode 100644 containers/docker/wemix/testdata/keystore/account3 create mode 100644 containers/docker/wemix/testdata/keystore/maintenance create mode 100644 containers/docker/wemix/testdata/nodekey/nodekey1 create mode 100644 containers/docker/wemix/testdata/nodekey/nodekey2 create mode 100644 containers/docker/wemix/testdata/nodekey/nodekey3 diff --git a/Dockerfile.wemix b/Dockerfile.wemix index c130bd9529b8..3001685fc0f5 100644 --- a/Dockerfile.wemix +++ b/Dockerfile.wemix @@ -64,6 +64,9 @@ RUN apt-get install -y --no-install-recommends \ # Create directories for wemix RUN mkdir -p /usr/local/wemix /usr/local/wemix/keystore +# Set environment variables +ENV PATH=/usr/local/wemix/bin:$PATH + # Copy the built binaries and configuration files from the builder stage COPY --from=builder /go-wemix/build /usr/local/wemix/ @@ -85,8 +88,7 @@ RUN apt-get remove -y \ apt-get clean # Expose necessary ports -EXPOSE 10009 -EXPOSE 10010 +EXPOSE 8588 8589 8598 # Set the entrypoint ENTRYPOINT ["/usr/local/wemix/bin/gwemix"] \ No newline at end of file diff --git a/containers/docker/wemix/Dockerfile b/containers/docker/wemix/Dockerfile index c130bd9529b8..3001685fc0f5 100644 --- a/containers/docker/wemix/Dockerfile +++ b/containers/docker/wemix/Dockerfile @@ -64,6 +64,9 @@ RUN apt-get install -y --no-install-recommends \ # Create directories for wemix RUN mkdir -p /usr/local/wemix /usr/local/wemix/keystore +# Set environment variables +ENV PATH=/usr/local/wemix/bin:$PATH + # Copy the built binaries and configuration files from the builder stage COPY --from=builder /go-wemix/build /usr/local/wemix/ @@ -85,8 +88,7 @@ RUN apt-get remove -y \ apt-get clean # Expose necessary ports -EXPOSE 10009 -EXPOSE 10010 +EXPOSE 8588 8589 8598 # Set the entrypoint ENTRYPOINT ["/usr/local/wemix/bin/gwemix"] \ No newline at end of file diff --git a/containers/docker/wemix/docker-compose.yml b/containers/docker/wemix/docker-compose.yml index 1773a3e8b5e7..b180cc458fc3 100644 --- a/containers/docker/wemix/docker-compose.yml +++ b/containers/docker/wemix/docker-compose.yml @@ -1,34 +1,77 @@ -version: "3" services: wemix1: - container_name: wemix1 + build: + context: . + dockerfile: Dockerfile + image: wemix/node-demo:latest hostname: wemix1 - stdin_open: true + networks: + wemix_bridge: + ipv4_address: 172.16.237.11 + restart: unless-stopped tty: true - build: . - image: wemix/multinode-demo:latest volumes: - - ".:/opt" - entrypoint: ["/usr/local/wemix/bin/gwemix-demo.sh", "start-leader", "wemix1", "wemix2", "wemix3"] + - /etc/localtime:/etc/localtime:ro + - ./testdata/bootnode.sh:/usr/local/wemix/bin/bootnode.sh:ro + - ./testdata/gwemix.sh:/usr/local/wemix/bin/gwemix.sh:ro + - ./testdata/config.json:/usr/local/wemix/conf/config.json:ro + - ./testdata/deploy-governance.js:/usr/local/wemix/conf/deploy-governance.js:ro + - ./testdata/genesis.json:/usr/local/wemix/genesis.json:ro + - ./testdata/.rc:/usr/local/wemix/.rc:ro + - ./testdata/keystore:/usr/local/wemix/keystore + - ./testdata/nodekey/nodekey1:/usr/local/wemix/geth/nodekey:ro + ports: + - 8588:8588 + - 8589:8589 + - 8598:8598 + container_name: wemix1 + entrypoint: ["sh", "-c", "bootnode.sh && sleep 5 && tail -f /usr/local/wemix/logs/log"] wemix2: - container_name: wemix2 + image: wemix/node-demo:latest hostname: wemix2 - stdin_open: true + networks: + wemix_bridge: + ipv4_address: 172.16.237.12 + restart: unless-stopped tty: true - image: wemix/multinode-demo:latest depends_on: - - wemix1 + wemix1: + condition: service_started volumes: - - ".:/opt" - entrypoint: ["/usr/local/wemix/bin/gwemix-demo.sh", "start"] + - /etc/localtime:/etc/localtime:ro + - ./testdata/gwemix.sh:/usr/local/wemix/bin/gwemix.sh:ro + - ./testdata/genesis.json:/usr/local/wemix/genesis.json:ro + - ./testdata/.rc:/usr/local/wemix/.rc:ro + - ./testdata/keystore/account2:/usr/local/wemix/keystore/account2 + - ./testdata/nodekey/nodekey2:/usr/local/wemix/geth/nodekey:ro + container_name: wemix2 + entrypoint: ["sh", "-c", "gwemix.sh start && sleep 5 && tail -f /usr/local/wemix/logs/log"] wemix3: - container_name: wemix3 + image: wemix/node-demo:latest hostname: wemix3 - stdin_open: true + networks: + wemix_bridge: + ipv4_address: 172.16.237.13 + restart: unless-stopped tty: true - image: wemix/multinode-demo:latest depends_on: - - wemix1 + wemix1: + condition: service_started volumes: - - ".:/opt" - entrypoint: ["/usr/local/wemix/bin/gwemix-demo.sh", "start"] + - /etc/localtime:/etc/localtime:ro + - ./testdata/gwemix.sh:/usr/local/wemix/bin/gwemix.sh:ro + - ./testdata/genesis.json:/usr/local/wemix/genesis.json:ro + - ./testdata/.rc:/usr/local/wemix/.rc:ro + - ./testdata/keystore/account3:/usr/local/wemix/keystore/account3 + - ./testdata/nodekey/nodekey3:/usr/local/wemix/geth/nodekey:ro + container_name: wemix3 + entrypoint: ["sh", "-c", "gwemix.sh start && sleep 5 && tail -f /usr/local/wemix/logs/log"] + +networks: + wemix_bridge: + name: wemix_bridge + driver: bridge + ipam: + driver: default + config: + - subnet: 172.16.237.0/24 diff --git a/containers/docker/wemix/testdata/.rc b/containers/docker/wemix/testdata/.rc new file mode 100644 index 000000000000..792df1fb93df --- /dev/null +++ b/containers/docker/wemix/testdata/.rc @@ -0,0 +1,2 @@ +PORT=8588 +DISCOVER=0 \ No newline at end of file diff --git a/containers/docker/wemix/testdata/bootnode.sh b/containers/docker/wemix/testdata/bootnode.sh new file mode 100755 index 000000000000..cba2bcf17303 --- /dev/null +++ b/containers/docker/wemix/testdata/bootnode.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +cd $(dirname ${BASH_SOURCE[0]})/.. + +gwemix.sh start +sleep 5 + +RESULT=$(gwemix --exec "admin.wemixInfo.etcd" attach gwemix.ipc) + +if [[ "$RESULT" == "Fatal:"* ]]; then + echo "Failed to start gwemix!" + exit 1 +elif [[ "$RESULT" == "{}" ]]; then + echo "Initailize governance" + + gwemix.sh init-gov wemix conf/config.json + sleep 5 + + gwemix --exec "admin.wemixInfo" attach gwemix.ipc + gwemix --exec "admin.etcdInit()" attach gwemix.ipc # Initialize etcd + sleep 5 + gwemix --exec "admin.wemixInfo.etcd" attach gwemix.ipc +fi + +echo "Started gwemix!" \ No newline at end of file diff --git a/containers/docker/wemix/testdata/config.json b/containers/docker/wemix/testdata/config.json new file mode 100644 index 000000000000..74b5e54acb81 --- /dev/null +++ b/containers/docker/wemix/testdata/config.json @@ -0,0 +1,69 @@ +{ + "extraData": "The beginning of Wemix3.0 localnet", + "staker": "0xf00d9928ed1dada205aec56ab85e0e2ab5670ad5", + "ecosystem": "0x92875d5ba8b104c375a471d58a6de4f75ccb431f", + "maintenance": "0x2c77f2c8997182e31a19ec48e321f4d09f36819e", + "feecollector": "0x2c77f2c8997182e31a19ec48e321f4d09f36819e", + "env": { + "ballotDurationMin": 86400, + "ballotDurationMax": 604800, + "stakingMin": 1500000000000000000000000, + "stakingMax": 1500000000000000000000000, + "MaxIdleBlockInterval": 100, + "blockCreationTime": 5000, + "blockRewardAmount": 1000000000000000000, + "maxPriorityFeePerGas": 100000000000, + "rewardDistributionMethod": [ 4000, 1000, 2500, 2500 ], + "maxBaseFee": 50000000000000, + "blockGasLimit": 105000000, + "baseFeeMaxChangeRate": 55, + "gasTargetPercentage": 30 + }, + "members": [ + { + "addr": "0x92875d5ba8b104c375a471d58a6de4f75ccb431f", + "stake": 1500000000000000000000000, + "name": "node1", + "id": "0xe4dfe854223c1b85ea7962cd724d98eec1863a49847eb749bc5caa519104713c78a972ebf263b13329ceb8a7b5959125ab6e9a3c73c15f659cc1291d0a7aae1e", + "ip": "172.16.237.11", + "port": 8589, + "bootnode": true + }, + { + "addr": "0xb61544371ef73161496009a77989da30f8f91867", + "stake": 1500000000000000000000000, + "name": "node2", + "id": "0x4b8b229f97bbe68fa7cfc43e357fe74503733d0cc236b8d176d896f33547d8fcfd59daa0b4f9e1a4e83157adf1a386ea314dfb9a3e6efe747948fa5e10d5fff5", + "ip": "172.16.237.12", + "port": 8589, + "bootnode": false + }, + { + "addr": "0x708ebe75a5dbc5f56176db6e84ce5740897e8a17", + "stake": 1500000000000000000000000, + "name": "node3", + "id": "0xa6f08d187a8da5d76f072b0f0d114e1469e77a53713b710177bd6206b16331b8ead7d41bdeec1df3bb0bb56de8f102e86ecaf44bb6affb4383151c603ff5ac10", + "ip": "172.16.237.13", + "port": 8589, + "bootnode": false + } + ], + "accounts": [ + { + "addr": "0x92875d5ba8b104c375a471d58a6de4f75ccb431f", + "balance": 2000000000000000000000000 + }, + { + "addr": "0xb61544371ef73161496009a77989da30f8f91867", + "balance": 2000000000000000000000000 + }, + { + "addr": "0x708ebe75a5dbc5f56176db6e84ce5740897e8a17", + "balance": 2000000000000000000000000 + }, + { + "addr": "0x2c77f2c8997182e31a19ec48e321f4d09f36819e", + "balance": 2000000000000000000000000 + } + ] +} \ No newline at end of file diff --git a/containers/docker/wemix/testdata/deploy-governance.js b/containers/docker/wemix/testdata/deploy-governance.js new file mode 100644 index 000000000000..5add63dd15b2 --- /dev/null +++ b/containers/docker/wemix/testdata/deploy-governance.js @@ -0,0 +1,420 @@ +// deploy-governance.js + +// uses offline wallet +var GovernanceDeployer = new function() { + this.wallet = ["keystore/account1", "keystore/account2", "keystore/account3"] + this.account = [] + this.from = null + this.gas = 21000 * 1400 + this.gasPrice = eth.gasPrice + this._nonce = [] + this.receiptCheckParams = { "interval": 100, "count": 300 } + + // bool log(var args...) + this.log = function() { + var msg = "" + for (var i in arguments) { + if (msg.length > 0) + msg += " " + msg += arguments[i] + } + console.log(msg) + return true + } + + // void verifyCfg(json data) + // verifies config data, and normalize addresses + // throws exception on failure + this.verifyCfg = function(data) { + if (data.accounts.length == 0 || data.members.length == 0) + throw "At least one account and node are required" + var bootnodeExists = false + for (var i in data.members) { + var m = data.members[i] + if (!web3.isAddress(m.addr)) + throw "Invalid address 1 " + m.addr + data.members[i].addr = web3.toChecksumAddress(m.addr) + if (m.bootnode) + bootnodeExists = true + } + if (!bootnodeExists) + throw "Bootnode is not designated" + for (var i in data.accounts) { + var a = data.accounts[i] + if (!web3.isAddress(a.addr)) + throw "Invalid address " + a.addr + data.accounts[i].addr = web3.toChecksumAddress(a.addr) + } + if (data.staker) { + if (!web3.isAddress(data.staker)) + throw "Invalid staker address " + data.staker + data.staker = web3.toChecksumAddress(data.staker) + } + if (data.ecosystem) { + if (!web3.isAddress(data.ecosystem)) + throw "Invalid ecosystem address " + data.ecosystem + data.ecosystem = web3.toChecksumAddress(data.ecosystem) + } + if (data.maintenance) { + if (!web3.isAddress(data.maintenance)) + throw "Invalid maintenance address " + data.maintenance + data.maintenance = web3.toChecksumAddress(data.maintenance) + } + if (data.feecollector) { + if (!web3.isAddress(data.feecollector)) + throw "Invalid feecollector address " + data.feecollector + data.feecollector = web3.toChecksumAddress(data.feecollector) + } + } + + // bytes packNum(int num) + // pack a number into 256 bit bytes + this.packNum = function(num) { + return web3.padLeft(web3.toHex(num).substr(2), 64, "0") + } + + // { "nodes": string, "stakes": string, "staker": address, + // "ecosystem": address, "maintenance": address, "feecollector": address, + // "env": { env variables } } + // getInitialGovernanceMembersAndNodes(json data) + this.getInitialGovernanceMembersAndNodes = function(data) { + var nodes = "0x", stakes = "0x" + + for (var i = 0, l = data.members.length; i < l; i++) { + var m = data.members[i], id + if (m.id.length != 128 && m.id.length != 130) + throw "Invalid enode id " + m.id + id = m.id.length == 128 ? m.id : m.id.substr(2) + if (m.addr) { + if (m.addr.indexOf("0x") == 0) + m.addr = m.addr.substr(2) + if (!m.staker) + m.staker = m.addr + if (!m.voter) + m.voter = m.addr + if (!m.reward) + m.reward = m.addr + } + if (m.staker) { + if (m.staker.indexOf("0x") == 0) + m.staker = m.staker.substr(2) + if (!m.addr) + m.addr = m.staker + if (!m.voter) + m.voter = m.staker + if (!m.reward) + m.reward = m.staker + } + if (!m.addr && !m.staker) + throw "Address & staker are missing" + nodes += web3.padLeft(m.staker, 64, "0") + + web3.padLeft(m.voter, 64, "0") + + web3.padLeft(m.reward, 64, "0") + + this.packNum(m.name.length) + web3.fromAscii(m.name).substr(2) + + this.packNum(id.length/2) + id + + this.packNum(m.ip.length) + web3.fromAscii(m.ip).substr(2) + + this.packNum(m.port) + + stakes += web3.padLeft(m.staker, 64, "0") + + this.packNum(m.stake) + } + return { + "nodes": nodes, + "stakes": stakes, + "staker": data.staker, + "ecosystem": data.ecosystem, + "maintenance": data.maintenance, + "feecollector": data.feecollector, + "env": data.env + } + } + + this.nonce = function(index) { + return this._nonce[index]++ + } + + // returns transaction hash, or throws error + this.deployContract = function(data) { + var tx = { + from: this.from, + data: data, + gas: this.gas, + gasPrice: this.gasPrice, + nonce: this.nonce(0) + } + var stx = offlineWalletSignTx(this.account[0].id, tx, eth.chainId()) + return eth.sendRawTransaction(stx) + } + + // wait for transaction receipt for contract address, then + // load a contract + // Contract resolveContract(ABI abi, hash txh) + this.resolveContract = function(abi, txh) { + for (var i = 0; i < this.receiptCheckParams.count; i++ ) { + var r = eth.getTransactionReceipt(txh) + if (r != null && r.contractAddress != null) { + var ctr = web3.eth.contract(abi).at(r.contractAddress) + ctr.transactionHash = txh + return ctr + } + msleep(this.receiptCheckParams.interval) + } + throw "Cannot get contract address for " + txh + } + + // sends a simple or method transaction, returns transaction hash + this.sendTx = function(to, value, data) { + var tx = {from:this.from, to:to, gas:this.gas, + gasPrice:this.gasPrice, nonce:this.nonce(0)} + if (value) + tx.value = value + if (data) + tx.data = data + var stx = offlineWalletSignTx(this.account[0].id, tx, eth.chainId()) + return eth.sendRawTransaction(stx) + } + + this.checkReceipt = function(tx) { + for (var i = 0; i < this.receiptCheckParams.count; i++ ) { + var r = eth.getTransactionReceipt(tx) + if (r != null) + return web3.toBigNumber(r.status) == 1 + msleep(this.receiptCheckParams.interval) + } + return false + //throw "Cannot get a transaction receipt for " + tx + } + + this.sendStakingDeposit = function (from, nonce, to, data, stake) { + this.log("staker addr = " + from.address) + var tx = { from: from.address, to: to, gas: this.gas, gasPrice: this.gasPrice, nonce: nonce, value: "0" } + tx.value = stake + if (data) tx.data = data + var stx = offlineWalletSignTx(from.id, tx, eth.chainId()) + + return eth.sendRawTransaction(stx) + } + + // bool deploy(string walletUrl, string password, string cfg) + this.deploy = function(cfg, doInitOnce) { + for (var i = 0; i < this.wallet.length; i++) { + w = offlineWalletOpen(this.wallet[i], "1") + if (!w || !w.id || !w.address) { + throw "Offline wallet is not loaded" + } + this.account[i] = w + this._nonce[i] = eth.getTransactionCount(this.account[i].address, 'pending') + } + this.from = this.account[0].address + + var data + if (!(data = loadFile(cfg))) + throw "cannot load governance contract .js or config .json file" + + // check if contracts exist + var contractNames = [ "Registry", "EnvStorageImp", "Staking", "StakingImp", + "BallotStorage", "EnvStorage", "GovImp", "Gov" ] + for (var i in contractNames) { + var cn = contractNames[i] + if (eval("typeof " + cn + "_data") == "undefined" || + eval("typeof " + cn + "_contract") == "undefined") + throw cn + " not found" + } + + // check config.js + eval("var data = " + data) + this.verifyCfg(data) + + // initial members and nodes data + var initData = this.getInitialGovernanceMembersAndNodes(data) + + // bootnode + var bootNode = { + "name": web3.fromAscii(data.members[0].name), + "id": data.members[0].id, + "ip": web3.fromAscii(data.members[0].ip), + "port": data.members[0].port, + "stake": data.members[0].stake + } + + // contacts, transactions to be deployed + var registry, envStorageImp, staking, stakingImp, ballotStorage, envStorage, govImp, gov + var txs = new Array() + + // 1. deploy Registry and EnvStorageImp contracts + this.log("Deploying Registry and EnvStorageImp...") + registry = this.deployContract(Registry_data) + envStorageImp = this.deployContract(EnvStorageImp_data) + stakingImp = this.deployContract(StakingImp_data) + + this.log("Waiting for receipts...") + envStorageImp = this.resolveContract(EnvStorageImp_contract.abi, envStorageImp) + registry = this.resolveContract(Registry_contract.abi, registry) + stakingImp = this.resolveContract(StakingImp_contract.abi, stakingImp); + + // 2. deploy Staking, BallotStorage, EnvStorage, GovImp, Gov + this.log("Deploying Staking, BallotStorage, EnvStorage, GovImp & Gov...") + var code = Staking_contract.getData(stakingImp.address, {data: Staking_data}) + staking = this.deployContract(code) + var code = BallotStorage_contract.getData(registry.address, {data: BallotStorage_data}) + ballotStorage = this.deployContract(code) + code = EnvStorage_contract.getData(envStorageImp.address, {data: EnvStorage_data}) + envStorage = this.deployContract(code) + govImp = this.deployContract(GovImp_data) + + this.log("Waiting for receipts...") + govImp = this.resolveContract(GovImp_contract.abi, govImp) + code = Gov_contract.getData(govImp.address, { data: Gov_data }) + gov = this.deployContract(code) + + this.log("Waiting for gov contract...") + gov = this.resolveContract(Gov_contract.abi, gov) + envStorage = this.resolveContract(EnvStorage_contract.abi, envStorage) + ballotStorage = this.resolveContract(BallotStorage_contract.abi, ballotStorage) + staking = this.resolveContract(Staking_contract.abi, staking) + + // 3. setup registry + this.log("Setting registry...") + txs.length = 0 + txs[txs.length] = this.sendTx(registry.address, null, + registry.setContractDomain.getData( + "Staking", staking.address)) + txs[txs.length] = this.sendTx(registry.address, null, + registry.setContractDomain.getData( + "BallotStorage", ballotStorage.address)) + txs[txs.length] = this.sendTx(registry.address, null, + registry.setContractDomain.getData( + "EnvStorage", envStorage.address)) + txs[txs.length] = this.sendTx(registry.address, null, + registry.setContractDomain.getData( + "GovernanceContract", gov.address)) + if (initData.staker) + txs[txs.length] = this.sendTx(registry.address, null, + registry.setContractDomain.getData( + "StakingReward", initData.staker)) + if (initData.ecosystem) + txs[txs.length] = this.sendTx(registry.address, null, + registry.setContractDomain.getData( + "Ecosystem", initData.ecosystem)) + if (initData.maintenance) + txs[txs.length] = this.sendTx(registry.address, null, + registry.setContractDomain.getData( + "Maintenance", initData.maintenance)) + if (initData.feecollector) + txs[txs.length] = this.sendTx(registry.address, null, + registry.setContractDomain.getData( + "FeeCollector", initData.feecollector)) + + // no need to wait for the receipts for the above + + // 4. initialize environment storage data: + this.log("Initializing environment storage...") + data.env = data.env || {} + // Just changing address doesn't work here. Address is embedded in + // the methods. Have to re-construct temporary EnvStorageImp here. + var tmpEnvStorageImp = web3.eth.contract(envStorageImp.abi).at(envStorage.address) + var envNames = [ + web3.sha3("blocksPer"), + web3.sha3("ballotDurationMin"), web3.sha3("ballotDurationMax"), + web3.sha3("stakingMin"), web3.sha3("stakingMax"), + web3.sha3("MaxIdleBlockInterval"), + web3.sha3("blockCreationTime"), + web3.sha3("blockRewardAmount"), + web3.sha3("maxPriorityFeePerGas"), + web3.sha3("blockRewardDistributionBlockProducer"), + web3.sha3("blockRewardDistributionStakingReward"), + web3.sha3("blockRewardDistributionEcosystem"), + web3.sha3("blockRewardDistributionMaintenance"), + web3.sha3("maxBaseFee"), + web3.sha3("blockGasLimit"), + web3.sha3("baseFeeMaxChangeRate"), + web3.sha3("gasTargetPercentage") ] + var rewardDistributionMethod = data.env.rewardDistributionMethod || [ 4000, 1000, 2500, 2500 ] + var envValues = [ + 1, + data.env.ballotDurationMin || 86400, + data.env.ballotDurationMax || 604800, + data.env.stakingMin || 1500000000000000000000000, + data.env.stakingMax || 1500000000000000000000000, + data.env.MaxIdleBlockInterval || 5, + data.env.blockCreationTime || 1000, + // mint amount: 1 wemix + data.env.blockRewardAmount || web3.toWei(1, 'ether'), + // tip: 100 gwei + data.env.maxPriorityFeePerGas || web3.toWei(100, 'gwei'), + // NCPs, WEMIX Staker, Eco System, Maintenance + rewardDistributionMethod[0], + rewardDistributionMethod[1], + rewardDistributionMethod[2], + rewardDistributionMethod[3], + // maxBaseFee * 21000 -> 1.05 wemix + data.env.maxBaseFee || web3.toWei(50000, 'gwei'), + data.env.blockGasLimit || 5000 * 21000, + data.env.baseFeeMaxChangeRate || 55, + data.env.gasTargetPercentage || 30 ] + txs[txs.length] = this.sendTx(envStorage.address, null, + tmpEnvStorageImp.initialize.getData(registry.address, envNames, envValues)) + + // 5. deposit staking + var tmpStakingImp = web3.eth.contract(stakingImp.abi).at(staking.address) + code = tmpStakingImp.init.getData(registry.address, + doInitOnce ? initData.stakes : "", {data: Staking_data}) + //"", {data: Staking_data}) + txs[txs.length] = this.sendTx(staking.address, null, code); + + for (var i = 1; i < this.account.length; i++) { + var d = tmpStakingImp.balanceOf.getData(this.account[i].address) + txs[txs.length] = this.sendStakingDeposit(this.account[i], this.nonce(i), staking.address, tmpStakingImp.deposit.getData(), web3.toBigNumber(bootNode.stake).toString(10)); + } + + this.log("txs.length = " + txs.length) + for(i=0;i /dev/null && pwd) + cd "$OPWD" +} + +function get_data_dir () +{ + if [ ! "$1" = "" ]; then + if [ -x "$1/bin/gwemix" ]; then + echo $1 + else + d=${WEMIX_DIR}/$1 + if [ -x "$d/bin/gwemix" ]; then + echo $d + fi + fi + else + echo $(dirname $(get_script_dir)) + fi +} + +# void init(String node, String config_json) +function init () +{ + NODE="$1" + CONFIG="$2" + + if [ ! -f "$CONFIG" ]; then + echo "Cannot find config file: $2" + return 1 + fi + + d=$(get_data_dir "${NODE}") + if [ -x "$d/bin/gwemix" ]; then + GWEMIX="$d/bin/gwemix" + else + echo "Cannot find gwemix" + return 1 + fi + + if [ ! -f "${d}/conf/genesis-template.json" ]; then + echo "Cannot find template files." + return 1 + fi + + echo "wiping out data..." + wipe $NODE + + [ -d "$d/geth" ] || mkdir -p "$d/geth" + [ -d "$d/logs" ] || mkdir -p "$d/logs" + + ${GWEMIX} wemix genesis --data "$CONFIG" --genesis "$d/conf/genesis-template.json" --out "$d/genesis.json" + [ $? = 0 ] || return $? + + echo "PORT=8588 +DISCOVER=0" > $d/.rc + ${GWEMIX} --datadir $d init $d/genesis.json + # echo "Generating dags for epoch 0 and 1..." + # ${GWEMIX} makedag 0 $d/.ethash & + # ${GWEMIX} makedag 30000 $d/.ethash & + wait +} + +# void init_gov(String node, String config_json, String account_file, bool doInitOnce) +# account_file can be +# 1. keystore file: "" +# 2. nano ledger: "ledger:" +# 3. trezor: "trezor:" +function init_gov () +{ + NODE="$1" + CONFIG="$2" + INIT_ONCE=true + + if [ ! -f "$CONFIG" ]; then + echo "Cannot find config file: $2" + return 1 + fi + + d=$(get_data_dir "${NODE}") + if [ -x "$d/bin/gwemix" ]; then + GWEMIX="$d/bin/gwemix" + else + echo "Cannot find gwemix" + return 1 + fi + + if [ ! -f "${d}/conf/WemixGovernance.js" ]; then + echo "Cannot find ${d}/conf/WemixGovernance.js" + return 1 + fi + + PORT=$(grep PORT ${d}/.rc | sed -e 's/PORT=//') + [ "$PORT" = "" ] && PORT=8588 + + exec ${GWEMIX} attach http://localhost:${PORT} --preload "$d/conf/WemixGovernance.js,$d/conf/deploy-governance.js" --exec 'GovernanceDeployer.deploy("'${CONFIG}'", '${INIT_ONCE}')' +} + +function wipe () +{ + d=$(get_data_dir "$1") + if [ ! -x "$d/bin/gwemix" ]; then + echo "Is '$1' wemix data directory?" + return + fi + + cd $d + /bin/rm -rf geth/LOCK geth/chaindata geth/ethash geth/lightchaindata \ + geth/transactions.rlp geth/nodes geth/triecache gwemix.ipc logs/* etcd +} + +function clean () +{ + d=$(get_data_dir "$1") + if [ -x "$d/bin/gwemix" ]; then + GWEMIX="$d/bin/gwemix" + else + echo "Cannot find gwemix" + return + fi + + cd $d + $GWEMIX --datadir ${PWD} removedb +} + +function start () +{ + d=$(get_data_dir "$1") + if [ -x "$d/bin/gwemix" ]; then + GWEMIX="$d/bin/gwemix" + else + echo "Cannot find gwemix" + return + fi + + [ -f "$d/.rc" ] && source "$d/.rc" + [ "$COINBASE" = "" ] && COINBASE="" || COINBASE="--miner.etherbase $COINBASE" + + RPCOPT="--http --http.addr 0.0.0.0 --mine" + [ "$PORT" = "" ] || RPCOPT="${RPCOPT} --http.port ${PORT}" + RPCOPT="${RPCOPT} --ws --ws.addr 0.0.0.0" + [ "$PORT" = "" ] || RPCOPT="${RPCOPT} --ws.port $((${PORT}+10))" + [ "$NONCE_LIMIT" = "" ] || NONCE_LIMIT="--noncelimit $NONCE_LIMIT" + [ "$BOOT_NODES" = "" ] || BOOT_NODES="--bootnodes $BOOT_NODES" + [ "$TESTNET" = "1" ] && TESTNET=--wemix-testnet + if [ "$DISCOVER" = "0" ]; then + DISCOVER=--nodiscover + else + DISCOVER= + fi + case $SYNC_MODE in + "full") + SYNC_MODE="--syncmode full";; + "fast") + SYNC_MODE="--syncmode fast";; + "snap") + SYNC_MODE="--syncmode snap";; + *) + SYNC_MODE="--syncmode full --gcmode archive";; + esac + + OPTS="$COINBASE $DISCOVER $RPCOPT $BOOT_NODES $NONCE_LIMIT $TESTNET $SYNC_MODE ${GWEMIX_OPTS}" + [ "$PORT" = "" ] || OPTS="${OPTS} --port $(($PORT + 1))" + [ "$HUB" = "" ] || OPTS="${OPTS} --hub ${HUB}" + [ "$MAX_TXS_PER_BLOCK" = "" ] || OPTS="${OPTS} --maxtxsperblock ${MAX_TXS_PER_BLOCK}" + + [ -d "$d/logs" ] || mkdir -p $d/logs + [ "$LOG_FILESIZE" = "" ] && LOG_FILESIZE="10M" + [ "$LOG_FILECOUNT" = "" ] && LOG_FILECOUNT="5" + + cd $d + if [ ! "$2" = "inner" ]; then + $GWEMIX --datadir ${PWD} --metrics $OPTS 2>&1 | \ + ${d}/bin/logrot ${d}/logs/log ${LOG_FILESIZE} ${LOG_FILECOUNT} & + else + if [ -x "$d/bin/logrot" ]; then + exec > >($d/bin/logrot $d/logs/log ${LOG_FILESIZE} ${LOG_FILECOUNT}) + exec 2>&1 + fi + exec $GWEMIX --datadir ${PWD} --metrics $OPTS + fi +} + +function get_gwemix_pids () +{ + ps axww | grep -v grep | grep "gwemix.*datadir.*${1}" | awk '{print $1}' +} + +function do_nodes () +{ + LHN=$(hostname) + CMD=${1/-nodes/} + shift + while [ ! "$1" = "" -a ! "$2" = "" ]; do + if [ "$1" = "$LHN" -o "$1" = "${LHN/.*/}" ]; then + $0 ${CMD} $2 + else + ssh -f $1 ${WEMIX_DIR}/$2/bin/gwemix.sh ${CMD} $2 + fi + shift + shift + done +} + +function usage () +{ + echo "Usage: `basename $0` [init | + init-gov | + clean [] | wipe [] | console [] | + [re]start [] | stop [] | [re]start-nodes | stop-nodes] + +*-nodes uses NODES environment variable: [ ]+ +" +} + +case "$1" in +"init") + if [ $# -lt 3 ]; then + usage; + else + init "$2" "$3" + fi + ;; + +"init-gov") + if [ $# -lt 3 ]; then + usage; + else + init_gov "$2" "$3" "$4" + fi + ;; + +"wipe") + wipe $2 + ;; + +"clean") + clean $2 + ;; + +"stop") + echo -n "stopping..." + dir=$(get_data_dir $2) + PIDS=$(get_gwemix_pids ${dir}) + if [ ! "$PIDS" = "" ]; then + # check if we're the miner or leader + CMD=' +function check_if_mining() { + for (var i = 0; i < 15; i++) { + try { + var token = debug.etcdGet("token") + eval("token = " + token) + // console.log("miner -> " + token.miner) + if (token.miner != admin.wemixInfo.self.name) { + break + } else { + console.log("we are the miner, sleeping...") + admin.sleep(0.25) + } + } catch { + admin.sleep(0.25) + } + } +} +if (admin.wemixInfo != null && admin.wemixInfo.self != null) { + check_if_mining() + if (admin.wemixInfo.etcd.leader.name == admin.wemixInfo.self.name) { + var nodes = admin.wemixNodes("", 0) + for (var n of nodes) { + if (admin.wemixInfo.etcd.leader.name != admin.wemixInfo.self.name) { + break + } + if (n.status == "up" && n.name != admin.wemixInfo.self.name) { + console.log("moving leader to " + n.name) + admin.etcdMoveLeader(n.name) + } + } + } + check_if_mining() +}' + ${dir}/bin/gwemix attach ipc:${dir}/gwemix.ipc --exec "$CMD" | grep -v "undefined" + echo $PIDS | xargs -L1 kill + fi + for i in {1..200}; do + PIDS=$(get_gwemix_pids ${dir}) + [ "$PIDS" = "" ] && break + echo -n "." + sleep 1 + done + PIDS=$(get_gwemix_pids ${dir}) + if [ ! "$PIDS" = "" ]; then + echo $PIDS | xargs -L1 kill -9 + fi + # wait until geth/chaindata is free + for i in {1..200}; do + lsof ${dir}/geth/chaindata/LOG 2>&1 | grep -q gwemix > /dev/null 2>&1 || break + sleep 1 + done + echo "done." + ;; + +"start") + start $2 + ;; + +"start-inner") + if [ "$2" = "" ]; then + usage; + else + start $2 inner + fi + ;; + +"restart") + $0 stop $2 + start $2 + ;; + +"start-nodes"|"restart-nodes"|"stop-nodes") + if [ "${NODES}" = "" ]; then + echo "NODES is not defined" + fi + do_nodes $1 ${NODES} + ;; + +"console") + d=$(get_data_dir "$2") + if [ ! -d $d ]; then + usage; exit; + fi + RCJS= + if [ -f "$d/rc.js" ]; then + RCJS="--preload $d/rc.js" + fi + exec ${d}/bin/gwemix ${RCJS} attach ipc:${d}/gwemix.ipc + ;; + +*) + usage; + ;; +esac + +# EOF diff --git a/containers/docker/wemix/testdata/keystore/account1 b/containers/docker/wemix/testdata/keystore/account1 new file mode 100644 index 000000000000..239d507bec25 --- /dev/null +++ b/containers/docker/wemix/testdata/keystore/account1 @@ -0,0 +1 @@ +{"address":"92875d5ba8b104c375a471d58a6de4f75ccb431f","crypto":{"cipher":"aes-128-ctr","ciphertext":"a07c46d69f5e35b76214af74004686a5c0abf54687dce4e3358318a6d7e3cf23","cipherparams":{"iv":"68f1ee7bd8e3c64ca00e5696b60a7846"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"4166f64bc5dfa526cf1a1da89b26cf1ffb60784827dda85a1ccca6193f818deb"},"mac":"6a2e60f7b74f42802d741503dececef073eaff56374bcfdf2a009c6424d96176"},"id":"caa93028-d6fc-4daf-8c48-152d2bd802bd","version":3} \ No newline at end of file diff --git a/containers/docker/wemix/testdata/keystore/account2 b/containers/docker/wemix/testdata/keystore/account2 new file mode 100644 index 000000000000..55e020da3d94 --- /dev/null +++ b/containers/docker/wemix/testdata/keystore/account2 @@ -0,0 +1 @@ +{"address":"b61544371ef73161496009a77989da30f8f91867","crypto":{"cipher":"aes-128-ctr","ciphertext":"cfc35242ce14823f04188ec46b3591cd17dd112d0cd8b90b4e9ef5600fd9c488","cipherparams":{"iv":"58dbb26dc76dddf7fcfc4ad9bdb18f58"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"17c027b25228ac748c2999dabc4047ac72af698c3260f5deadd025c97027d436"},"mac":"469b428c69e9ed23c509c63211205b354632a018c5798bb02a0456a890018a4b"},"id":"572324e3-fd42-4ef9-a877-843a9d6ea231","version":3} \ No newline at end of file diff --git a/containers/docker/wemix/testdata/keystore/account3 b/containers/docker/wemix/testdata/keystore/account3 new file mode 100644 index 000000000000..f4e8cd39989d --- /dev/null +++ b/containers/docker/wemix/testdata/keystore/account3 @@ -0,0 +1 @@ +{"address":"708ebe75a5dbc5f56176db6e84ce5740897e8a17","crypto":{"cipher":"aes-128-ctr","ciphertext":"5cc062f0bd18808a0708877b79fe85f608ba05a43256f17426c1991e97c7b75b","cipherparams":{"iv":"a84efff4ec48f5ad9ca269a06e893f32"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"b994ab1c05a7da29b2f29b5dfc3dcd39acd1fc07bd19b5c6184ac4c4bc2a3f89"},"mac":"13536b9717e35d2665d6f86b96d3f4c80d8921853cc5ca9be0c13ca9f83a7cbd"},"id":"4aed4e3a-9545-4c6f-a832-db9061962ace","version":3} \ No newline at end of file diff --git a/containers/docker/wemix/testdata/keystore/maintenance b/containers/docker/wemix/testdata/keystore/maintenance new file mode 100644 index 000000000000..853b48f908aa --- /dev/null +++ b/containers/docker/wemix/testdata/keystore/maintenance @@ -0,0 +1 @@ +{"address":"2c77f2c8997182e31a19ec48e321f4d09f36819e","crypto":{"cipher":"aes-128-ctr","ciphertext":"92fdc92f09b59c20ff2a39d5cacc8953006679f797a446371d20caaa9b44201b","cipherparams":{"iv":"560b9a6fe1bba58cfaf4a5a4f95cb7d3"},"kdf":"scrypt","kdfparams":{"dklen":32,"n":262144,"p":1,"r":8,"salt":"cfd2974920c10638af987464ed23ccfad5a787b067bffb346c6f6adbc44e0141"},"mac":"a3fbe185cfad466d73addcc814d0c91771707e95d0cf04431e2276dee04f1bdb"},"id":"aa594e16-1669-4d7c-bd5f-ada55400427c","version":3} \ No newline at end of file diff --git a/containers/docker/wemix/testdata/nodekey/nodekey1 b/containers/docker/wemix/testdata/nodekey/nodekey1 new file mode 100644 index 000000000000..54bde66ceb64 --- /dev/null +++ b/containers/docker/wemix/testdata/nodekey/nodekey1 @@ -0,0 +1 @@ +6af367dc76aaf0dd08464c2af10df669343601e458172c8822d7baebf72dd58b \ No newline at end of file diff --git a/containers/docker/wemix/testdata/nodekey/nodekey2 b/containers/docker/wemix/testdata/nodekey/nodekey2 new file mode 100644 index 000000000000..3c2f344d5931 --- /dev/null +++ b/containers/docker/wemix/testdata/nodekey/nodekey2 @@ -0,0 +1 @@ +9d5e6380dbcd2e202f699867f31302059918c5b90fcbd02207214f8ca89fa62d \ No newline at end of file diff --git a/containers/docker/wemix/testdata/nodekey/nodekey3 b/containers/docker/wemix/testdata/nodekey/nodekey3 new file mode 100644 index 000000000000..582ffe51f88c --- /dev/null +++ b/containers/docker/wemix/testdata/nodekey/nodekey3 @@ -0,0 +1 @@ +9f011066ffb5ec558d1bc6efaf1efac620e79fd44a3a3fcf30fbb1015f0a5b1d \ No newline at end of file From e2ddddad1d56c3fd9933daf81e2f268feea5fa2d Mon Sep 17 00:00:00 2001 From: egonspace Date: Fri, 24 May 2024 14:07:06 +0900 Subject: [PATCH 30/51] fix: adjust sample finish reward block --- params/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/params/config.go b/params/config.go index fa323cf58746..863509a5a793 100644 --- a/params/config.go +++ b/params/config.go @@ -165,7 +165,7 @@ var ( BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(53_557_371), HalvingPeriod: big.NewInt(63_115_200), - FinishRewardBlock: big.NewInt(1_000_000_000), // TODO fix last reward block + FinishRewardBlock: big.NewInt(2_000_000_000), // TODO fix last reward block HalvingTimes: 16, HalvingRate: 50, }, @@ -195,7 +195,7 @@ var ( BlockReward: big.NewInt(1e18), FirstHalvingBlock: big.NewInt(60_537_845), HalvingPeriod: big.NewInt(63_115_200), - FinishRewardBlock: big.NewInt(1_000_000_000), // TODO fix last reward block + FinishRewardBlock: big.NewInt(2_000_000_000), // TODO fix last reward block HalvingTimes: 16, HalvingRate: 50, }, From ac78fcd0ca9b31510e9b6db8fd295f8619a59225 Mon Sep 17 00:00:00 2001 From: eomti-wm Date: Fri, 24 May 2024 14:38:53 +0900 Subject: [PATCH 31/51] fix: apply comment --- eth/api.go | 23 ++++++++++++++++------- eth/backend.go | 4 ++-- internal/web3ext/web3ext.go | 12 ++++++------ 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/eth/api.go b/eth/api.go index 5248a430aaee..d5e78153e96c 100644 --- a/eth/api.go +++ b/eth/api.go @@ -679,15 +679,15 @@ func (api *PrivateDebugAPI) GetAccessibleState(from, to rpc.BlockNumber) (uint64 return 0, fmt.Errorf("No state found") } -type BriocheConfigAPI struct { +type PublicWemixAPI struct { e *Ethereum } -func NewBriocheConfigAPI(e *Ethereum) *BriocheConfigAPI { - return &BriocheConfigAPI{e} +func NewPublicWemixAPI(e *Ethereum) *PublicWemixAPI { + return &PublicWemixAPI{e} } -func (api *BriocheConfigAPI) BriocheConfig() *params.BriocheConfig { +func (api *PublicWemixAPI) BriocheConfig() *params.BriocheConfig { return api.e.BlockChain().Config().Brioche } @@ -698,15 +698,23 @@ type HalvingInfo struct { BlockReward *big.Int `json:"blockReward"` } -func (api *BriocheConfigAPI) HalvingSchedule() []*HalvingInfo { +func (api *PublicWemixAPI) HalvingSchedule() []*HalvingInfo { bc := api.BriocheConfig() if bc.FirstHalvingBlock == nil || bc.HalvingPeriod == nil || bc.HalvingTimes == 0 { return nil } + var lastRewardBlock *big.Int + if bc.FinishRewardBlock != nil { + lastRewardBlock = new(big.Int).Sub(bc.FinishRewardBlock, common.Big1) + } + result := make([]*HalvingInfo, 0) for i := uint64(0); i < bc.HalvingTimes; i++ { startBlock := new(big.Int).Add(bc.FirstHalvingBlock, new(big.Int).Mul(bc.HalvingPeriod, new(big.Int).SetUint64(i))) + if lastRewardBlock != nil && startBlock.Cmp(lastRewardBlock) == 1 { + break + } result = append(result, &HalvingInfo{ HalvingTimes: i + 1, StartBlock: startBlock, @@ -714,12 +722,13 @@ func (api *BriocheConfigAPI) HalvingSchedule() []*HalvingInfo { BlockReward: api.GetBriocheBlockReward(startBlock), }) } - result[len(result)-1].EndBlock = bc.FinishRewardBlock + + result[len(result)-1].EndBlock = lastRewardBlock return result } -func (api *BriocheConfigAPI) GetBriocheBlockReward(height *big.Int) *big.Int { +func (api *PublicWemixAPI) GetBriocheBlockReward(height *big.Int) *big.Int { if wemixapi.Info == nil { return nil } diff --git a/eth/backend.go b/eth/backend.go index b45883ed140e..08bfc4967e95 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -294,9 +294,9 @@ func (s *Ethereum) APIs() []rpc.API { if brioche := s.blockchain.Config().Brioche; brioche != nil { apis = append(apis, rpc.API{ - Namespace: "brioche", + Namespace: "wemix", Version: "1.0", - Service: NewBriocheConfigAPI(s), + Service: NewPublicWemixAPI(s), Public: true, }) } diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index 006741a25a51..b593a7850a43 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -30,7 +30,7 @@ var Modules = map[string]string{ "txpool": TxpoolJs, "les": LESJs, "vflux": VfluxJs, - "brioche": BriocheJs, + "wemix": WemixJs, } const CliqueJs = ` @@ -1006,13 +1006,13 @@ web3._extend({ }); ` -const BriocheJs = ` +const WemixJs = ` web3._extend({ - property: 'brioche', + property: 'wemix', methods: [ new web3._extend.Method({ name: 'getBriocheBlockReward', - call: 'brioche_getBriocheBlockReward', + call: 'wemix_getBriocheBlockReward', params: 1, inputFormatter: [null] }) @@ -1021,11 +1021,11 @@ web3._extend({ [ new web3._extend.Property({ name: 'briocheConfig', - getter: 'brioche_briocheConfig' + getter: 'wemix_briocheConfig' }), new web3._extend.Property({ name: 'halvingSchedule', - getter: 'brioche_halvingSchedule' + getter: 'wemix_halvingSchedule' }) ] }); From 237f883b71c9923bdad379863a3c0d91c3d48e10 Mon Sep 17 00:00:00 2001 From: egonspace Date: Mon, 27 May 2024 10:54:30 +0900 Subject: [PATCH 32/51] fix: finalize the brioche block --- params/config.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/params/config.go b/params/config.go index 863509a5a793..41a3631b1e01 100644 --- a/params/config.go +++ b/params/config.go @@ -159,13 +159,13 @@ var ( LondonBlock: big.NewInt(0), PangyoBlock: big.NewInt(0), ApplepieBlock: big.NewInt(20_476_911), - BriocheBlock: big.NewInt(53_557_371), // 24-07-01 00:00:00 (UTC) expected + BriocheBlock: big.NewInt(53_525_500), // target date: 24-07-01 00:00:00 (GMT+09) Ethash: new(EthashConfig), Brioche: &BriocheConfig{ BlockReward: big.NewInt(1e18), - FirstHalvingBlock: big.NewInt(53_557_371), + FirstHalvingBlock: big.NewInt(53_525_500), HalvingPeriod: big.NewInt(63_115_200), - FinishRewardBlock: big.NewInt(2_000_000_000), // TODO fix last reward block + FinishRewardBlock: big.NewInt(2_467_714_000), // target date: 2101-01-01 00:00:00 (GMT+09) HalvingTimes: 16, HalvingRate: 50, }, @@ -189,13 +189,13 @@ var ( LondonBlock: big.NewInt(0), PangyoBlock: big.NewInt(10_000_000), ApplepieBlock: big.NewInt(26_240_268), - BriocheBlock: big.NewInt(60_537_845), // TODO fix hardfork date + BriocheBlock: big.NewInt(59_414_700), // target date: 24-06-04 11:00:41 (GMT+09) Ethash: new(EthashConfig), Brioche: &BriocheConfig{ BlockReward: big.NewInt(1e18), - FirstHalvingBlock: big.NewInt(60_537_845), + FirstHalvingBlock: big.NewInt(59_414_700), HalvingPeriod: big.NewInt(63_115_200), - FinishRewardBlock: big.NewInt(2_000_000_000), // TODO fix last reward block + FinishRewardBlock: big.NewInt(2_473_258_000), // target date: 2100-12-01 11:02:21 (GMT+09) HalvingTimes: 16, HalvingRate: 50, }, From 5181ef8be8c3f189dfa40ac2cda1926b013c589a Mon Sep 17 00:00:00 2001 From: egonspace Date: Mon, 27 May 2024 15:07:16 +0900 Subject: [PATCH 33/51] fix: modify more big.NewInt(0) --- params/config.go | 6 +++--- params/config_test.go | 8 ++++---- wemix/admin.go | 14 +++++++------- wemix/rewards_test.go | 22 +++++++++++----------- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/params/config.go b/params/config.go index 41a3631b1e01..3481f6115ee0 100644 --- a/params/config.go +++ b/params/config.go @@ -440,14 +440,14 @@ type BriocheConfig struct { } func (bc *BriocheConfig) GetBriocheBlockReward(defaultReward *big.Int, num *big.Int) *big.Int { - blockReward := big.NewInt(0).Set(defaultReward) // default brioche block reward + blockReward := new(big.Int).Set(defaultReward) // default brioche block reward if bc != nil { if bc.BlockReward != nil { - blockReward = big.NewInt(0).Set(bc.BlockReward) + blockReward = new(big.Int).Set(bc.BlockReward) } if bc.FinishRewardBlock != nil && bc.FinishRewardBlock.Cmp(num) <= 0 { - blockReward = big.NewInt(0) + blockReward = new(big.Int) } else if bc.FirstHalvingBlock != nil && bc.HalvingPeriod != nil && bc.HalvingTimes > 0 && diff --git a/params/config_test.go b/params/config_test.go index 07395ec1a017..332297659411 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -246,7 +246,7 @@ func TestGetBriocheBlockReward(t *testing.T) { HalvingRate: 50, }, blockNum: big.NewInt(100), - expected: big.NewInt(0), + expected: new(big.Int), }, { id: 7, @@ -259,7 +259,7 @@ func TestGetBriocheBlockReward(t *testing.T) { HalvingRate: 50, }, blockNum: big.NewInt(100), - expected: big.NewInt(0).Div(defaultBlockReward, big.NewInt(2)), + expected: new(big.Int).Div(defaultBlockReward, big.NewInt(2)), }, // no halving @@ -341,7 +341,7 @@ func TestGetBriocheBlockReward(t *testing.T) { HalvingRate: 0, // no reward }, blockNum: big.NewInt(100), - expected: big.NewInt(0), + expected: new(big.Int), }, { id: 14, @@ -367,7 +367,7 @@ func TestGetBriocheBlockReward(t *testing.T) { HalvingRate: 50, }, blockNum: big.NewInt(200), - expected: big.NewInt(0), + expected: new(big.Int), }, // halving rate variations diff --git a/wemix/admin.go b/wemix/admin.go index 677e9ce6c30f..57925cf9fd73 100644 --- a/wemix/admin.go +++ b/wemix/admin.go @@ -123,9 +123,9 @@ type rewardParameters struct { var ( // "Wemix Registry" - magic, _ = big.NewInt(0).SetString("0x57656d6978205265676973747279", 0) + magic, _ = new(big.Int).SetString("0x57656d6978205265676973747279", 0) etcdClusterName = "Wemix" - big0 = big.NewInt(0) + big0 = new(big.Int) nilAddress = common.Address{} defaultBriocheBlockReward = big.NewInt(1e18) admin *wemixAdmin @@ -1056,7 +1056,7 @@ func distributeRewards(height *big.Int, rp *rewardParameters, blockReward *big.I var rewards []reward if n := len(rp.members); n > 0 { - stakeTotal, equalStakes := big.NewInt(0), true + stakeTotal, equalStakes := new(big.Int), true for i := 0; i < n; i++ { if equalStakes && i < n-1 && rp.members[i].Stake.Cmp(rp.members[i+1].Stake) != 0 { equalStakes = false @@ -1065,7 +1065,7 @@ func distributeRewards(height *big.Int, rp *rewardParameters, blockReward *big.I } if equalStakes { - v0, v1 := big.NewInt(0), big.NewInt(1) + v0, v1 := new(big.Int), big.NewInt(1) vn := big.NewInt(int64(n)) b := new(big.Int).Set(minerAmount) d := new(big.Int) @@ -1084,7 +1084,7 @@ func distributeRewards(height *big.Int, rp *rewardParameters, blockReward *big.I } } else { // rewards distributed according to stakes - v0, v1 := big.NewInt(0), big.NewInt(1) + v0, v1 := new(big.Int), big.NewInt(1) remainder := new(big.Int).Set(minerAmount) for i := 0; i < n; i++ { memberReward := new(big.Int).Mul(minerAmount, rp.members[i].Stake) @@ -1427,8 +1427,8 @@ func getBlockBuildParameters(height *big.Int) (blockInterval int64, maxBaseFee, // default values blockInterval = 15 - maxBaseFee = big.NewInt(0) - gasLimit = big.NewInt(0) + maxBaseFee = new(big.Int) + gasLimit = new(big.Int) baseFeeMaxChangeRate = 0 gasTargetPercentage = 100 diff --git a/wemix/rewards_test.go b/wemix/rewards_test.go index d989116e79ab..dc8a118ed544 100644 --- a/wemix/rewards_test.go +++ b/wemix/rewards_test.go @@ -152,21 +152,21 @@ func TestDistributeRewards(t *testing.T) { t.Errorf("distributeRewards() failed: %v, %v <-> %v", err, tt.want, string(rewardsString)) } - distTotal := big.NewInt(0) + distTotal := new(big.Int) for _, dist := range tt.rp.distributionMethod { distTotal.Add(distTotal, dist) } - totalRewards := big.NewInt(0) - memberRewards := big.NewInt(0) + totalRewards := new(big.Int) + memberRewards := new(big.Int) for i, reward := range rewards { totalRewards.Add(totalRewards, reward.Reward) if i < len(tt.rp.members) { memberRewards.Add(memberRewards, reward.Reward) } } - totalAmount := big.NewInt(0).Set(tt.rp.rewardAmount) + totalAmount := new(big.Int).Set(tt.rp.rewardAmount) totalAmount.Add(totalAmount, tt.fees) - memberAmount := big.NewInt(0).Set(tt.rp.rewardAmount) + memberAmount := new(big.Int).Set(tt.rp.rewardAmount) memberAmount = memberAmount.Mul(memberAmount, tt.rp.distributionMethod[0]) memberAmount = memberAmount.Div(memberAmount, distTotal) if memberRewards.Cmp(memberAmount) != 0 { @@ -226,13 +226,13 @@ func TestRewardValidation(t *testing.T) { BriocheBlock: common.Big0, Brioche: ¶ms.BriocheConfig{ BlockReward: big.NewInt(100), - FirstHalvingBlock: big.NewInt(0), + FirstHalvingBlock: new(big.Int), HalvingPeriod: big.NewInt(10), FinishRewardBlock: big.NewInt(30), HalvingTimes: 3, HalvingRate: 50, }}, - Alloc: core.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: big.NewInt(0)}}, + Alloc: core.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, } genesis = gspec.MustCommit(db) signer = types.LatestSigner(gspec.Config) @@ -331,21 +331,21 @@ func TestBriocheHardFork(t *testing.T) { HalvingTimes: 2, HalvingRate: 50, }}, - Alloc: core.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: big.NewInt(0)}}, + Alloc: core.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, } genesis = gspec.MustCommit(db) signer = types.LatestSigner(gspec.Config) ) expectedBlockReward := []*big.Int{ - big.NewInt(0), // zero block reward; not used + new(big.Int), // zero block reward; not used big.NewInt(1e18), big.NewInt(4e17), big.NewInt(4e17), big.NewInt(2e17), big.NewInt(2e17), big.NewInt(1e17), - big.NewInt(0), + new(big.Int), } miners := []common.Address{ @@ -371,7 +371,7 @@ func TestBriocheHardFork(t *testing.T) { }, }, blocksPer: 1, - distributionMethod: []*big.Int{big.NewInt(5000), big.NewInt(0), big.NewInt(2500), big.NewInt(2500)}, // miner, staker, eco, maintenance + distributionMethod: []*big.Int{big.NewInt(5000), new(big.Int), big.NewInt(2500), big.NewInt(2500)}, // miner, staker, eco, maintenance } wemixminer.CalculateRewardsFunc = makeCalculateRewardFunc(rp) From 2010205a30376082a1d384ced18af53536c5dd39 Mon Sep 17 00:00:00 2001 From: eomti-wm Date: Mon, 27 May 2024 15:29:29 +0900 Subject: [PATCH 34/51] fix: apply comment --- eth/api.go | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/eth/api.go b/eth/api.go index d5e78153e96c..4a69dc8ca9ff 100644 --- a/eth/api.go +++ b/eth/api.go @@ -692,10 +692,10 @@ func (api *PublicWemixAPI) BriocheConfig() *params.BriocheConfig { } type HalvingInfo struct { - HalvingTimes uint64 `json:"halvingTimes"` - StartBlock *big.Int `json:"startBlock"` - EndBlock *big.Int `json:"endBlock"` - BlockReward *big.Int `json:"blockReward"` + HalvingTimes hexutil.Uint64 `json:"halvingTimes"` + StartBlock *hexutil.Big `json:"startBlock"` + EndBlock *hexutil.Big `json:"endBlock"` + BlockReward *hexutil.Big `json:"blockReward"` } func (api *PublicWemixAPI) HalvingSchedule() []*HalvingInfo { @@ -716,31 +716,39 @@ func (api *PublicWemixAPI) HalvingSchedule() []*HalvingInfo { break } result = append(result, &HalvingInfo{ - HalvingTimes: i + 1, - StartBlock: startBlock, - EndBlock: new(big.Int).Sub(new(big.Int).Add(startBlock, bc.HalvingPeriod), common.Big1), - BlockReward: api.GetBriocheBlockReward(startBlock), + HalvingTimes: hexutil.Uint64(i + 1), + StartBlock: (*hexutil.Big)(startBlock), + EndBlock: (*hexutil.Big)(new(big.Int).Sub(new(big.Int).Add(startBlock, bc.HalvingPeriod), common.Big1)), + BlockReward: (*hexutil.Big)(api.getBriocheBlockReward(startBlock)), }) } - result[len(result)-1].EndBlock = lastRewardBlock + result[len(result)-1].EndBlock = (*hexutil.Big)(lastRewardBlock) return result } -func (api *PublicWemixAPI) GetBriocheBlockReward(height *big.Int) *big.Int { +func (api *PublicWemixAPI) GetBriocheBlockReward(blockNumber *hexutil.Big) *hexutil.Big { + return (*hexutil.Big)(api.getBriocheBlockReward((*big.Int)(blockNumber))) +} + +func (api *PublicWemixAPI) getBriocheBlockReward(blockNumber *big.Int) *big.Int { if wemixapi.Info == nil { return nil } + wemixInfoPtr, ok := wemixapi.Info().(*map[string]interface{}) + if !ok { + return nil + } + wemixInfo := *wemixInfoPtr config := api.e.BlockChain().Config() - wemixInfo := *(wemixapi.Info().(*map[string]interface{})) - if height == nil { - height = api.e.BlockChain().CurrentHeader().Number + if blockNumber == nil { + blockNumber = api.e.BlockChain().CurrentHeader().Number } - if config.IsBrioche(height) { - return config.Brioche.GetBriocheBlockReward(wemixInfo["defaultBriocheBlockReward"].(*big.Int), height) + if config.IsBrioche(blockNumber) { + return config.Brioche.GetBriocheBlockReward(wemixInfo["defaultBriocheBlockReward"].(*big.Int), blockNumber) } else { return wemixInfo["blockReward"].(*big.Int) } From 69ce2d37145bdd08c04a2137c4553f95b9fd2581 Mon Sep 17 00:00:00 2001 From: egonspace Date: Mon, 27 May 2024 15:34:57 +0900 Subject: [PATCH 35/51] fix: use big.NewInt(0) for explicit zero --- params/config.go | 2 +- params/config_test.go | 6 +++--- wemix/admin.go | 12 ++++++------ wemix/rewards_test.go | 12 ++++++------ 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/params/config.go b/params/config.go index 3481f6115ee0..c86356c663ad 100644 --- a/params/config.go +++ b/params/config.go @@ -447,7 +447,7 @@ func (bc *BriocheConfig) GetBriocheBlockReward(defaultReward *big.Int, num *big. } if bc.FinishRewardBlock != nil && bc.FinishRewardBlock.Cmp(num) <= 0 { - blockReward = new(big.Int) + blockReward = big.NewInt(0) } else if bc.FirstHalvingBlock != nil && bc.HalvingPeriod != nil && bc.HalvingTimes > 0 && diff --git a/params/config_test.go b/params/config_test.go index 332297659411..17b49b3d18ff 100644 --- a/params/config_test.go +++ b/params/config_test.go @@ -246,7 +246,7 @@ func TestGetBriocheBlockReward(t *testing.T) { HalvingRate: 50, }, blockNum: big.NewInt(100), - expected: new(big.Int), + expected: big.NewInt(0), }, { id: 7, @@ -341,7 +341,7 @@ func TestGetBriocheBlockReward(t *testing.T) { HalvingRate: 0, // no reward }, blockNum: big.NewInt(100), - expected: new(big.Int), + expected: big.NewInt(0), }, { id: 14, @@ -367,7 +367,7 @@ func TestGetBriocheBlockReward(t *testing.T) { HalvingRate: 50, }, blockNum: big.NewInt(200), - expected: new(big.Int), + expected: big.NewInt(0), }, // halving rate variations diff --git a/wemix/admin.go b/wemix/admin.go index 57925cf9fd73..62256504dcdd 100644 --- a/wemix/admin.go +++ b/wemix/admin.go @@ -125,7 +125,7 @@ var ( // "Wemix Registry" magic, _ = new(big.Int).SetString("0x57656d6978205265676973747279", 0) etcdClusterName = "Wemix" - big0 = new(big.Int) + big0 = big.NewInt(0) nilAddress = common.Address{} defaultBriocheBlockReward = big.NewInt(1e18) admin *wemixAdmin @@ -1056,7 +1056,7 @@ func distributeRewards(height *big.Int, rp *rewardParameters, blockReward *big.I var rewards []reward if n := len(rp.members); n > 0 { - stakeTotal, equalStakes := new(big.Int), true + stakeTotal, equalStakes := big.NewInt(0), true for i := 0; i < n; i++ { if equalStakes && i < n-1 && rp.members[i].Stake.Cmp(rp.members[i+1].Stake) != 0 { equalStakes = false @@ -1065,7 +1065,7 @@ func distributeRewards(height *big.Int, rp *rewardParameters, blockReward *big.I } if equalStakes { - v0, v1 := new(big.Int), big.NewInt(1) + v0, v1 := big.NewInt(0), big.NewInt(1) vn := big.NewInt(int64(n)) b := new(big.Int).Set(minerAmount) d := new(big.Int) @@ -1084,7 +1084,7 @@ func distributeRewards(height *big.Int, rp *rewardParameters, blockReward *big.I } } else { // rewards distributed according to stakes - v0, v1 := new(big.Int), big.NewInt(1) + v0, v1 := big.NewInt(0), big.NewInt(1) remainder := new(big.Int).Set(minerAmount) for i := 0; i < n; i++ { memberReward := new(big.Int).Mul(minerAmount, rp.members[i].Stake) @@ -1427,8 +1427,8 @@ func getBlockBuildParameters(height *big.Int) (blockInterval int64, maxBaseFee, // default values blockInterval = 15 - maxBaseFee = new(big.Int) - gasLimit = new(big.Int) + maxBaseFee = big.NewInt(0) + gasLimit = big.NewInt(0) baseFeeMaxChangeRate = 0 gasTargetPercentage = 100 diff --git a/wemix/rewards_test.go b/wemix/rewards_test.go index dc8a118ed544..dcafac7732e8 100644 --- a/wemix/rewards_test.go +++ b/wemix/rewards_test.go @@ -226,13 +226,13 @@ func TestRewardValidation(t *testing.T) { BriocheBlock: common.Big0, Brioche: ¶ms.BriocheConfig{ BlockReward: big.NewInt(100), - FirstHalvingBlock: new(big.Int), + FirstHalvingBlock: big.NewInt(0), HalvingPeriod: big.NewInt(10), FinishRewardBlock: big.NewInt(30), HalvingTimes: 3, HalvingRate: 50, }}, - Alloc: core.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, + Alloc: core.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: big.NewInt(0)}}, } genesis = gspec.MustCommit(db) signer = types.LatestSigner(gspec.Config) @@ -331,21 +331,21 @@ func TestBriocheHardFork(t *testing.T) { HalvingTimes: 2, HalvingRate: 50, }}, - Alloc: core.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, + Alloc: core.GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: big.NewInt(0)}}, } genesis = gspec.MustCommit(db) signer = types.LatestSigner(gspec.Config) ) expectedBlockReward := []*big.Int{ - new(big.Int), // zero block reward; not used + big.NewInt(0), // zero block reward; not used big.NewInt(1e18), big.NewInt(4e17), big.NewInt(4e17), big.NewInt(2e17), big.NewInt(2e17), big.NewInt(1e17), - new(big.Int), + big.NewInt(0), } miners := []common.Address{ @@ -371,7 +371,7 @@ func TestBriocheHardFork(t *testing.T) { }, }, blocksPer: 1, - distributionMethod: []*big.Int{big.NewInt(5000), new(big.Int), big.NewInt(2500), big.NewInt(2500)}, // miner, staker, eco, maintenance + distributionMethod: []*big.Int{big.NewInt(5000), big.NewInt(0), big.NewInt(2500), big.NewInt(2500)}, // miner, staker, eco, maintenance } wemixminer.CalculateRewardsFunc = makeCalculateRewardFunc(rp) From c01beea5adc25095c9a7ab410dd96c4a96914546 Mon Sep 17 00:00:00 2001 From: kai-yu-wm Date: Tue, 28 May 2024 15:45:28 +0900 Subject: [PATCH 36/51] docs: Add container.md and move feedelegation.md --- README.md | 4 ++++ FEEDELEGATION.md => docs/FEEDELEGATION.md | 0 docs/container.md | 9 +++++++++ 3 files changed, 13 insertions(+) rename FEEDELEGATION.md => docs/FEEDELEGATION.md (100%) create mode 100644 docs/container.md diff --git a/README.md b/README.md index 3d4dd711fd35..d844c72fb4a5 100644 --- a/README.md +++ b/README.md @@ -166,6 +166,10 @@ After getting enodes of mining nodes, run gwemix as follows. bin/gwemix --syncmode full --datadir --bootnodes --http --http.addr 0.0.0.0 +### Starting Nodes With Docker + +See documentation [here](docs/container.md) + ### The original go-ethereum README follows... ## Go Ethereum diff --git a/FEEDELEGATION.md b/docs/FEEDELEGATION.md similarity index 100% rename from FEEDELEGATION.md rename to docs/FEEDELEGATION.md diff --git a/docs/container.md b/docs/container.md new file mode 100644 index 000000000000..4464b14da648 --- /dev/null +++ b/docs/container.md @@ -0,0 +1,9 @@ +### Starting Nodes With Docker + +Before starting node, an image build is required. Runs from the `containers/docker/wemix` directory. + + docker compose build + +After, run gwemix as follows. + + docker compose up -d \ No newline at end of file From 68700e670f8bde523c6775588fc2174534b6e6e1 Mon Sep 17 00:00:00 2001 From: eomti-wm Date: Tue, 28 May 2024 16:43:29 +0900 Subject: [PATCH 37/51] fix: apply comment --- eth/api.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/eth/api.go b/eth/api.go index 4a69dc8ca9ff..c205053e75b4 100644 --- a/eth/api.go +++ b/eth/api.go @@ -743,12 +743,15 @@ func (api *PublicWemixAPI) getBriocheBlockReward(blockNumber *big.Int) *big.Int wemixInfo := *wemixInfoPtr config := api.e.BlockChain().Config() + height := new(big.Int) if blockNumber == nil { - blockNumber = api.e.BlockChain().CurrentHeader().Number + height.Set(api.e.BlockChain().CurrentHeader().Number) + } else { + height.Set(blockNumber) } - if config.IsBrioche(blockNumber) { - return config.Brioche.GetBriocheBlockReward(wemixInfo["defaultBriocheBlockReward"].(*big.Int), blockNumber) + if config.IsBrioche(height) { + return config.Brioche.GetBriocheBlockReward(wemixInfo["defaultBriocheBlockReward"].(*big.Int), height) } else { return wemixInfo["blockReward"].(*big.Int) } From c57147db35ccb6ef66943a9aec1bc7c12a41a0a9 Mon Sep 17 00:00:00 2001 From: egonspace Date: Tue, 28 May 2024 17:29:21 +0900 Subject: [PATCH 38/51] fix: restore genesis logic, add fork checking logging --- core/genesis.go | 5 +---- eth/protocols/eth/handshake.go | 12 +++++++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/core/genesis.go b/core/genesis.go index f98aa8966071..b4a318727a69 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -302,10 +302,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override // chain config as that would be AllProtocolChanges (applying any new fork // on top of an existing private network genesis block). In that case, only // apply the overrides. - if genesis == nil && - !(stored == params.MainnetGenesisHash || - stored == params.WemixMainnetGenesisHash || - stored == params.WemixTestnetGenesisHash) { + if genesis == nil && !(stored == params.MainnetGenesisHash || stored == params.WemixMainnetGenesisHash) { newcfg = storedcfg if overrideArrowGlacier != nil { newcfg.ArrowGlacierBlock = overrideArrowGlacier diff --git a/eth/protocols/eth/handshake.go b/eth/protocols/eth/handshake.go index 9a2769fa0d12..9db02a5b3ac2 100644 --- a/eth/protocols/eth/handshake.go +++ b/eth/protocols/eth/handshake.go @@ -23,6 +23,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/forkid" + "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/p2p" ) @@ -51,7 +52,7 @@ func (p *Peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis }) }() go func() { - errc <- p.readStatus(network, &status, genesis, forkFilter) + errc <- p.readStatus(network, &status, genesis, forkFilter, forkID) }() timeout := time.NewTimer(handshakeTimeout) defer timeout.Stop() @@ -76,7 +77,7 @@ func (p *Peer) Handshake(network uint64, td *big.Int, head common.Hash, genesis } // readStatus reads the remote handshake message. -func (p *Peer) readStatus(network uint64, status *StatusPacket, genesis common.Hash, forkFilter forkid.Filter) error { +func (p *Peer) readStatus(network uint64, status *StatusPacket, genesis common.Hash, forkFilter forkid.Filter, myForkID forkid.ID) error { msg, err := p.rw.ReadMsg() if err != nil { return err @@ -100,7 +101,12 @@ func (p *Peer) readStatus(network uint64, status *StatusPacket, genesis common.H if status.Genesis != genesis { return fmt.Errorf("%w: %x (!= %x)", errGenesisMismatch, status.Genesis, genesis) } - if err := forkFilter(status.ForkID); err != nil { + + // Wemix cannot tolerate a fork among etcd members, so we need to check fork ID manually before the hard fork date + if status.ForkID.Next != myForkID.Next { + defer log.Warn("Checking ForkID: different next fork", "peer", p.ID(), "peerForkID", status.ForkID, "myForkID", myForkID, "error", err) + } + if err = forkFilter(status.ForkID); err != nil { return fmt.Errorf("%w: %v", errForkIDRejected, err) } return nil From 1dfc936931f1850f01d9354146503cf5b8cd33df Mon Sep 17 00:00:00 2001 From: egonspace Date: Tue, 28 May 2024 17:44:14 +0900 Subject: [PATCH 39/51] fix: apply comment --- core/state_processor.go | 9 ++++++--- wemix/admin.go | 3 +-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index 2f7dd6627b38..e2d67255cf25 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -89,13 +89,16 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) err := p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) - header.Fees = fees + if err != nil { + return nil, nil, 0, err + } - if block.Header().Hash() != header.Hash() { + header.Fees = fees + if block.Hash() != header.Hash() { return nil, nil, 0, fmt.Errorf("remote block hash is different from being processed one locally (remote=%v, local=%v)", block.Header().Hash(), header.Hash()) } - return receipts, allLogs, *usedGas, err + return receipts, allLogs, *usedGas, nil } func applyTransaction(msg types.Message, config *params.ChainConfig, gp *GasPool, statedb *state.StateDB, blockNumber *big.Int, blockHash common.Hash, tx *types.Transaction, usedGas *uint64, fees *big.Int, evm *vm.EVM) (*types.Receipt, error) { diff --git a/wemix/admin.go b/wemix/admin.go index 62256504dcdd..313578ea4cb1 100644 --- a/wemix/admin.go +++ b/wemix/admin.go @@ -1175,8 +1175,7 @@ func calculateRewards(config *params.ChainConfig, num, fees *big.Int, addBalance rp, err := admin.getRewardParams(ctx, big.NewInt(num.Int64()-1)) if err != nil { // all goes to the coinbase - err = wemixminer.ErrNotInitialized - return nil, err + return nil, wemixminer.ErrNotInitialized } return calculateRewardsWithParams(config, rp, num, fees, addBalance) From c6242285328fe90ab514c8bde47bfde36c3eed64 Mon Sep 17 00:00:00 2001 From: eomti-wm Date: Tue, 28 May 2024 18:15:43 +0900 Subject: [PATCH 40/51] fix: modify hexutil.Big to rpc.BlockNumber --- eth/api.go | 23 ++++++++++++++--------- internal/web3ext/web3ext.go | 3 +-- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/eth/api.go b/eth/api.go index c205053e75b4..776e7125883a 100644 --- a/eth/api.go +++ b/eth/api.go @@ -728,8 +728,19 @@ func (api *PublicWemixAPI) HalvingSchedule() []*HalvingInfo { return result } -func (api *PublicWemixAPI) GetBriocheBlockReward(blockNumber *hexutil.Big) *hexutil.Big { - return (*hexutil.Big)(api.getBriocheBlockReward((*big.Int)(blockNumber))) +func (api *PublicWemixAPI) GetBriocheBlockReward(blockNumber rpc.BlockNumber) *hexutil.Big { + height := new(big.Int) + if blockNumber == rpc.LatestBlockNumber { + height.Set(api.e.BlockChain().CurrentHeader().Number) + } else if blockNumber == rpc.FinalizedBlockNumber { + height.Set(api.e.BlockChain().CurrentHeader().Number) + } else if blockNumber == rpc.PendingBlockNumber { + height.Set(api.e.miner.PendingBlock().Header().Number) + } else { + height.SetInt64(blockNumber.Int64()) + } + + return (*hexutil.Big)(api.getBriocheBlockReward(height)) } func (api *PublicWemixAPI) getBriocheBlockReward(blockNumber *big.Int) *big.Int { @@ -742,13 +753,7 @@ func (api *PublicWemixAPI) getBriocheBlockReward(blockNumber *big.Int) *big.Int } wemixInfo := *wemixInfoPtr config := api.e.BlockChain().Config() - - height := new(big.Int) - if blockNumber == nil { - height.Set(api.e.BlockChain().CurrentHeader().Number) - } else { - height.Set(blockNumber) - } + height := new(big.Int).Set(blockNumber) if config.IsBrioche(height) { return config.Brioche.GetBriocheBlockReward(wemixInfo["defaultBriocheBlockReward"].(*big.Int), height) diff --git a/internal/web3ext/web3ext.go b/internal/web3ext/web3ext.go index b593a7850a43..64d871e5139f 100644 --- a/internal/web3ext/web3ext.go +++ b/internal/web3ext/web3ext.go @@ -1013,8 +1013,7 @@ web3._extend({ new web3._extend.Method({ name: 'getBriocheBlockReward', call: 'wemix_getBriocheBlockReward', - params: 1, - inputFormatter: [null] + params: 1 }) ], properties: From c5b7e5e7a1779b20a069714ef80ec26e7f2e64b9 Mon Sep 17 00:00:00 2001 From: egonspace Date: Wed, 29 May 2024 09:02:15 +0900 Subject: [PATCH 41/51] fix: return receipt on error case --- core/state_processor.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/state_processor.go b/core/state_processor.go index e2d67255cf25..6edd6592de9f 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -90,12 +90,12 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) err := p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles()) if err != nil { - return nil, nil, 0, err + return receipts, nil, 0, err } header.Fees = fees if block.Hash() != header.Hash() { - return nil, nil, 0, fmt.Errorf("remote block hash is different from being processed one locally (remote=%v, local=%v)", block.Header().Hash(), header.Hash()) + return receipts, nil, 0, fmt.Errorf("remote block hash is different from being processed one locally (remote=%v, local=%v)", block.Header().Hash(), header.Hash()) } return receipts, allLogs, *usedGas, nil From 0f9ad8ec947b1996f85d28323bff782f23418787 Mon Sep 17 00:00:00 2001 From: egonspace Date: Wed, 29 May 2024 11:13:32 +0900 Subject: [PATCH 42/51] fix: version up to v0.10.8 --- params/version.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/params/version.go b/params/version.go index 65bce5efb03b..daf0ba2ca895 100644 --- a/params/version.go +++ b/params/version.go @@ -23,7 +23,7 @@ import ( const ( VersionMajor = 0 // Major version component of the current release VersionMinor = 10 // Minor version component of the current release - VersionPatch = 7 // Patch version component of the current release + VersionPatch = 8 // Patch version component of the current release VersionMeta = "stable" // Version metadata to append to the version string ) From eb5a9657f567a60fe930a99d9947c2b329768529 Mon Sep 17 00:00:00 2001 From: eomti-wm Date: Thu, 30 May 2024 13:58:11 +0900 Subject: [PATCH 43/51] fix: modify big.Int to hexutil.Big --- eth/api.go | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/eth/api.go b/eth/api.go index 776e7125883a..23e27d61702d 100644 --- a/eth/api.go +++ b/eth/api.go @@ -683,12 +683,13 @@ type PublicWemixAPI struct { e *Ethereum } -func NewPublicWemixAPI(e *Ethereum) *PublicWemixAPI { - return &PublicWemixAPI{e} -} - -func (api *PublicWemixAPI) BriocheConfig() *params.BriocheConfig { - return api.e.BlockChain().Config().Brioche +type BriocheConfigResult struct { + BlockReward *hexutil.Big `json:"blockReward,omitempty"` + FirstHalvingBlock *hexutil.Big `json:"firstHalvingBlock,omitempty"` + HalvingPeriod *hexutil.Big `json:"halvingPeriod,omitempty"` + FinishRewardBlock *hexutil.Big `json:"finishRewardBlock,omitempty"` + HalvingTimes hexutil.Uint64 `json:"halvingTimes,omitempty"` + HalvingRate hexutil.Uint64 `json:"halvingRate,omitempty"` } type HalvingInfo struct { @@ -698,8 +699,24 @@ type HalvingInfo struct { BlockReward *hexutil.Big `json:"blockReward"` } +func NewPublicWemixAPI(e *Ethereum) *PublicWemixAPI { + return &PublicWemixAPI{e} +} + +func (api *PublicWemixAPI) BriocheConfig() BriocheConfigResult { + bc := api.e.BlockChain().Config().Brioche + return BriocheConfigResult{ + BlockReward: (*hexutil.Big)(bc.BlockReward), + FirstHalvingBlock: (*hexutil.Big)(bc.FirstHalvingBlock), + HalvingPeriod: (*hexutil.Big)(bc.HalvingPeriod), + FinishRewardBlock: (*hexutil.Big)(bc.FinishRewardBlock), + HalvingTimes: hexutil.Uint64(bc.HalvingTimes), + HalvingRate: hexutil.Uint64(bc.HalvingRate), + } +} + func (api *PublicWemixAPI) HalvingSchedule() []*HalvingInfo { - bc := api.BriocheConfig() + bc := api.e.BlockChain().Config().Brioche if bc.FirstHalvingBlock == nil || bc.HalvingPeriod == nil || bc.HalvingTimes == 0 { return nil } @@ -712,7 +729,7 @@ func (api *PublicWemixAPI) HalvingSchedule() []*HalvingInfo { result := make([]*HalvingInfo, 0) for i := uint64(0); i < bc.HalvingTimes; i++ { startBlock := new(big.Int).Add(bc.FirstHalvingBlock, new(big.Int).Mul(bc.HalvingPeriod, new(big.Int).SetUint64(i))) - if lastRewardBlock != nil && startBlock.Cmp(lastRewardBlock) == 1 { + if lastRewardBlock != nil && startBlock.Cmp(lastRewardBlock) > 0 { break } result = append(result, &HalvingInfo{ @@ -730,13 +747,14 @@ func (api *PublicWemixAPI) HalvingSchedule() []*HalvingInfo { func (api *PublicWemixAPI) GetBriocheBlockReward(blockNumber rpc.BlockNumber) *hexutil.Big { height := new(big.Int) - if blockNumber == rpc.LatestBlockNumber { + switch blockNumber { + case rpc.LatestBlockNumber: height.Set(api.e.BlockChain().CurrentHeader().Number) - } else if blockNumber == rpc.FinalizedBlockNumber { + case rpc.FinalizedBlockNumber: height.Set(api.e.BlockChain().CurrentHeader().Number) - } else if blockNumber == rpc.PendingBlockNumber { + case rpc.PendingBlockNumber: height.Set(api.e.miner.PendingBlock().Header().Number) - } else { + default: height.SetInt64(blockNumber.Int64()) } From d439b023eca93ff73a4ce760e3d4d071f24f6710 Mon Sep 17 00:00:00 2001 From: egon-wm Date: Fri, 31 May 2024 10:13:24 +0900 Subject: [PATCH 44/51] fix: remove 6 PNs for testnet (#94) fix: remote 6 PNs for testnet --- params/wemix_config.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/params/wemix_config.go b/params/wemix_config.go index 772976c16345..455782306915 100644 --- a/params/wemix_config.go +++ b/params/wemix_config.go @@ -16,13 +16,7 @@ var ( WemixTestnetBootnodes = []string{ "enode://6137facc7a938d245d3a9b8a8ab2bed33b4d4dbc6f75058e176d54f3f9689ac5b7fad00efbda3eec8a292412d3616e84507adecc12c175eaa5dd7c1374a46fb2@20.41.113.133:8589", - "enode://a7274dcc5653edf72db753208ce21fce4ed23f967f94eaa720d1296ef4ceb99ed429aec2daedf01864e07c38d48407e8c02b768698b4f34aac845829045b6705@20.41.113.165:8589", "enode://7b53a01356fd4b227dc354f1f725705257c96b504f2da4bb6e0f1beb6bbd4e9203608711e13035f278dbfd144a904bddb3fe526719d878e15b3e9f759afbef85@20.89.67.116:8589", - "enode://f8b4979b8e8afd5031ced4ebb9c8e7ce0ad8d914be3186bc8a67346fbd1c9cae1447d2c006d986e910820956b755ce32e40f5af953e3e68812bb5f3f62ce8cd3@20.222.40.143:8589", - "enode://64e4cb4b0702f1fb33ca8f5beb62f19c928ecc0acf925c53312e44ea53ccf381616178bcc77f70eec68770158b8d8be994b4bde317bea33c13185bdc689a018e@20.24.30.174:8589", - "enode://0778431754005b5a0332ffbb61d54983668cbfdbfcd5d830364c0b7fb0355f81306ef761762eb38f0800f37b1aebbd4f680fde33cfc9c683bb3c8283d12dc64a@20.212.107.1:8589", - "enode://0b8f4bc0ada2695f5d064953cf9f2486c4fc3560dc662363d01a1908df9d273118009755413a3eb6e651f1cdc62ec5425e03ecf6e511c3a2fddae690e91f2b5c@20.245.249.106:8589", - "enode://1a66550c2e7ec3e07aa39efc615331539aadca109377575a4c86bf84d24e66317dd1939f99016699f217285c2a82e4f1e225796666f6af59ab2b29b3c8243fc8@20.245.249.99:8589", } WemixGenesisFile string From 9f8f87012ace91dcdd883859fae5b37c11f45a6b Mon Sep 17 00:00:00 2001 From: jed-wemade <127728629+jed-wemade@users.noreply.github.com> Date: Mon, 3 Jun 2024 10:25:42 +0900 Subject: [PATCH 45/51] feat: make artifact for dev-ci --- .github/workflows/dev-ci.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/dev-ci.yml b/.github/workflows/dev-ci.yml index df9f049e80aa..a38ed5030d9d 100644 --- a/.github/workflows/dev-ci.yml +++ b/.github/workflows/dev-ci.yml @@ -19,9 +19,21 @@ jobs: go-version: 1.19 - name: Build Go-WEMIX - run: make gwemix.tar.gz - - name: Check Build - run: ls -al build/gwemix.tar.gz + run: USE_ROCKSDB=YES make gwemix.tar.gz + + - name: Stat Go-WEMIX + run: | + ls -l build/gwemix.tar.gz + tar tf build/gwemix.tar.gz + - name: Move results to artifact + run: mv build/gwemix.tar.gz gwemix-${{ github.event.pull_request.head.sha }}-linux-amd64-rocksdb.tar.gz + + - name: Upload Go-WEMIX + uses: actions/upload-artifact@v4 + with: + name: artifact-${{ github.event.pull_request.head.sha }} + path: gwemix-${{ github.event.pull_request.head.sha }}-linux-amd64-rocksdb.tar.gz + retention-days: 7 lint_test: strategy: From cb117c3f6a6d4ecd8fbcc07309ac52c41de95576 Mon Sep 17 00:00:00 2001 From: jed-wemade <127728629+jed-wemade@users.noreply.github.com> Date: Mon, 3 Jun 2024 10:26:31 +0900 Subject: [PATCH 46/51] feat: make artifact for master-ci --- .github/workflows/master-ci.yml | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/workflows/master-ci.yml b/.github/workflows/master-ci.yml index 46736e268895..043664d41fdb 100644 --- a/.github/workflows/master-ci.yml +++ b/.github/workflows/master-ci.yml @@ -19,9 +19,21 @@ jobs: go-version: 1.19 - name: Build Go-WEMIX - run: make gwemix.tar.gz - - name: Check Build - run: ls -al build/gwemix.tar.gz + run: USE_ROCKSDB=YES make gwemix.tar.gz + + - name: Stat Go-WEMIX + run: | + ls -l build/gwemix.tar.gz + tar tf build/gwemix.tar.gz + - name: Move results to artifact + run: mv build/gwemix.tar.gz gwemix-${{ github.event.pull_request.head.sha }}-linux-amd64-rocksdb.tar.gz + + - name: Upload Go-WEMIX + uses: actions/upload-artifact@v4 + with: + name: artifact-${{ github.event.pull_request.head.sha }} + path: gwemix-${{ github.event.pull_request.head.sha }}-linux-amd64-rocksdb.tar.gz + retention-days: 7 lint_test: strategy: From 376fc608b849f396ec061b75140b7b282a3d1e1c Mon Sep 17 00:00:00 2001 From: jed-wemade <127728629+jed-wemade@users.noreply.github.com> Date: Mon, 3 Jun 2024 13:56:08 +0900 Subject: [PATCH 47/51] feat: make artifact during ci --- .github/workflows/artifacts.yml | 38 +++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/artifacts.yml diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml new file mode 100644 index 000000000000..86aea2b69c79 --- /dev/null +++ b/.github/workflows/artifacts.yml @@ -0,0 +1,38 @@ +name: artifacts + +on: + push: + branches: + - devnet + - dev + - master + +jobs: + + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Go + uses: actions/setup-go@v4 + with: + go-version: '1.19' + + - name: Build Go-WEMIX tarball + run: USE_ROCKSDB=YES make gwemix.tar.gz + + - name: Stat Go-WEMIX tarball + run: | + ls -l build/gwemix.tar.gz + tar tf build/gwemix.tar.gz + + - name: Move results to artifact + run: mv build/gwemix.tar.gz gwemix-${{ github.ref_name }}-${{ github.sha }}-linux-amd64-rocksdb.tar.gz + + - name: Upload Go-WEMIX + uses: actions/upload-artifact@v4 + with: + name: artifact-${{ github.ref_name }}-${{ github.sha }} + path: gwemix-${{ github.ref_name }}-${{ github.sha }}-linux-amd64-rocksdb.tar.gz + retention-days: 7 From 782779ff6f150988ef763896122d16e7b1cbf038 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=9D=EC=9A=A9=28WM=29?= Date: Mon, 3 Jun 2024 14:00:25 +0900 Subject: [PATCH 48/51] Revert "feat: make artifact for dev-ci" This reverts commit 9f8f87012ace91dcdd883859fae5b37c11f45a6b. --- .github/workflows/dev-ci.yml | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/.github/workflows/dev-ci.yml b/.github/workflows/dev-ci.yml index a38ed5030d9d..df9f049e80aa 100644 --- a/.github/workflows/dev-ci.yml +++ b/.github/workflows/dev-ci.yml @@ -19,21 +19,9 @@ jobs: go-version: 1.19 - name: Build Go-WEMIX - run: USE_ROCKSDB=YES make gwemix.tar.gz - - - name: Stat Go-WEMIX - run: | - ls -l build/gwemix.tar.gz - tar tf build/gwemix.tar.gz - - name: Move results to artifact - run: mv build/gwemix.tar.gz gwemix-${{ github.event.pull_request.head.sha }}-linux-amd64-rocksdb.tar.gz - - - name: Upload Go-WEMIX - uses: actions/upload-artifact@v4 - with: - name: artifact-${{ github.event.pull_request.head.sha }} - path: gwemix-${{ github.event.pull_request.head.sha }}-linux-amd64-rocksdb.tar.gz - retention-days: 7 + run: make gwemix.tar.gz + - name: Check Build + run: ls -al build/gwemix.tar.gz lint_test: strategy: From 8f0d9e1cd1f043afe694467b46f924fbe89ed61b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=84=9D=EC=9A=A9=28WM=29?= Date: Mon, 3 Jun 2024 14:00:34 +0900 Subject: [PATCH 49/51] Revert "feat: make artifact for master-ci" This reverts commit cb117c3f6a6d4ecd8fbcc07309ac52c41de95576. --- .github/workflows/master-ci.yml | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/.github/workflows/master-ci.yml b/.github/workflows/master-ci.yml index 043664d41fdb..46736e268895 100644 --- a/.github/workflows/master-ci.yml +++ b/.github/workflows/master-ci.yml @@ -19,21 +19,9 @@ jobs: go-version: 1.19 - name: Build Go-WEMIX - run: USE_ROCKSDB=YES make gwemix.tar.gz - - - name: Stat Go-WEMIX - run: | - ls -l build/gwemix.tar.gz - tar tf build/gwemix.tar.gz - - name: Move results to artifact - run: mv build/gwemix.tar.gz gwemix-${{ github.event.pull_request.head.sha }}-linux-amd64-rocksdb.tar.gz - - - name: Upload Go-WEMIX - uses: actions/upload-artifact@v4 - with: - name: artifact-${{ github.event.pull_request.head.sha }} - path: gwemix-${{ github.event.pull_request.head.sha }}-linux-amd64-rocksdb.tar.gz - retention-days: 7 + run: make gwemix.tar.gz + - name: Check Build + run: ls -al build/gwemix.tar.gz lint_test: strategy: From cec95f56fa39bc538dd2ff0facb96a28d7afd4e8 Mon Sep 17 00:00:00 2001 From: jed-wemade <127728629+jed-wemade@users.noreply.github.com> Date: Mon, 3 Jun 2024 15:09:03 +0900 Subject: [PATCH 50/51] fix: use default retention-days and ignore dev branch --- .github/workflows/artifacts.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/artifacts.yml b/.github/workflows/artifacts.yml index 86aea2b69c79..527a85885a3e 100644 --- a/.github/workflows/artifacts.yml +++ b/.github/workflows/artifacts.yml @@ -4,7 +4,6 @@ on: push: branches: - devnet - - dev - master jobs: @@ -35,4 +34,3 @@ jobs: with: name: artifact-${{ github.ref_name }}-${{ github.sha }} path: gwemix-${{ github.ref_name }}-${{ github.sha }}-linux-amd64-rocksdb.tar.gz - retention-days: 7 From 9d160117bbec4d8cb48e339785e5435f14195c3c Mon Sep 17 00:00:00 2001 From: egon-wm Date: Tue, 4 Jun 2024 09:54:50 +0900 Subject: [PATCH 51/51] fix: adjust boot node count (hotfix to dev) (#100) fix: adjust boot node count --- cmd/utils/flags.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 96e8cd654c53..6786ac702d82 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1041,6 +1041,9 @@ func setRandomBootstrapNodes(ctx *cli.Context, bootnodes []string) []string { } // select random bootnodes selectcount := params.BootnodeCount + if selectcount > bootnodeslen { + selectcount = bootnodeslen + } urls := make([]string, selectcount) tempnode := make([]string, bootnodeslen) copy(tempnode, bootnodes)