Skip to content

Commit

Permalink
Merge pull request #4600 from harmony-one/maintodev122023
Browse files Browse the repository at this point in the history
Main -> Dev Consolidation #2
  • Loading branch information
sophoah authored Jan 9, 2024
2 parents 5443bf7 + 7df72eb commit 2927929
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 48 deletions.
10 changes: 3 additions & 7 deletions core/tx_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -850,15 +850,11 @@ func (pool *TxPool) validateStakingTx(tx *staking.StakingTransaction) error {
}
currentBlockNumber := pool.chain.CurrentBlock().Number()
pendingBlockNumber := new(big.Int).Add(currentBlockNumber, big.NewInt(1))
pendingEpoch := pool.chain.CurrentBlock().Epoch()
if shard.Schedule.IsLastBlock(currentBlockNumber.Uint64()) {
pendingEpoch = new(big.Int).Add(pendingEpoch, big.NewInt(1))
}
chainContext, ok := pool.chain.(ChainContext)
if !ok {
chainContext = nil // might use testing blockchain, set to nil for verifier to handle.
}
_, err = VerifyAndCreateValidatorFromMsg(pool.currentState, chainContext, pendingEpoch, pendingBlockNumber, stkMsg)
_, err = VerifyAndCreateValidatorFromMsg(pool.currentState, chainContext, pool.pendingEpoch(), pendingBlockNumber, stkMsg)
return err
case staking.DirectiveEditValidator:
msg, err := staking.RLPDecodeStakeMsg(tx.Data(), staking.DirectiveEditValidator)
Expand Down Expand Up @@ -932,7 +928,6 @@ func (pool *TxPool) validateStakingTx(tx *staking.StakingTransaction) error {
if from != stkMsg.DelegatorAddress {
return errors.WithMessagef(ErrInvalidSender, "staking transaction sender is %s", b32)
}

_, err = VerifyAndUndelegateFromMsg(pool.currentState, pool.pendingEpoch(), stkMsg)
return err
case staking.DirectiveCollectRewards:
Expand Down Expand Up @@ -964,11 +959,12 @@ func (pool *TxPool) validateStakingTx(tx *staking.StakingTransaction) error {
}
}

// pendingEpoch refers to the epoch of the pending block
func (pool *TxPool) pendingEpoch() *big.Int {
currentBlock := pool.chain.CurrentBlock()
pendingEpoch := currentBlock.Epoch()
if shard.Schedule.IsLastBlock(currentBlock.Number().Uint64()) {
pendingEpoch.Add(pendingEpoch, big.NewInt(1))
pendingEpoch = new(big.Int).Add(pendingEpoch, common.Big1)
}
return pendingEpoch
}
Expand Down
8 changes: 7 additions & 1 deletion hmy/staking.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,11 @@ func (hmy *Harmony) IsNoEarlyUnlockEpoch(epoch *big.Int) bool {
return hmy.BlockChain.Config().IsNoEarlyUnlock(epoch)
}

// IsMaxRate ...
func (hmy *Harmony) IsMaxRate(epoch *big.Int) bool {
return hmy.BlockChain.Config().IsMaxRate(epoch)
}

