Skip to content

Commit 3e7ff38

Browse files
do not return bech32 in receipt, fix 7% fee (#4588)
* Fix: max rate issue (#4580) * fix: max-rate bellow the era min-rate * fix comments * add localnet epoch config * update config * update config * update config * update config * add log * remove hip30 from localnet * disable localnet config * engine: actually fix the 7% fee implementation * rpc: fix transaction receipt format for eth use the same receipt as `hmyv2_`. using a boolean variable, decide if the addresses need to be converted to bech32. do not return a contract address unless a contract was actually deployed in the transaction by using a pointer address type. * rpc: add comment indicating function is unused with the switch to `v2.NewReceipt` for even `eth_` queries, the `eth.NewReceipt` function is no longer used * build: fix delegation tests * update comment blocks was referring to `blocks of code` and not blocks in a chain. removed the confusing word * rpc: remove ConvertToEth in GetBlockReceipts * internal: max rate hard fork schedule * internal: testnet max rate schedule --------- Co-authored-by: Diego Nava <[email protected]>
1 parent 2bba333 commit 3e7ff38

File tree

13 files changed

+138
-67
lines changed

13 files changed

+138
-67
lines changed

core/state/statedb.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -894,7 +894,9 @@ func (db *DB) Finalise(deleteEmptyObjects bool) {
894894
// Commit validator changes in cache to stateObjects
895895
// TODO: remove validator cache after commit
896896
for addr, wrapper := range db.stateValidators {
897-
db.UpdateValidatorWrapper(addr, wrapper)
897+
if err := db.UpdateValidatorWrapper(addr, wrapper); err != nil {
898+
utils.Logger().Warn().Err(err).Msg("Unable to update the validator wrapper on the finalize")
899+
}
898900
}
899901
addressesToPrefetch := make([][]byte, 0, len(db.journal.dirties))
900902
for addr := range db.journal.dirties {

core/tx_pool.go

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -850,15 +850,11 @@ func (pool *TxPool) validateStakingTx(tx *staking.StakingTransaction) error {
850850
}
851851
currentBlockNumber := pool.chain.CurrentBlock().Number()
852852
pendingBlockNumber := new(big.Int).Add(currentBlockNumber, big.NewInt(1))
853-
pendingEpoch := pool.chain.CurrentBlock().Epoch()
854-
if shard.Schedule.IsLastBlock(currentBlockNumber.Uint64()) {
855-
pendingEpoch = new(big.Int).Add(pendingEpoch, big.NewInt(1))
856-
}
857853
chainContext, ok := pool.chain.(ChainContext)
858854
if !ok {
859855
chainContext = nil // might use testing blockchain, set to nil for verifier to handle.
860856
}
861-
_, err = VerifyAndCreateValidatorFromMsg(pool.currentState, chainContext, pendingEpoch, pendingBlockNumber, stkMsg)
857+
_, err = VerifyAndCreateValidatorFromMsg(pool.currentState, chainContext, pool.pendingEpoch(), pendingBlockNumber, stkMsg)
862858
return err
863859
case staking.DirectiveEditValidator:
864860
msg, err := staking.RLPDecodeStakeMsg(tx.Data(), staking.DirectiveEditValidator)
@@ -932,7 +928,6 @@ func (pool *TxPool) validateStakingTx(tx *staking.StakingTransaction) error {
932928
if from != stkMsg.DelegatorAddress {
933929
return errors.WithMessagef(ErrInvalidSender, "staking transaction sender is %s", b32)
934930
}
935-
936931
_, err = VerifyAndUndelegateFromMsg(pool.currentState, pool.pendingEpoch(), stkMsg)
937932
return err
938933
case staking.DirectiveCollectRewards:
@@ -964,11 +959,12 @@ func (pool *TxPool) validateStakingTx(tx *staking.StakingTransaction) error {
964959
}
965960
}
966961

962+
// pendingEpoch refers to the epoch of the pending block
967963
func (pool *TxPool) pendingEpoch() *big.Int {
968964
currentBlock := pool.chain.CurrentBlock()
969965
pendingEpoch := currentBlock.Epoch()
970966
if shard.Schedule.IsLastBlock(currentBlock.Number().Uint64()) {
971-
pendingEpoch.Add(pendingEpoch, big.NewInt(1))
967+
pendingEpoch = new(big.Int).Add(pendingEpoch, common.Big1)
972968
}
973969
return pendingEpoch
974970
}

hmy/staking.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ func (hmy *Harmony) IsNoEarlyUnlockEpoch(epoch *big.Int) bool {
143143
return hmy.BlockChain.Config().IsNoEarlyUnlock(epoch)
144144
}
145145

146+
// IsMaxRate ...
147+
func (hmy *Harmony) IsMaxRate(epoch *big.Int) bool {
148+
return hmy.BlockChain.Config().IsMaxRate(epoch)
149+
}
150+
146151
// IsCommitteeSelectionBlock checks if the given block is the committee selection block
147152
func (hmy *Harmony) IsCommitteeSelectionBlock(header *block.Header) bool {
148153
return chain.IsCommitteeSelectionBlock(hmy.BlockChain, header)
@@ -592,6 +597,7 @@ func (hmy *Harmony) GetUndelegationPayouts(
592597
return undelegationPayouts, nil
593598
}
594599

600+
isMaxRate := hmy.IsMaxRate(epoch)
595601
lockingPeriod := hmy.GetDelegationLockingPeriodInEpoch(undelegationPayoutBlock.Epoch())
596602
for _, validator := range hmy.GetAllValidatorAddresses() {
597603
wrapper, err := hmy.BlockChain.ReadValidatorInformationAtRoot(validator, undelegationPayoutBlock.Root())
@@ -600,7 +606,7 @@ func (hmy *Harmony) GetUndelegationPayouts(
600606
}
601607
noEarlyUnlock := hmy.IsNoEarlyUnlockEpoch(epoch)
602608
for _, delegation := range wrapper.Delegations {
603-
withdraw := delegation.RemoveUnlockedUndelegations(epoch, wrapper.LastEpochInCommittee, lockingPeriod, noEarlyUnlock)
609+
withdraw := delegation.RemoveUnlockedUndelegations(epoch, wrapper.LastEpochInCommittee, lockingPeriod, noEarlyUnlock, isMaxRate)
604610
if withdraw.Cmp(bigZero) == 1 {
605611
undelegationPayouts.SetPayoutByDelegatorAddrAndValidatorAddr(validator, delegation.DelegatorAddress, withdraw)
606612
}

internal/chain/engine.go

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -370,9 +370,15 @@ func payoutUndelegations(
370370
const msg = "[Finalize] failed to read all validators"
371371
return errors.New(msg)
372372
}
373-
// Payout undelegated/unlocked tokens
373+
// Payout undelegated/unlocked tokens at the end of each epoch
374374
lockPeriod := GetLockPeriodInEpoch(chain, header.Epoch())
375375
noEarlyUnlock := chain.Config().IsNoEarlyUnlock(header.Epoch())
376+
newShardState, err := header.GetShardState()
377+
if err != nil {
378+
const msg = "[Finalize] failed to read shard state"
379+
return errors.New(msg)
380+
}
381+
isMaxRate := chain.Config().IsMaxRate(newShardState.Epoch)
376382
for _, validator := range validators {
377383
wrapper, err := state.ValidatorWrapper(validator, true, false)
378384
if err != nil {
@@ -383,7 +389,7 @@ func payoutUndelegations(
383389
for i := range wrapper.Delegations {
384390
delegation := &wrapper.Delegations[i]
385391
totalWithdraw := delegation.RemoveUnlockedUndelegations(
386-
header.Epoch(), wrapper.LastEpochInCommittee, lockPeriod, noEarlyUnlock,
392+
header.Epoch(), wrapper.LastEpochInCommittee, lockPeriod, noEarlyUnlock, isMaxRate,
387393
)
388394
if totalWithdraw.Sign() != 0 {
389395
state.AddBalance(delegation.DelegatorAddress, totalWithdraw)
@@ -426,6 +432,7 @@ func setElectionEpochAndMinFee(chain engine.ChainReader, header *block.Header, s
426432
map[common.Address]struct{},
427433
len(newShardState.StakedValidators().Addrs),
428434
)
435+
// this loop is for elected validators only
429436
for _, addr := range newShardState.StakedValidators().Addrs {
430437
wrapper, err := state.ValidatorWrapper(addr, true, false)
431438
if err != nil {
@@ -448,11 +455,13 @@ func setElectionEpochAndMinFee(chain engine.ChainReader, header *block.Header, s
448455
}
449456
isElected[addr] = struct{}{}
450457
}
458+
451459
// due to a bug in the old implementation of the minimum fee,
452460
// unelected validators did not have their fee updated even
453461
// when the protocol required them to do so. here we fix it,
454-
// but only after the HIP-30 hard fork is effective.
455-
if config.IsHIP30(newShardState.Epoch) {
462+
// but only after the HIP-30 hard fork is effective
463+
// this loop applies to all validators, but excludes the ones in isElected
464+
if config.IsHIP30(newShardState.Epoch) && minRateNotZero {
456465
for _, addr := range chain.ValidatorCandidates() {
457466
// skip elected validator
458467
if _, ok := isElected[addr]; ok {
@@ -466,6 +475,19 @@ func setElectionEpochAndMinFee(chain engine.ChainReader, header *block.Header, s
466475
}
467476
}
468477
}
478+
479+
// for all validators which have MaxRate < minRate + maxChangeRate
480+
// set their MaxRate equal to the minRate + MaxChangeRate
481+
// this will allow the wrapper.SanityCheck to pass if Rate is set to a value
482+
// higher than the the MaxRate by UpdateMinimumCommissionFee above
483+
if config.IsMaxRate(newShardState.Epoch) && minRateNotZero {
484+
for _, addr := range chain.ValidatorCandidates() {
485+
if _, err := availability.UpdateMaxCommissionFee(state, addr, minRate); err != nil {
486+
return err
487+
}
488+
}
489+
}
490+
469491
return nil
470492
}
471493

internal/params/config.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ var (
7575
ValidatorCodeFixEpoch: big.NewInt(1535), // 2023-07-20 05:51:07+00:00
7676
HIP30Epoch: big.NewInt(1673), // 2023-11-02 17:30:00+00:00
7777
BlockGas30MEpoch: big.NewInt(1673), // 2023-11-02 17:30:00+00:00
78+
MaxRateEpoch: big.NewInt(1733), // 2023-12-17 12:20:15+00:00
7879
}
7980

8081
// TestnetChainConfig contains the chain parameters to run a node on the harmony test network.
@@ -118,6 +119,7 @@ var (
118119
ValidatorCodeFixEpoch: big.NewInt(1296), // 2023-04-28 07:14:20+00:00
119120
HIP30Epoch: big.NewInt(2176), // 2023-10-12 10:00:00+00:00
120121
BlockGas30MEpoch: big.NewInt(2176), // 2023-10-12 10:00:00+00:00
122+
MaxRateEpoch: big.NewInt(2520), // 2023-12-16 12:17:14+00:00
121123
}
122124
// PangaeaChainConfig contains the chain parameters for the Pangaea network.
123125
// All features except for CrossLink are enabled at launch.
@@ -161,6 +163,7 @@ var (
161163
ValidatorCodeFixEpoch: EpochTBD,
162164
HIP30Epoch: EpochTBD,
163165
BlockGas30MEpoch: big.NewInt(0),
166+
MaxRateEpoch: EpochTBD,
164167
}
165168

166169
// PartnerChainConfig contains the chain parameters for the Partner network.
@@ -205,6 +208,7 @@ var (
205208
ValidatorCodeFixEpoch: big.NewInt(5),
206209
HIP30Epoch: big.NewInt(7),
207210
BlockGas30MEpoch: big.NewInt(7),
211+
MaxRateEpoch: EpochTBD,
208212
}
209213

210214
// StressnetChainConfig contains the chain parameters for the Stress test network.
@@ -249,6 +253,7 @@ var (
249253
ValidatorCodeFixEpoch: EpochTBD,
250254
HIP30Epoch: EpochTBD,
251255
BlockGas30MEpoch: big.NewInt(0),
256+
MaxRateEpoch: EpochTBD,
252257
}
253258

254259
// LocalnetChainConfig contains the chain parameters to run for local development.
@@ -292,6 +297,7 @@ var (
292297
ValidatorCodeFixEpoch: big.NewInt(2),
293298
HIP30Epoch: EpochTBD,
294299
BlockGas30MEpoch: big.NewInt(0),
300+
MaxRateEpoch: EpochTBD,
295301
}
296302

297303
// AllProtocolChanges ...
@@ -336,7 +342,8 @@ var (
336342
big.NewInt(0), // FeeCollectEpoch
337343
big.NewInt(0), // ValidatorCodeFixEpoch
338344
big.NewInt(0), // BlockGas30M
339-
big.NewInt(0), // HIP30Epoch
345+
big.NewInt(0), // BlockGas30M
346+
big.NewInt(0), // MaxRateEpoch
340347
}
341348

342349
// TestChainConfig ...
@@ -382,6 +389,7 @@ var (
382389
big.NewInt(0), // ValidatorCodeFixEpoch
383390
big.NewInt(0), // HIP30Epoch
384391
big.NewInt(0), // BlockGas30M
392+
big.NewInt(0), // MaxRateEpoch
385393
}
386394

387395
// TestRules ...
@@ -547,6 +555,9 @@ type ChainConfig struct {
547555
HIP30Epoch *big.Int `json:"hip30-epoch,omitempty"`
548556

549557
BlockGas30MEpoch *big.Int `json:"block-gas-30m-epoch,omitempty"`
558+
559+
// MaxRateEpoch will make sure the validator max-rate is at least equal to the minRate + the validator max-rate-increase
560+
MaxRateEpoch *big.Int `json:"max-rate-epoch,omitempty"`
550561
}
551562

552563
// String implements the fmt.Stringer interface.
@@ -612,6 +623,9 @@ func (c *ChainConfig) mustValid() {
612623
// capabilities required to transfer balance across shards
613624
require(c.HIP30Epoch.Cmp(c.CrossTxEpoch) > 0,
614625
"must satisfy: HIP30Epoch > CrossTxEpoch")
626+
// max rate (7%) fix is applied on or after hip30
627+
require(c.MaxRateEpoch.Cmp(c.HIP30Epoch) >= 0,
628+
"must satisfy: MaxRateEpoch >= HIP30Epoch")
615629
}
616630

617631
// IsEIP155 returns whether epoch is either equal to the EIP155 fork epoch or greater.
@@ -803,6 +817,10 @@ func (c *ChainConfig) IsHIP30(epoch *big.Int) bool {
803817
return isForked(c.HIP30Epoch, epoch)
804818
}
805819

820+
func (c *ChainConfig) IsMaxRate(epoch *big.Int) bool {
821+
return isForked(c.MaxRateEpoch, epoch)
822+
}
823+
806824
// During this epoch, shards 2 and 3 will start sending
807825
// their balances over to shard 0 or 1.
808826
func (c *ChainConfig) IsOneEpochBeforeHIP30(epoch *big.Int) bool {

rpc/blockchain.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -461,10 +461,10 @@ func (s *PublicBlockchainService) GetBlockReceipts(
461461
case V1:
462462
r, err = v1.NewReceipt(tx, blockHash, block.NumberU64(), index, rmap[tx.Hash()])
463463
case V2:
464-
r, err = v2.NewReceipt(tx, blockHash, block.NumberU64(), index, rmap[tx.Hash()])
464+
r, err = v2.NewReceipt(tx, blockHash, block.NumberU64(), index, rmap[tx.Hash()], false)
465465
case Eth:
466466
if tx, ok := tx.(*types.Transaction); ok {
467-
r, err = eth.NewReceipt(tx.ConvertToEth(), blockHash, block.NumberU64(), index, rmap[tx.Hash()])
467+
r, err = v2.NewReceipt(tx, blockHash, block.NumberU64(), index, rmap[tx.Hash()], true)
468468
}
469469
default:
470470
return nil, ErrUnknownRPCVersion

rpc/eth/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ func NewTransaction(
111111
return result, nil
112112
}
113113

114-
// NewReceipt returns the RPC data for a new receipt
114+
// NewReceipt returns the RPC data for a new receipt. It is unused at the moment.
115115
func NewReceipt(tx *types.EthTransaction, blockHash common.Hash, blockNumber, blockIndex uint64, receipt *types.Receipt) (map[string]interface{}, error) {
116116
senderAddr, err := tx.SenderAddress()
117117
if err != nil {

rpc/transaction.go

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -751,19 +751,11 @@ func (s *PublicTransactionService) GetTransactionReceipt(
751751
return nil, err
752752
}
753753
return NewStructuredResponse(RPCReceipt)
754-
case V2:
754+
case V2, Eth:
755755
if tx == nil {
756-
RPCReceipt, err = v2.NewReceipt(stx, blockHash, blockNumber, index, receipt)
756+
RPCReceipt, err = v2.NewReceipt(stx, blockHash, blockNumber, index, receipt, false)
757757
} else {
758-
RPCReceipt, err = v2.NewReceipt(tx, blockHash, blockNumber, index, receipt)
759-
}
760-
if err != nil {
761-
return nil, err
762-
}
763-
return NewStructuredResponse(RPCReceipt)
764-
case Eth:
765-
if tx != nil {
766-
RPCReceipt, err = eth.NewReceipt(tx.ConvertToEth(), blockHash, blockNumber, index, receipt)
758+
RPCReceipt, err = v2.NewReceipt(tx, blockHash, blockNumber, index, receipt, s.version == Eth)
767759
}
768760
if err != nil {
769761
return nil, err

rpc/v2/types.go

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -204,20 +204,20 @@ type UndelegateMsg struct {
204204

205205
// TxReceipt represents a transaction receipt that will serialize to the RPC representation.
206206
type TxReceipt struct {
207-
BlockHash common.Hash `json:"blockHash"`
208-
TransactionHash common.Hash `json:"transactionHash"`
209-
BlockNumber uint64 `json:"blockNumber"`
210-
TransactionIndex uint64 `json:"transactionIndex"`
211-
GasUsed uint64 `json:"gasUsed"`
212-
CumulativeGasUsed uint64 `json:"cumulativeGasUsed"`
213-
ContractAddress common.Address `json:"contractAddress"`
214-
Logs []*types.Log `json:"logs"`
215-
LogsBloom ethtypes.Bloom `json:"logsBloom"`
216-
ShardID uint32 `json:"shardID"`
217-
From string `json:"from"`
218-
To string `json:"to"`
219-
Root hexutil.Bytes `json:"root"`
220-
Status uint `json:"status"`
207+
BlockHash common.Hash `json:"blockHash"`
208+
TransactionHash common.Hash `json:"transactionHash"`
209+
BlockNumber uint64 `json:"blockNumber"`
210+
TransactionIndex uint64 `json:"transactionIndex"`
211+
GasUsed uint64 `json:"gasUsed"`
212+
CumulativeGasUsed uint64 `json:"cumulativeGasUsed"`
213+
ContractAddress *common.Address `json:"contractAddress"`
214+
Logs []*types.Log `json:"logs"`
215+
LogsBloom ethtypes.Bloom `json:"logsBloom"`
216+
ShardID uint32 `json:"shardID"`
217+
From string `json:"from"`
218+
To string `json:"to"`
219+
Root hexutil.Bytes `json:"root"`
220+
Status uint `json:"status"`
221221
}
222222

223223
// StakingTxReceipt represents a staking transaction receipt that will serialize to the RPC representation.
@@ -334,11 +334,11 @@ func NewTransaction(
334334

335335
// NewReceipt returns a transaction OR staking transaction that will serialize to the RPC representation
336336
func NewReceipt(
337-
tx interface{}, blockHash common.Hash, blockNumber, blockIndex uint64, receipt *types.Receipt,
337+
tx interface{}, blockHash common.Hash, blockNumber, blockIndex uint64, receipt *types.Receipt, eth bool,
338338
) (interface{}, error) {
339339
plainTx, ok := tx.(*types.Transaction)
340340
if ok {
341-
return NewTxReceipt(plainTx, blockHash, blockNumber, blockIndex, receipt)
341+
return NewTxReceipt(plainTx, blockHash, blockNumber, blockIndex, receipt, eth)
342342
}
343343
stakingTx, ok := tx.(*staking.StakingTransaction)
344344
if ok {
@@ -349,7 +349,7 @@ func NewReceipt(
349349

350350
// NewTxReceipt returns a plain transaction receipt that will serialize to the RPC representation
351351
func NewTxReceipt(
352-
tx *types.Transaction, blockHash common.Hash, blockNumber, blockIndex uint64, receipt *types.Receipt,
352+
tx *types.Transaction, blockHash common.Hash, blockNumber, blockIndex uint64, receipt *types.Receipt, eth bool,
353353
) (*TxReceipt, error) {
354354
// Set correct to & from address
355355
senderAddr, err := tx.SenderAddress()
@@ -363,13 +363,18 @@ func NewTxReceipt(
363363
receiver = ""
364364
} else {
365365
// Handle response type for regular transaction
366-
sender, err = internal_common.AddressToBech32(senderAddr)
367-
if err != nil {
368-
return nil, err
369-
}
370-
receiver, err = internal_common.AddressToBech32(*tx.To())
371-
if err != nil {
372-
return nil, err
366+
if eth {
367+
sender = senderAddr.String()
368+
receiver = tx.To().String()
369+
} else {
370+
sender, err = internal_common.AddressToBech32(senderAddr)
371+
if err != nil {
372+
return nil, err
373+
}
374+
receiver, err = internal_common.AddressToBech32(*tx.To())
375+
if err != nil {
376+
return nil, err
377+
}
373378
}
374379
}
375380

@@ -404,7 +409,7 @@ func NewTxReceipt(
404409

405410
// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation
406411
if receipt.ContractAddress != (common.Address{}) {
407-
txReceipt.ContractAddress = receipt.ContractAddress
412+
txReceipt.ContractAddress = &receipt.ContractAddress
408413
}
409414
return txReceipt, nil
410415
}

0 commit comments

Comments
 (0)