Skip to content

Commit

Permalink
[staking] enable CandidateTransferOwnership at CandidateIdentifiedByO…
Browse files Browse the repository at this point in the history
…wner feature (#4275)
  • Loading branch information
envestcc authored Jun 4, 2024
1 parent cbf0080 commit b11e562
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 2 deletions.
2 changes: 2 additions & 0 deletions action/protocol/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ type (
RefactorFreshAccountConversion bool
SuicideTxLogMismatchPanic bool
PanicUnrecoverableError bool
CandidateIdentifiedByOwner bool
}

// FeatureWithHeightCtx provides feature check functions.
Expand Down Expand Up @@ -267,6 +268,7 @@ func WithFeatureCtx(ctx context.Context) context.Context {
RefactorFreshAccountConversion: g.IsTsunami(height),
SuicideTxLogMismatchPanic: g.IsToBeEnabled(height),
PanicUnrecoverableError: g.IsToBeEnabled(height),
CandidateIdentifiedByOwner: !g.IsToBeEnabled(height),
},
)
}
Expand Down
2 changes: 1 addition & 1 deletion action/protocol/staking/handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ func (p *Protocol) handleCandidateRegister(ctx context.Context, act *action.Cand
failureStatus: iotextypes.ReceiptStatus_ErrCandidateAlreadyExist,
}
}
// TODO: should be hard-fork
// cannot collide with existing identifier
c = csm.GetByIdentifier(owner)
if c != nil {
return log, nil, &handleError{
Expand Down
4 changes: 4 additions & 0 deletions action/protocol/staking/protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,8 @@ func (p *Protocol) handle(ctx context.Context, act action.Action, csm CandidateS
rLog, tLogs, err = p.handleCandidateActivate(ctx, act, csm)
case *action.CandidateEndorsement:
rLog, tLogs, err = p.handleCandidateEndorsement(ctx, act, csm)
case *action.CandidateTransferOwnership:
rLog, tLogs, err = p.handleCandidateTransferOwnership(ctx, act, csm)
default:
return nil, nil
}
Expand Down Expand Up @@ -473,6 +475,8 @@ func (p *Protocol) Validate(ctx context.Context, act action.Action, sr protocol.
return p.validateCandidateActivate(ctx, act)
case *action.CandidateEndorsement:
return p.validateCandidateEndorsement(ctx, act)
case *action.CandidateTransferOwnership:
return p.validateCandidateTransferOwnershipAction(ctx, act)
}
return nil
}
Expand Down
8 changes: 8 additions & 0 deletions action/protocol/staking/validations.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,11 @@ func (p *Protocol) validateCandidateActivate(ctx context.Context, act *action.Ca
}
return nil
}

func (p *Protocol) validateCandidateTransferOwnershipAction(ctx context.Context, act *action.CandidateTransferOwnership) error {
// TODO: remove this check after candidate transfer ownership is enabled
if protocol.MustGetFeatureCtx(ctx).CandidateIdentifiedByOwner {
return errors.Wrap(action.ErrInvalidAct, "candidate transfer ownership is disabled")
}
return nil
}
25 changes: 25 additions & 0 deletions action/signedaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,3 +317,28 @@ func SignedRestake(
}
return selp, nil
}

// SignedCandidateTransferOwnership returns a signed candidate transfer ownership
func SignedCandidateTransferOwnership(
nonce uint64,
ownerAddrStr string,
payload []byte,
gasLimit uint64,
gasPrice *big.Int,
senderPriKey crypto.PrivateKey,
) (*SealedEnvelope, error) {
cto, err := NewCandidateTransferOwnership(nonce, gasLimit, gasPrice, ownerAddrStr, payload)
if err != nil {
return nil, err
}
bd := &EnvelopeBuilder{}
elp := bd.SetNonce(nonce).
SetGasPrice(gasPrice).
SetGasLimit(gasLimit).
SetAction(cto).Build()
selp, err := Sign(elp, senderPriKey)
if err != nil {
return nil, errors.Wrapf(err, "failed to sign candidate transfer ownership %v", elp)
}
return selp, nil
}
14 changes: 14 additions & 0 deletions action/signedaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,3 +201,17 @@ func TestSignedRestake(t *testing.T) {
require.Equal([]byte{}, exec.payload)
require.NotNil(selp.Signature())
}

func TestSignedCandidateTransferOwnership(t *testing.T) {
require := require.New(t)
selp, err := SignedCandidateTransferOwnership(1, _cand1Addr, []byte{}, _gasLimit, _gasPrice, _cand1PriKey)
require.NoError(err)

exec := selp.Action().(*CandidateTransferOwnership)
require.Equal(uint64(1), exec.Nonce())
require.Equal(_cand1Addr, exec.newOwner.String())
require.Equal(_gasLimit, exec.GasLimit())
require.Equal(_gasPrice, exec.GasPrice())
require.Equal([]byte{}, exec.payload)
require.NotNil(selp.Signature())
}
57 changes: 56 additions & 1 deletion e2etest/native_staking_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package e2etest