// IsCommitteeSelectionBlock checks if the given block is the committee selection block
func (hmy *Harmony) IsCommitteeSelectionBlock(header *block.Header) bool {
return chain.IsCommitteeSelectionBlock(hmy.BlockChain, header)
Expand Down Expand Up @@ -592,6 +597,7 @@ func (hmy *Harmony) GetUndelegationPayouts(
return undelegationPayouts, nil
}

isMaxRate := hmy.IsMaxRate(epoch)
lockingPeriod := hmy.GetDelegationLockingPeriodInEpoch(undelegationPayoutBlock.Epoch())
for _, validator := range hmy.GetAllValidatorAddresses() {
wrapper, err := hmy.BlockChain.ReadValidatorInformationAtRoot(validator, undelegationPayoutBlock.Root())
Expand All @@ -600,7 +606,7 @@ func (hmy *Harmony) GetUndelegationPayouts(
}
noEarlyUnlock := hmy.IsNoEarlyUnlockEpoch(epoch)
for _, delegation := range wrapper.Delegations {
withdraw := delegation.RemoveUnlockedUndelegations(epoch, wrapper.LastEpochInCommittee, lockingPeriod, noEarlyUnlock)
withdraw := delegation.RemoveUnlockedUndelegations(epoch, wrapper.LastEpochInCommittee, lockingPeriod, noEarlyUnlock, isMaxRate)
if withdraw.Cmp(bigZero) == 1 {
undelegationPayouts.SetPayoutByDelegatorAddrAndValidatorAddr(validator, delegation.DelegatorAddress, withdraw)
}
Expand Down
29 changes: 25 additions & 4 deletions internal/chain/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,9 +370,15 @@ func payoutUndelegations(
const msg = "[Finalize] failed to read all validators"
return errors.New(msg)
}
// Payout undelegated/unlocked tokens
// Payout undelegated/unlocked tokens at the end of each epoch
lockPeriod := GetLockPeriodInEpoch(chain, header.Epoch())
noEarlyUnlock := chain.Config().IsNoEarlyUnlock(header.Epoch())
newShardState, err := header.GetShardState()
if err != nil {
const msg = "[Finalize] failed to read shard state"
return errors.New(msg)
}
isMaxRate := chain.Config().IsMaxRate(newShardState.Epoch)
for _, validator := range validators {
wrapper, err := state.ValidatorWrapper(validator, true, false)
if err != nil {
Expand All @@ -383,7 +389,7 @@ func payoutUndelegations(
for i := range wrapper.Delegations {
delegation := &wrapper.Delegations[i]
totalWithdraw := delegation.RemoveUnlockedUndelegations(
header.Epoch(), wrapper.LastEpochInCommittee, lockPeriod, noEarlyUnlock,
header.Epoch(), wrapper.LastEpochInCommittee, lockPeriod, noEarlyUnlock, isMaxRate,
)
if totalWithdraw.Sign() != 0 {
state.AddBalance(delegation.DelegatorAddress, totalWithdraw)
Expand Down Expand Up @@ -426,6 +432,7 @@ func setElectionEpochAndMinFee(chain engine.ChainReader, header *block.Header, s
map[common.Address]struct{},
len(newShardState.StakedValidators().Addrs),
)
// this loop is for elected validators only
for _, addr := range newShardState.StakedValidators().Addrs {
wrapper, err := state.ValidatorWrapper(addr, true, false)
if err != nil {
Expand Down Expand Up @@ -459,8 +466,9 @@ func setElectionEpochAndMinFee(chain engine.ChainReader, header *block.Header, s
// 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,
// but only after the HIP-30 hard fork is effective.
if config.IsHIP30(newShardState.Epoch) {
// but only after the HIP-30 hard fork is effective
// this loop applies to all validators, but excludes the ones in isElected
if config.IsHIP30(newShardState.Epoch) && minRateNotZero {
for _, addr := range chain.ValidatorCandidates() {
// skip elected validator
if _, ok := isElected[addr]; ok {
Expand All @@ -474,6 +482,19 @@ func setElectionEpochAndMinFee(chain engine.ChainReader, header *block.Header, s
}
}
}

// for all validators which have MaxRate < minRate + maxChangeRate
// set their MaxRate equal to the minRate + MaxChangeRate
// this will allow the wrapper.SanityCheck to pass if Rate is set to a value
// higher than the the MaxRate by UpdateMinimumCommissionFee above
if config.IsMaxRate(newShardState.Epoch) && minRateNotZero {
for _, addr := range chain.ValidatorCandidates() {
if _, err := availability.UpdateMaxCommissionFee(state, addr, minRate); err != nil {
return err
}
}
}

return nil
}

Expand Down
3 changes: 3 additions & 0 deletions internal/params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,9 @@ func (c *ChainConfig) mustValid() {
// capabilities required to transfer balance across shards
require(c.HIP30Epoch.Cmp(c.CrossTxEpoch) > 0,
"must satisfy: HIP30Epoch > CrossTxEpoch")
// max rate (7%) fix is applied on or after hip30
require(c.MaxRateEpoch.Cmp(c.HIP30Epoch) >= 0,
"must satisfy: MaxRateEpoch >= HIP30Epoch")
}

// IsEIP155 returns whether epoch is either equal to the EIP155 fork epoch or greater.
Expand Down
6 changes: 5 additions & 1 deletion rpc/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -464,7 +464,11 @@ func (s *PublicBlockchainService) GetBlockReceipts(
r, err = v2.NewReceipt(tx, blockHash, block.NumberU64(), index, rmap[tx.Hash()])
case Eth:
if tx, ok := tx.(*types.Transaction); ok {
r, err = eth.NewReceipt(tx.ConvertToEth(), blockHash, block.NumberU64(), index, rmap[tx.Hash()])
from, err := tx.SenderAddress()
if err != nil {
return nil, err
}
r, err = eth.NewReceipt(from, tx.ConvertToEth(), blockHash, block.NumberU64(), index, rmap[tx.Hash()])
}
default:
return nil, ErrUnknownRPCVersion
Expand Down
34 changes: 14 additions & 20 deletions rpc/eth/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,9 @@ type Transaction struct {
// representation, with the given location metadata set (if available).
// Note that all txs on Harmony are replay protected (post EIP155 epoch).
func NewTransaction(
tx *types.EthTransaction, blockHash common.Hash,
from common.Address, tx *types.EthTransaction, blockHash common.Hash,
blockNumber uint64, timestamp uint64, index uint64,
) (*Transaction, error) {
from := common.Address{}
var err error
if tx.IsEthCompatible() {
from, err = tx.SenderAddress()
} else {
from, err = tx.ConvertToHmy().SenderAddress()
}
if err != nil {
return nil, err
}
v, r, s := tx.RawSignatureValues()

result := &Transaction{
Expand Down Expand Up @@ -143,14 +133,9 @@ func NewTransactionFromTransaction(
}

// 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) {
senderAddr, err := tx.SenderAddress()
if err != nil {
return nil, err
}

func NewReceipt(senderAddr common.Address, tx *types.EthTransaction, blockHash common.Hash, blockNumber, blockIndex uint64, receipt *types.Receipt) (map[string]interface{}, error) {
ethTxHash := tx.Hash()
for i, _ := range receipt.Logs {
for i := range receipt.Logs {
// Override log txHash with receipt's
receipt.Logs[i].TxHash = ethTxHash
}
Expand Down Expand Up @@ -240,7 +225,11 @@ func blockWithFullTxFromBlock(b *types.Block) (*BlockWithFullTx, error) {
}

for idx, tx := range b.Transactions() {
fmtTx, err := NewTransaction(tx.ConvertToEth(), b.Hash(), b.NumberU64(), b.Time().Uint64(), uint64(idx))
from, err := tx.SenderAddress()
if err != nil {
return nil, err
}
fmtTx, err := NewTransaction(from, tx.ConvertToEth(), b.Hash(), b.NumberU64(), b.Time().Uint64(), uint64(idx))
if err != nil {
return nil, err
}
Expand All @@ -257,5 +246,10 @@ func NewTransactionFromBlockIndex(b *types.Block, index uint64) (*Transaction, e
"tx index %v greater than or equal to number of transactions on block %v", index, b.Hash().String(),
)
}
return NewTransaction(txs[index].ConvertToEth(), b.Hash(), b.NumberU64(), b.Time().Uint64(), index)
tx := txs[index].ConvertToEth()
from, err := tx.SenderAddress()
if err != nil {
return nil, err
}
return NewTransaction(from, tx, b.Hash(), b.NumberU64(), b.Time().Uint64(), index)
}
9 changes: 8 additions & 1 deletion rpc/pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,14 @@ func (s *PublicPoolService) PendingTransactions(
continue // Legacy behavior is to not return error here
}
case Eth:
tx, err = eth.NewTransaction(plainTx.ConvertToEth(), common.Hash{}, 0, 0, 0)
from, err := plainTx.SenderAddress()
if err != nil {
utils.Logger().Debug().
Err(err).
Msgf("%v error at %v", LogTag, "PendingTransactions")
continue // Legacy behavior is to not return error here
}
tx, err = eth.NewTransaction(from, plainTx.ConvertToEth(), common.Hash{}, 0, 0, 0)
if err != nil {
utils.Logger().Debug().
Err(err).
Expand Down
23 changes: 21 additions & 2 deletions rpc/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,13 @@ func (s *PublicTransactionService) newRPCTransaction(tx *types.Transaction, bloc
}
return NewStructuredResponse(tx)
case Eth:
tx, err := eth.NewTransactionFromTransaction(tx, blockHash, blockNumber, timestamp, index)
// calculate SenderAddress before ConvertToEth
senderAddr, err := tx.SenderAddress()
if err != nil {
DoMetricRPCQueryInfo(GetTransactionByHash, FailedNumber)
return nil, err
}
tx, err := eth.NewTransaction(senderAddr, tx.ConvertToEth(), blockHash, blockNumber, timestamp, index)
if err != nil {
DoMetricRPCQueryInfo(GetTransactionByHash, FailedNumber)
return nil, err
Expand Down Expand Up @@ -751,7 +757,7 @@ func (s *PublicTransactionService) GetTransactionReceipt(
return nil, err
}
return NewStructuredResponse(RPCReceipt)
case V2, Eth:
case V2:
if tx == nil {
RPCReceipt, err = v2.NewReceipt(stx, blockHash, blockNumber, index, receipt)
} else {
Expand All @@ -761,6 +767,19 @@ func (s *PublicTransactionService) GetTransactionReceipt(
return nil, err
}
return NewStructuredResponse(RPCReceipt)
case Eth:
if tx != nil {
// calculate SenderAddress before ConvertToEth
senderAddr, err := tx.SenderAddress()
if err != nil {
return nil, err
}
RPCReceipt, err = eth.NewReceipt(senderAddr, tx.ConvertToEth(), blockHash, blockNumber, index, receipt)
}
if err != nil {
return nil, err
}
return NewStructuredResponse(RPCReceipt)
default:
return nil, ErrUnknownRPCVersion
}
Expand Down
16 changes: 11 additions & 5 deletions staking/types/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,21 @@ func (d *Delegation) DeleteEntry(epoch *big.Int) {
// RemoveUnlockedUndelegations removes all fully unlocked
// undelegations and returns the total sum
func (d *Delegation) RemoveUnlockedUndelegations(
curEpoch, lastEpochInCommittee *big.Int, lockPeriod int, noEarlyUnlock bool,
curEpoch, lastEpochInCommittee *big.Int, lockPeriod int, noEarlyUnlock bool, isMaxRate bool,
) *big.Int {
totalWithdraw := big.NewInt(0)
count := 0
for j := range d.Undelegations {
if big.NewInt(0).Sub(curEpoch, d.Undelegations[j].Epoch).Int64() >= int64(lockPeriod) ||
(!noEarlyUnlock && big.NewInt(0).Sub(curEpoch, lastEpochInCommittee).Int64() >= int64(lockPeriod)) {
// need to wait at least 7 epochs to withdraw; or the validator has been out of committee for 7 epochs
totalWithdraw.Add(totalWithdraw, d.Undelegations[j].Amount)
epochsSinceUndelegation := big.NewInt(0).Sub(curEpoch, d.Undelegations[j].Epoch).Int64()
// >=7 epochs have passed since undelegation, or
lockPeriodApplies := epochsSinceUndelegation >= int64(lockPeriod)
// >=7 epochs have passed since unelection during the noEarlyUnlock configuration
earlyUnlockPeriodApplies := big.NewInt(0).Sub(curEpoch, lastEpochInCommittee).Int64() >= int64(lockPeriod) && !noEarlyUnlock
maxRateApplies := isMaxRate && epochsSinceUndelegation > int64(lockPeriod)
if lockPeriodApplies || earlyUnlockPeriodApplies {
if !maxRateApplies {
totalWithdraw.Add(totalWithdraw, d.Undelegations[j].Amount)
}
count++
} else {
break
Expand Down
Loading

0 comments on commit 2927929

Please sign in to comment.