Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Main -> Dev Consolidation #2 #4600

Merged
merged 11 commits into from
Jan 9, 2024
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