import (
"context"
"encoding/hex"
"math/big"
"testing"
"time"
Expand Down Expand Up @@ -454,6 +455,59 @@ func TestNativeStaking(t *testing.T) {
require.NoError(err)
require.Equal(4, len(cands))
})
t.Run("candidate transfer ownership to self", func(t *testing.T) {
_, ccto, err := addOneTx(action.SignedCandidateTransferOwnership(5, cand1Addr.String(), nil, gasLimit, gasPrice, cand1PriKey))
require.NoError(err)
require.EqualValues(iotextypes.ReceiptStatus_ErrUnauthorizedOperator, ccto.Status)
require.NoError(checkCandidateState(sf, candidate1Name, cand1Addr.String(), selfStake, cand1Votes, cand1Addr))
})

t.Run("candidate transfer ownership to a normal new address", func(t *testing.T) {
newOwner1 := identityset.Address(33)
_, ccto, err := addOneTx(action.SignedCandidateTransferOwnership(6, newOwner1.String(), nil, gasLimit, gasPrice, cand1PriKey))
require.NoError(err)
require.EqualValues(iotextypes.ReceiptStatus_Success, ccto.Status)
require.NoError(checkCandidateState(sf, candidate1Name, newOwner1.String(), selfStake, cand1Votes, cand1Addr))
})
t.Run("candidate transfer ownership to a exist candidate", func(t *testing.T) {
_, ccto, err := addOneTx(action.SignedCandidateTransferOwnership(7, cand2Addr.String(), nil, gasLimit, gasPrice, cand1PriKey))
require.NoError(err)
require.EqualValues(iotextypes.ReceiptStatus_ErrUnauthorizedOperator, ccto.Status)
require.NoError(checkCandidateState(sf, candidate1Name, identityset.Address(33).String(), selfStake, cand1Votes, cand1Addr))
})
t.Run("candidate transfer ownership to a normal new address again", func(t *testing.T) {
newOwner2 := identityset.Address(34)
_, ccto, err := addOneTx(action.SignedCandidateTransferOwnership(8, newOwner2.String(), nil, gasLimit, gasPrice, cand1PriKey))
require.NoError(err)
require.EqualValues(iotextypes.ReceiptStatus_Success, ccto.Status)
require.NoError(checkCandidateState(sf, candidate1Name, newOwner2.String(), selfStake, cand1Votes, cand1Addr))
})
t.Run("candidate transfer ownership to a transfered candidate", func(t *testing.T) {
newOwner2 := identityset.Address(34)
_, ccto, err := addOneTx(action.SignedCandidateTransferOwnership(9, newOwner2.String(), nil, gasLimit, gasPrice, cand1PriKey))
require.NoError(err)
require.EqualValues(iotextypes.ReceiptStatus_ErrUnauthorizedOperator, ccto.Status)
require.NoError(checkCandidateState(sf, candidate1Name, newOwner2.String(), selfStake, cand1Votes, cand1Addr))
})
t.Run("candidate transfer ownership to a contract address", func(t *testing.T) {
data, _ := hex.DecodeString("608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582002faabbefbbda99b20217cf33cb8ab8100caf1542bf1f48117d72e2c59139aea0029")
_, se, err := addOneTx(action.SignedExecution(action.EmptyAddress, cand1PriKey, 10, big.NewInt(0), uint64(100000), big.NewInt(0), data))
require.NoError(err)
require.EqualValues(iotextypes.ReceiptStatus_Success, se.Status)
_, ccto, err := addOneTx(action.SignedCandidateTransferOwnership(11, se.ContractAddress, nil, gasLimit, gasPrice, cand1PriKey))
require.NoError(err)
require.EqualValues(iotextypes.ReceiptStatus_ErrUnauthorizedOperator, ccto.Status)
require.NoError(checkCandidateState(sf, candidate1Name, identityset.Address(34).String(), selfStake, cand1Votes, cand1Addr))
})
t.Run("candidate transfer ownership to a invalid address", func(t *testing.T) {
_, _, err := addOneTx(action.SignedCandidateTransferOwnership(12, "123", nil, gasLimit, gasPrice, cand1PriKey))
require.ErrorContains(err, action.ErrAddress.Error())
})
t.Run("candidate transfer ownership with none candidate", func(t *testing.T) {
newOwner := identityset.Address(34)
_, _, err := addOneTx(action.SignedCandidateTransferOwnership(12, newOwner.String(), nil, gasLimit, gasPrice, identityset.PrivateKey(12)))
require.ErrorContains(err, "failed to find receipt")
})
}

cfg := config.Default
Expand Down Expand Up @@ -489,8 +543,9 @@ func TestNativeStaking(t *testing.T) {
cfg.Chain.EnableAsyncIndexWrite = false
cfg.Genesis.BootstrapCandidates = testInitCands
cfg.Genesis.FbkMigrationBlockHeight = 1
cfg.Genesis.TsunamiBlockHeight = 0
cfg.Genesis.TsunamiBlockHeight = 2
cfg.Genesis.EndorsementWithdrawWaitingBlocks = 10
cfg.Genesis.ToBeEnabledBlockHeight = 3 // enable CandidateIdentifiedByOwner feature

t.Run("test native staking", func(t *testing.T) {
testNativeStaking(cfg, t)
Expand Down

0 comments on commit b11e562

Please sign in to comment.