diff --git a/api/service/stagedstreamsync/staged_stream_sync.go b/api/service/stagedstreamsync/staged_stream_sync.go index 98922af28..0a14d0cb3 100644 --- a/api/service/stagedstreamsync/staged_stream_sync.go +++ b/api/service/stagedstreamsync/staged_stream_sync.go @@ -642,8 +642,9 @@ func (ss *StagedStreamSync) addConsensusLastMile(bc core.BlockChain, cs *consens case errors.Is(err, core.ErrNotLastBlockInEpoch): case err != nil: return errors.Wrap(err, "failed to InsertChain") + default: + hashes = append(hashes, block.Header().Hash()) } - hashes = append(hashes, block.Header().Hash()) } return nil }) diff --git a/api/service/stagedstreamsync/syncing.go b/api/service/stagedstreamsync/syncing.go index 738f2f920..9e8926468 100644 --- a/api/service/stagedstreamsync/syncing.go +++ b/api/service/stagedstreamsync/syncing.go @@ -219,6 +219,8 @@ func (s *StagedStreamSync) Debug(source string, msg interface{}) { // For each iteration, estimate the current block number, then fetch block & insert to blockchain func (s *StagedStreamSync) doSync(downloaderContext context.Context, initSync bool) (uint64, int, error) { + startedNumber := s.bc.CurrentBlock().NumberU64() + var totalInserted int s.initSync = initSync @@ -249,7 +251,7 @@ func (s *StagedStreamSync) doSync(downloaderContext context.Context, initSync bo for { ctx, cancel := context.WithCancel(downloaderContext) - n, err := s.doSyncCycle(ctx, initSync) + n, err := s.doSyncCycle(ctx) if err != nil { utils.Logger().Error(). Err(err). @@ -281,6 +283,8 @@ func (s *StagedStreamSync) doSync(downloaderContext context.Context, initSync bo Bool("isBeacon", s.isBeacon). Uint32("shard", s.bc.ShardID()). Int("blocks", totalInserted). + Uint64("startedNumber", startedNumber). + Uint64("currentNumber", s.bc.CurrentBlock().NumberU64()). Msg(WrapStagedSyncMsg("sync cycle blocks inserted successfully")) } @@ -304,7 +308,7 @@ func (s *StagedStreamSync) doSync(downloaderContext context.Context, initSync bo return estimatedHeight, totalInserted, nil } -func (s *StagedStreamSync) doSyncCycle(ctx context.Context, initSync bool) (int, error) { +func (s *StagedStreamSync) doSyncCycle(ctx context.Context) (int, error) { // TODO: initSync=true means currentCycleNumber==0, so we can remove initSync diff --git a/consensus/consensus.go b/consensus/consensus.go index 019fd8542..18b53e682 100644 --- a/consensus/consensus.go +++ b/consensus/consensus.go @@ -40,6 +40,10 @@ const ( AsyncProposal ) +type DownloadAsync interface { + DownloadAsync() +} + // Consensus is the main struct with all states and data related to consensus process. type Consensus struct { Decider quorum.Decider @@ -122,9 +126,7 @@ type Consensus struct { // finalityCounter keep tracks of the finality time finalityCounter atomic.Value //int64 - dHelper interface { - DownloadAsync() - } + dHelper DownloadAsync // Both flags only for initialization state. start bool @@ -190,10 +192,10 @@ func (consensus *Consensus) BlocksSynchronized() { } // BlocksNotSynchronized lets the main loop know that block is not synchronized -func (consensus *Consensus) BlocksNotSynchronized() { +func (consensus *Consensus) BlocksNotSynchronized(reason string) { consensus.mutex.Lock() defer consensus.mutex.Unlock() - consensus.syncNotReadyChan() + consensus.syncNotReadyChan(reason) } // VdfSeedSize returns the number of VRFs for VDF computation diff --git a/consensus/consensus_v2.go b/consensus/consensus_v2.go index 514feaf86..0eb6e338d 100644 --- a/consensus/consensus_v2.go +++ b/consensus/consensus_v2.go @@ -359,11 +359,12 @@ func (consensus *Consensus) syncReadyChan() { } } -func (consensus *Consensus) syncNotReadyChan() { - consensus.getLogger().Info().Msg("[ConsensusMainLoop] syncNotReadyChan") +func (consensus *Consensus) syncNotReadyChan(reason string) { + mode := consensus.current.Mode() consensus.setBlockNum(consensus.Blockchain().CurrentHeader().Number().Uint64() + 1) consensus.current.SetMode(Syncing) - consensus.getLogger().Info().Msg("[ConsensusMainLoop] Node is OUT OF SYNC") + consensus.getLogger().Info().Msgf("[ConsensusMainLoop] syncNotReadyChan, prev %s, reason %s", mode.String(), reason) + consensus.getLogger().Info().Msgf("[ConsensusMainLoop] Node is OUT OF SYNC, reason: %s", reason) consensusSyncCounterVec.With(prometheus.Labels{"consensus": "out_of_sync"}).Inc() } diff --git a/consensus/downloader.go b/consensus/downloader.go index 804a25aab..595d07b01 100644 --- a/consensus/downloader.go +++ b/consensus/downloader.go @@ -61,7 +61,7 @@ func (dh *downloadHelper) downloadStartedLoop(c *Consensus) { for { select { case <-dh.startedCh: - c.BlocksNotSynchronized() + c.BlocksNotSynchronized("downloadStartedLoop") case err := <-dh.startedSub.Err(): c.GetLogger().Info().Err(err).Msg("consensus download finished loop closed") diff --git a/consensus/validator.go b/consensus/validator.go index c148a6189..891fe0c03 100644 --- a/consensus/validator.go +++ b/consensus/validator.go @@ -65,7 +65,7 @@ func (consensus *Consensus) onAnnounce(msg *msg_pb.Message) { _, err := consensus.ValidateNewBlock(recvMsg) if err == nil { consensus.GetLogger().Info(). - Msg("[Announce] Block verified") + Msgf("[Announce] Block verified %d", recvMsg.BlockNum) } }() } diff --git a/core/blockchain_impl.go b/core/blockchain_impl.go index 39a41d654..9a1a8325c 100644 --- a/core/blockchain_impl.go +++ b/core/blockchain_impl.go @@ -1609,7 +1609,7 @@ func (bc *BlockChainImpl) insertChain(chain types.Blocks, verifyHeaders bool) (i switch status { case CanonStatTy: - logger.Info().Msg("Inserted new block") + logger.Info().Msgf("Inserted new block s: %d e: %d n:%d", block.ShardID(), block.Epoch().Uint64(), block.NumberU64()) coalescedLogs = append(coalescedLogs, logs...) blockInsertTimer.UpdateSince(bstart) events = append(events, ChainEvent{block, block.Hash(), logs}) diff --git a/core/epochchain.go b/core/epochchain.go index 7d9aeae1a..2dab28471 100644 --- a/core/epochchain.go +++ b/core/epochchain.go @@ -166,7 +166,8 @@ func (bc *EpochChain) InsertChain(blocks types.Blocks, _ bool) (int, error) { se1() se2() utils.Logger().Info(). - Msgf("[EPOCHSYNC] Added block %d %s", block.NumberU64(), block.Hash().Hex()) + Msgf("[EPOCHSYNC] Added block %d, epoch %d, %s", block.NumberU64(), block.Epoch().Uint64(), block.Hash().Hex()) + } return 0, nil } diff --git a/core/rawdb/accessors_offchain.go b/core/rawdb/accessors_offchain.go index dd4329903..4808c8c23 100644 --- a/core/rawdb/accessors_offchain.go +++ b/core/rawdb/accessors_offchain.go @@ -43,7 +43,7 @@ func WriteShardStateBytes(db DatabaseWriter, epoch *big.Int, data []byte) error } utils.Logger().Info(). Str("epoch", epoch.String()). - Int("size", len(data)).Msg("wrote sharding state") + Int("size", len(data)).Msgf("wrote sharding state, epoch %d", epoch.Uint64()) return nil } diff --git a/core/state/statedb.go b/core/state/statedb.go index fa5526354..344455e11 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -895,7 +895,9 @@ func (db *DB) Finalise(deleteEmptyObjects bool) { // Commit validator changes in cache to stateObjects // TODO: remove validator cache after commit for addr, wrapper := range db.stateValidators { - db.UpdateValidatorWrapper(addr, wrapper) + if err := db.UpdateValidatorWrapper(addr, wrapper); err != nil { + utils.Logger().Warn().Err(err).Msg("Unable to update the validator wrapper on the finalize") + } } addressesToPrefetch := make([][]byte, 0, len(db.journal.dirties)) for addr := range db.journal.dirties { diff --git a/internal/chain/engine.go b/internal/chain/engine.go index 5c949bf66..ff303579c 100644 --- a/internal/chain/engine.go +++ b/internal/chain/engine.go @@ -555,6 +555,14 @@ func setElectionEpochAndMinFee(chain engine.ChainReader, header *block.Header, s } isElected[addr] = struct{}{} } + + if config.IsMaxRate(newShardState.Epoch) { + for _, addr := range chain.ValidatorCandidates() { + if _, err := availability.UpdateMaxCommissionFee(state, addr, minRate); err != nil { + return err + } + } + } // due to a bug in the old implementation of the minimum fee, // unelected validators did not have their fee updated even // when the protocol required them to do so. here we fix it, diff --git a/internal/params/config.go b/internal/params/config.go index baecf1a65..78174341f 100644 --- a/internal/params/config.go +++ b/internal/params/config.go @@ -76,6 +76,7 @@ var ( HIP30Epoch: big.NewInt(1673), // 2023-11-02 17:30:00+00:00 NoNilDelegationsEpoch: EpochTBD, BlockGas30MEpoch: big.NewInt(1673), // 2023-11-02 17:30:00+00:00 + MaxRateEpoch: EpochTBD, } // TestnetChainConfig contains the chain parameters to run a node on the harmony test network. @@ -120,7 +121,7 @@ var ( HIP30Epoch: big.NewInt(2176), // 2023-10-12 10:00:00+00:00 NoNilDelegationsEpoch: EpochTBD, BlockGas30MEpoch: big.NewInt(2176), // 2023-10-12 10:00:00+00:00 - + MaxRateEpoch: EpochTBD, } // PangaeaChainConfig contains the chain parameters for the Pangaea network. // All features except for CrossLink are enabled at launch. @@ -165,6 +166,7 @@ var ( HIP30Epoch: EpochTBD, NoNilDelegationsEpoch: EpochTBD, BlockGas30MEpoch: big.NewInt(0), + MaxRateEpoch: EpochTBD, } // PartnerChainConfig contains the chain parameters for the Partner network. @@ -203,13 +205,14 @@ var ( SlotsLimitedEpoch: EpochTBD, // epoch to enable HIP-16 CrossShardXferPrecompileEpoch: big.NewInt(5), AllowlistEpoch: EpochTBD, - LeaderRotationInternalValidatorsEpoch: EpochTBD, + LeaderRotationInternalValidatorsEpoch: big.NewInt(2379), LeaderRotationExternalValidatorsEpoch: EpochTBD, FeeCollectEpoch: big.NewInt(5), ValidatorCodeFixEpoch: big.NewInt(5), HIP30Epoch: big.NewInt(7), BlockGas30MEpoch: big.NewInt(7), NoNilDelegationsEpoch: EpochTBD, + MaxRateEpoch: EpochTBD, } // StressnetChainConfig contains the chain parameters for the Stress test network. @@ -255,6 +258,7 @@ var ( HIP30Epoch: EpochTBD, NoNilDelegationsEpoch: big.NewInt(2), BlockGas30MEpoch: big.NewInt(0), + MaxRateEpoch: EpochTBD, } // LocalnetChainConfig contains the chain parameters to run for local development. @@ -299,6 +303,7 @@ var ( HIP30Epoch: EpochTBD, NoNilDelegationsEpoch: big.NewInt(2), BlockGas30MEpoch: big.NewInt(0), + MaxRateEpoch: EpochTBD, } // AllProtocolChanges ... @@ -345,6 +350,7 @@ var ( big.NewInt(0), // BlockGas30M big.NewInt(0), // HIP30Epoch big.NewInt(0), // NoNilDelegationsEpoch + big.NewInt(0), // MaxRateEpoch } // TestChainConfig ... @@ -391,6 +397,7 @@ var ( big.NewInt(0), // HIP30Epoch big.NewInt(0), // NoNilDelegationsEpoch big.NewInt(0), // BlockGas30M + big.NewInt(0), // MaxRateEpoch } // TestRules ... @@ -559,6 +566,9 @@ type ChainConfig struct { HIP30Epoch *big.Int `json:"hip30-epoch,omitempty"` BlockGas30MEpoch *big.Int `json:"block-gas-30m-epoch,omitempty"` + + // MaxRateEpoch will make sure the validator max-rate is at least equal to the minRate + the validator max-rate-increase + MaxRateEpoch *big.Int `json:"max-rate-epoch,omitempty"` } // String implements the fmt.Stringer interface. @@ -834,6 +844,10 @@ func (c *ChainConfig) IsHIP30(epoch *big.Int) bool { return isForked(c.HIP30Epoch, epoch) } +func (c *ChainConfig) IsMaxRate(epoch *big.Int) bool { + return isForked(c.MaxRateEpoch, epoch) +} + // During this epoch, shards 2 and 3 will start sending // their balances over to shard 0 or 1. func (c *ChainConfig) IsOneEpochBeforeHIP30(epoch *big.Int) bool { diff --git a/node/node_handler.go b/node/node_handler.go index c5feeed07..b745ca713 100644 --- a/node/node_handler.go +++ b/node/node_handler.go @@ -337,7 +337,7 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block) error { } BroadcastCXReceipts(newBlock, node.Consensus) } else { - if node.Consensus.Mode() != consensus.Listening { + if mode := node.Consensus.Mode(); mode != consensus.Listening { numSignatures := node.Consensus.NumSignaturesIncludedInBlock(newBlock) utils.Logger().Info(). Uint64("blockNum", newBlock.NumberU64()). @@ -347,9 +347,12 @@ func (node *Node) PostConsensusProcessing(newBlock *types.Block) error { Int("numTxns", len(newBlock.Transactions())). Int("numStakingTxns", len(newBlock.StakingTransactions())). Uint32("numSignatures", numSignatures). + Str("mode", mode.String()). Msg("BINGO !!! Reached Consensus") if node.Consensus.Mode() == consensus.Syncing { - node.Consensus.SetMode(node.Consensus.UpdateConsensusInformation()) + mode = node.Consensus.UpdateConsensusInformation() + utils.Logger().Info().Msgf("Switching to mode %s", mode) + node.Consensus.SetMode(mode) } node.Consensus.UpdateValidatorMetrics(float64(numSignatures), float64(newBlock.NumberU64())) diff --git a/node/node_syncing.go b/node/node_syncing.go index 5319827ff..b1ee21ea7 100644 --- a/node/node_syncing.go +++ b/node/node_syncing.go @@ -316,7 +316,7 @@ func (node *Node) doSync(syncInstance ISync, syncingPeerProvider SyncingPeerProv if isSynchronized, _, _ := syncInstance.GetParsedSyncStatusDoubleChecked(); !isSynchronized { node.IsSynchronized.UnSet() if willJoinConsensus { - consensus.BlocksNotSynchronized() + consensus.BlocksNotSynchronized("node.doSync") } isBeacon := bc.ShardID() == shard.BeaconChainShardID syncInstance.SyncLoop(bc, isBeacon, consensus, legacysync.LoopMinTime) diff --git a/rpc/eth/types.go b/rpc/eth/types.go index f76aa4442..f1ad725eb 100644 --- a/rpc/eth/types.go +++ b/rpc/eth/types.go @@ -110,6 +110,37 @@ func NewTransaction( } return result, nil } +func NewTransactionFromTransaction( + tx *types.Transaction, blockHash common.Hash, + blockNumber uint64, timestamp uint64, index uint64, +) (*Transaction, error) { + from, err := tx.SenderAddress() + if err != nil { + return nil, fmt.Errorf("unable to get sender address: %w", err) + } + v, r, s := tx.RawSignatureValues() + + result := &Transaction{ + From: from, + Gas: hexutil.Uint64(tx.GasLimit()), + GasPrice: (*hexutil.Big)(tx.GasPrice()), + Hash: tx.Hash(), + Input: hexutil.Bytes(tx.Data()), + Nonce: hexutil.Uint64(tx.Nonce()), + To: tx.To(), + Value: (*hexutil.Big)(tx.Value()), + Timestamp: hexutil.Uint64(timestamp), + V: (*hexutil.Big)(v), + R: (*hexutil.Big)(r), + S: (*hexutil.Big)(s), + } + if blockHash != (common.Hash{}) { + result.BlockHash = &blockHash + result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber)) + result.TransactionIndex = (*hexutil.Uint64)(&index) + } + return result, nil +} // NewReceipt returns the RPC data for a new receipt func NewReceipt(tx *types.EthTransaction, blockHash common.Hash, blockNumber, blockIndex uint64, receipt *types.Receipt) (map[string]interface{}, error) { diff --git a/rpc/transaction.go b/rpc/transaction.go index 8ea211d6a..4106425c2 100644 --- a/rpc/transaction.go +++ b/rpc/transaction.go @@ -236,7 +236,7 @@ func (s *PublicTransactionService) newRPCTransaction(tx *types.Transaction, bloc } return NewStructuredResponse(tx) case Eth: - tx, err := eth.NewTransaction(tx.ConvertToEth(), blockHash, blockNumber, timestamp, index) + tx, err := eth.NewTransactionFromTransaction(tx, blockHash, blockNumber, timestamp, index) if err != nil { DoMetricRPCQueryInfo(GetTransactionByHash, FailedNumber) return nil, err @@ -751,7 +751,7 @@ func (s *PublicTransactionService) GetTransactionReceipt( return nil, err } return NewStructuredResponse(RPCReceipt) - case V2: + case V2, Eth: if tx == nil { RPCReceipt, err = v2.NewReceipt(stx, blockHash, blockNumber, index, receipt) } else { @@ -761,14 +761,6 @@ func (s *PublicTransactionService) GetTransactionReceipt( return nil, err } return NewStructuredResponse(RPCReceipt) - case Eth: - if tx != nil { - RPCReceipt, err = eth.NewReceipt(tx.ConvertToEth(), blockHash, blockNumber, index, receipt) - } - if err != nil { - return nil, err - } - return NewStructuredResponse(RPCReceipt) default: return nil, ErrUnknownRPCVersion } diff --git a/staking/availability/measure.go b/staking/availability/measure.go index 881baa855..6bf36bfb0 100644 --- a/staking/availability/measure.go +++ b/staking/availability/measure.go @@ -267,3 +267,27 @@ func UpdateMinimumCommissionFee( } return false, nil } + +// UpdateMaxCommissionFee makes sure the max-rate is at least higher than the rate + max-rate-change. +func UpdateMaxCommissionFee(state *state.DB, addr common.Address, minRate numeric.Dec) (bool, error) { + utils.Logger().Info().Msg("begin update max commission fee") + + wrapper, err := state.ValidatorWrapper(addr, true, false) + if err != nil { + return false, err + } + + minMaxRate := minRate.Add(wrapper.MaxChangeRate) + + if wrapper.MaxRate.LT(minMaxRate) { + utils.Logger().Info(). + Str("addr", addr.Hex()). + Str("old max-rate", wrapper.MaxRate.String()). + Str("new max-rate", minMaxRate.String()). + Msg("updating max commission rate") + wrapper.MaxRate.SetBytes(minMaxRate.Bytes()) + return true, nil + } + + return false, nil +} diff --git a/test/build-localnet-validator.sh b/test/build-localnet-validator.sh index 08d987777..70501c8d6 100644 --- a/test/build-localnet-validator.sh +++ b/test/build-localnet-validator.sh @@ -32,7 +32,7 @@ hmy --node="http://localhost:9500" staking create-validator \ --bls-pubkeys 4f41a37a3a8d0695dd6edcc58142c6b7d98e74da5c90e79b587b3b960b6a4f5e048e6d8b8a000d77a478d44cd640270c,7dcc035a943e29e17959dabe636efad7303d2c6f273ace457ba9dcc2fd19d3f37e70ba1cd8d082cf8ff7be2f861db48c \ --name "s0-localnet-validator1" --identity "validator1" --details "validator1" \ --security-contact "localnet" --website "localnet.one" \ - --max-change-rate 0.1 --max-rate 0.1 --rate 0.1 \ + --max-change-rate 0.01 --max-rate 0.01 --rate 0.01 \ --max-total-delegation 100000000 --min-self-delegation 10000 --bls-pubkeys-dir .hmy/extbls/ hmy --node="http://localhost:9500" staking create-validator \ @@ -40,7 +40,7 @@ hmy --node="http://localhost:9500" staking create-validator \ --bls-pubkeys b0917378b179a519a5055259c4f8980cce37d58af300b00dd98b07076d3d9a3b16c4a55f84522f553872225a7b1efc0c \ --name "s0-localnet-validator2" --identity "validator2" --details "validator2" \ --security-contact "localnet" --website "localnet.one" \ - --max-change-rate 0.1 --max-rate 0.1 --rate 0.1 \ + --max-change-rate 0.1 --max-rate 0.1 --rate 0.05 \ --max-total-delegation 100000000 --min-self-delegation 10000 --bls-pubkeys-dir .hmy/extbls/ hmy --node="http://localhost:9500" staking create-validator \