Add logs for redelegated tokens (#3310)

pull/3309/head
Rongjian Lan 4 years ago committed by GitHub
parent 3ff21060a9
commit 273d0c5633
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      core/staking_verifier.go
  2. 27
      core/staking_verifier_test.go
  3. 38
      core/state_transition.go
  4. 2
      core/tx_pool.go
  5. 2
      staking/params.go

@ -201,22 +201,23 @@ var (
// Note that this function never updates the stateDB, it only reads from stateDB.
func VerifyAndDelegateFromMsg(
stateDB vm.StateDB, epoch *big.Int, msg *staking.Delegate, delegations []staking.DelegationIndex, redelegation bool,
) ([]*staking.ValidatorWrapper, *big.Int, error) {
) ([]*staking.ValidatorWrapper, *big.Int, map[common.Address]*big.Int, error) {
if stateDB == nil {
return nil, nil, errStateDBIsMissing
return nil, nil, nil, errStateDBIsMissing
}
if !stateDB.IsValidator(msg.ValidatorAddress) {
return nil, nil, errValidatorNotExist
return nil, nil, nil, errValidatorNotExist
}
if msg.Amount.Sign() == -1 {
return nil, nil, errNegativeAmount
return nil, nil, nil, errNegativeAmount
}
if msg.Amount.Cmp(minimumDelegation) < 0 {
return nil, nil, errDelegationTooSmall
return nil, nil, nil, errDelegationTooSmall
}
updatedValidatorWrappers := []*staking.ValidatorWrapper{}
delegateBalance := big.NewInt(0).Set(msg.Amount)
fromLockedTokens := map[common.Address]*big.Int{}
var delegateeWrapper *staking.ValidatorWrapper
if redelegation {
@ -225,7 +226,7 @@ func VerifyAndDelegateFromMsg(
delegationIndex := &delegations[i]
wrapper, err := stateDB.ValidatorWrapperCopy(delegationIndex.ValidatorAddress)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
if uint64(len(wrapper.Delegations)) <= delegationIndex.Index {
utils.Logger().Warn().
@ -233,7 +234,7 @@ func VerifyAndDelegateFromMsg(
Uint64("delegation index", delegationIndex.Index).
Int("delegations length", len(wrapper.Delegations)).
Msg("Delegation index out of bound")
return nil, nil, errors.New("Delegation index out of bound")
return nil, nil, nil, errors.New("Delegation index out of bound")
}
delegation := &wrapper.Delegations[delegationIndex.Index]
@ -260,13 +261,14 @@ func VerifyAndDelegateFromMsg(
// Used undelegated token for redelegation
delegation.Undelegations = delegation.Undelegations[curIndex:]
if err := wrapper.SanityCheck(); err != nil {
return nil, nil, err
return nil, nil, nil, err
}
if bytes.Equal(delegationIndex.ValidatorAddress[:], msg.ValidatorAddress[:]) {
delegateeWrapper = wrapper
}
updatedValidatorWrappers = append(updatedValidatorWrappers, wrapper)
fromLockedTokens[delegationIndex.ValidatorAddress] = big.NewInt(0).Sub(startBalance, delegateBalance)
}
}
}
@ -275,7 +277,7 @@ func VerifyAndDelegateFromMsg(
var err error
delegateeWrapper, err = stateDB.ValidatorWrapperCopy(msg.ValidatorAddress)
if err != nil {
return nil, nil, err
return nil, nil, nil, err
}
updatedValidatorWrappers = append(updatedValidatorWrappers, delegateeWrapper)
}
@ -287,7 +289,7 @@ func VerifyAndDelegateFromMsg(
if bytes.Equal(delegation.DelegatorAddress.Bytes(), msg.DelegatorAddress.Bytes()) {
delegation.Amount.Add(delegation.Amount, msg.Amount)
if err := delegateeWrapper.SanityCheck(); err != nil {
return nil, nil, err
return nil, nil, nil, err
}
found = true
}
@ -301,24 +303,24 @@ func VerifyAndDelegateFromMsg(
),
)
if err := delegateeWrapper.SanityCheck(); err != nil {
return nil, nil, err
return nil, nil, nil, err
}
}
if delegateBalance.Cmp(big.NewInt(0)) == 0 {
// delegation fully from undelegated tokens, no need to deduct from balance.
return updatedValidatorWrappers, big.NewInt(0), nil
return updatedValidatorWrappers, big.NewInt(0), fromLockedTokens, nil
}
// Still need to deduct tokens from balance for delegation
// Check if there is enough liquid token to delegate
if !CanTransfer(stateDB, msg.DelegatorAddress, delegateBalance) {
return nil, nil, errors.Wrapf(
return nil, nil, nil, errors.Wrapf(
errInsufficientBalanceForStake, "totalRedelegatable: %v, balance: %v; trying to stake %v",
big.NewInt(0).Sub(msg.Amount, delegateBalance), stateDB.GetBalance(msg.DelegatorAddress), msg.Amount)
}
return updatedValidatorWrappers, delegateBalance, nil
return updatedValidatorWrappers, delegateBalance, fromLockedTokens, nil
}
// VerifyAndUndelegateFromMsg verifies the undelegate validator message

@ -729,6 +729,7 @@ func TestVerifyAndDelegateFromMsg(t *testing.T) {
expVWrappers []staking.ValidatorWrapper
expAmt *big.Int
expRedel map[common.Address]*big.Int
expErr error
}{
{
@ -875,6 +876,10 @@ func TestVerifyAndDelegateFromMsg(t *testing.T) {
expVWrappers: defaultExpVWrappersRedelegate(),
expAmt: big.NewInt(0),
expRedel: map[common.Address]*big.Int{
validatorAddr: fiveKOnes,
validatorAddr2: fiveKOnes,
},
},
{
// 11: redelegate with undelegation epoch too recent, have to use some balance
@ -892,6 +897,9 @@ func TestVerifyAndDelegateFromMsg(t *testing.T) {
return wrappers
}(),
expAmt: fiveKOnes,
expRedel: map[common.Address]*big.Int{
validatorAddr: fiveKOnes,
},
},
{
// 12: redelegate with not enough undelegated token, have to use some balance
@ -911,6 +919,10 @@ func TestVerifyAndDelegateFromMsg(t *testing.T) {
return wrappers
}(),
expAmt: tenKOnes,
expRedel: map[common.Address]*big.Int{
validatorAddr: fiveKOnes,
validatorAddr2: fiveKOnes,
},
},
{
// 13: no redelegation and full balance used
@ -989,7 +1001,7 @@ func TestVerifyAndDelegateFromMsg(t *testing.T) {
},
}
for i, test := range tests {
ws, amt, err := VerifyAndDelegateFromMsg(test.sdb, test.epoch, &test.msg, test.ds, test.redelegate)
ws, amt, amtRedel, err := VerifyAndDelegateFromMsg(test.sdb, test.epoch, &test.msg, test.ds, test.redelegate)
if assErr := assertError(err, test.expErr); assErr != nil {
t.Errorf("Test %v: %v", i, assErr)
@ -1002,6 +1014,19 @@ func TestVerifyAndDelegateFromMsg(t *testing.T) {
t.Errorf("Test %v: unexpected amount %v / %v", i, amt, test.expAmt)
}
if len(amtRedel) != len(test.expRedel) {
t.Errorf("Test %v: wrong expected redelegation length %d / %d", i, len(amtRedel), len(test.expRedel))
} else {
for key, value := range test.expRedel {
actValue, ok := amtRedel[key]
if !ok {
t.Errorf("Test %v: missing expected redelegation key/value %v / %v", i, key, value)
}
if value.Cmp(actValue) != 0 {
t.Errorf("Test %v: unexpeced redelegation value %v / %v", i, actValue, value)
}
}
}
for j := range ws {
if err := staketest.CheckValidatorWrapperEqual(*ws[j], test.expVWrappers[j]); err != nil {
t.Errorf("Test %v: %v", i, err)

@ -364,16 +364,7 @@ func (st *StateTransition) StakingTransitionDb() (usedGas uint64, err error) {
if msg.From() != stkMsg.DelegatorAddress {
return 0, errInvalidSigner
}
collectedRewards, tempErr := st.verifyAndApplyCollectRewards(stkMsg)
err = tempErr
if err == nil {
st.state.AddLog(&types.Log{
Address: stkMsg.DelegatorAddress,
Topics: []common.Hash{staking2.CollectRewardsTopic},
Data: collectedRewards.Bytes(),
BlockNumber: st.evm.BlockNumber.Uint64(),
})
}
_, err = st.verifyAndApplyCollectRewards(stkMsg)
default:
return 0, staking.ErrInvalidStakingKind
}
@ -420,7 +411,7 @@ func (st *StateTransition) verifyAndApplyDelegateTx(delegate *staking.Delegate)
if err != nil {
return err
}
updatedValidatorWrappers, balanceToBeDeducted, err := VerifyAndDelegateFromMsg(
updatedValidatorWrappers, balanceToBeDeducted, fromLockedTokens, err := VerifyAndDelegateFromMsg(
st.state, st.evm.EpochNumber, delegate, delegations, st.evm.ChainConfig().IsRedelegation(st.evm.EpochNumber))
if err != nil {
return err
@ -434,6 +425,22 @@ func (st *StateTransition) verifyAndApplyDelegateTx(delegate *staking.Delegate)
st.state.SubBalance(delegate.DelegatorAddress, balanceToBeDeducted)
// Add log if everything is good
for valAddr, redelegatedToken := range fromLockedTokens {
encodedRedelegationData := []byte{}
addrBytes := valAddr.Bytes()
encodedRedelegationData = append(encodedRedelegationData, addrBytes...)
encodedRedelegationData = append(encodedRedelegationData, redelegatedToken.Bytes()...)
// The data field format is:
// [first 20 bytes]: Validator address from which the locked token is used for redelegation.
// [rest of the bytes]: the bigInt serialized bytes for the token amount.
st.state.AddLog(&types.Log{
Address: delegate.DelegatorAddress,
Topics: []common.Hash{staking2.DelegateTopic},
Data: encodedRedelegationData,
BlockNumber: st.evm.BlockNumber.Uint64(),
})
}
return nil
}
@ -467,5 +474,14 @@ func (st *StateTransition) verifyAndApplyCollectRewards(collectRewards *staking.
}
}
st.state.AddBalance(collectRewards.DelegatorAddress, totalRewards)
// Add log if everything is good
st.state.AddLog(&types.Log{
Address: collectRewards.DelegatorAddress,
Topics: []common.Hash{staking2.CollectRewardsTopic},
Data: totalRewards.Bytes(),
BlockNumber: st.evm.BlockNumber.Uint64(),
})
return totalRewards, nil
}

@ -836,7 +836,7 @@ func (pool *TxPool) validateStakingTx(tx *staking.StakingTransaction) error {
if shard.Schedule.IsLastBlock(pool.chain.CurrentBlock().Number().Uint64()) {
pendingEpoch = new(big.Int).Add(pendingEpoch, big.NewInt(1))
}
_, _, err = VerifyAndDelegateFromMsg(
_, _, _, err = VerifyAndDelegateFromMsg(
pool.currentState, pendingEpoch, stkMsg, delegations, pool.chainconfig.IsRedelegation(pendingEpoch))
return err
case staking.DirectiveUndelegate:

@ -8,6 +8,7 @@ const (
isValidatorKeyStr = "Harmony/IsValidator/Key/v1"
isValidatorStr = "Harmony/IsValidator/Value/v1"
collectRewardsStr = "Harmony/CollectRewards"
delegateStr = "Harmony/Delegate"
)
// keys used to retrieve staking related informatio
@ -15,4 +16,5 @@ var (
IsValidatorKey = crypto.Keccak256Hash([]byte(isValidatorKeyStr))
IsValidator = crypto.Keccak256Hash([]byte(isValidatorStr))
CollectRewardsTopic = crypto.Keccak256Hash([]byte(collectRewardsStr))
DelegateTopic = crypto.Keccak256Hash([]byte(delegateStr))
)

Loading…
Cancel
Save