mirror of https://github.com/poanetwork/gecko.git
380 lines
11 KiB
Go
380 lines
11 KiB
Go
|
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||
|
// See the file LICENSE for licensing terms.
|
||
|
|
||
|
package platformvm
|
||
|
|
||
|
import (
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
"github.com/ava-labs/gecko/ids"
|
||
|
"github.com/ava-labs/gecko/utils/crypto"
|
||
|
)
|
||
|
|
||
|
func TestAddDefaultSubnetDelegatorTxSyntacticVerify(t *testing.T) {
|
||
|
vm := defaultVM()
|
||
|
|
||
|
// Case 1: tx is nil
|
||
|
var tx *addDefaultSubnetDelegatorTx
|
||
|
if err := tx.SyntacticVerify(); err == nil {
|
||
|
t.Fatal("should have errored because tx is nil")
|
||
|
}
|
||
|
|
||
|
// Case 2: Tx ID is nil
|
||
|
tx, err := vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
defaultStakeAmount,
|
||
|
uint64(defaultValidateStartTime.Unix()),
|
||
|
uint64(defaultValidateEndTime.Unix()),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
tx.id = ids.ID{}
|
||
|
if err := tx.SyntacticVerify(); err == nil {
|
||
|
t.Fatal("should have errored because ID is nil")
|
||
|
}
|
||
|
|
||
|
// Case 3: Wrong network ID
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
defaultStakeAmount,
|
||
|
uint64(defaultValidateStartTime.Unix()),
|
||
|
uint64(defaultValidateEndTime.Unix()),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID+1,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if err := tx.SyntacticVerify(); err == nil {
|
||
|
t.Fatal("should have errored because the wrong network ID was used")
|
||
|
}
|
||
|
|
||
|
// Case 4: Missing Node ID
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
defaultStakeAmount,
|
||
|
uint64(defaultValidateStartTime.Unix()),
|
||
|
uint64(defaultValidateEndTime.Unix()),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
tx.NodeID = ids.ShortID{}
|
||
|
if err := tx.SyntacticVerify(); err == nil {
|
||
|
t.Fatal("should have errored because NodeID is nil")
|
||
|
}
|
||
|
|
||
|
// Case 5: Not enough weight
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
MinimumStakeAmount-1,
|
||
|
uint64(defaultValidateStartTime.Unix()),
|
||
|
uint64(defaultValidateEndTime.Unix()),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if err := tx.SyntacticVerify(); err == nil {
|
||
|
t.Fatal("should have errored because of not enough weight")
|
||
|
}
|
||
|
|
||
|
// Case 6: Validation length is too short
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
defaultStakeAmount,
|
||
|
uint64(defaultValidateStartTime.Unix()),
|
||
|
uint64(defaultValidateStartTime.Add(MinimumStakingDuration).Unix())-1,
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
err = tx.SyntacticVerify()
|
||
|
if err == nil {
|
||
|
t.Fatal("should have errored because validation length too short")
|
||
|
}
|
||
|
|
||
|
// Case 7: Validation length is too long
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
defaultStakeAmount,
|
||
|
uint64(defaultValidateStartTime.Unix()),
|
||
|
uint64(defaultValidateStartTime.Add(MaximumStakingDuration).Unix())+1,
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
err = tx.SyntacticVerify()
|
||
|
if err == nil {
|
||
|
t.Fatal("should have errored because validation length too long")
|
||
|
}
|
||
|
|
||
|
// Case 8: Valid
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
defaultStakeAmount,
|
||
|
uint64(defaultValidateStartTime.Unix()),
|
||
|
uint64(defaultValidateEndTime.Unix()),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if err := tx.SyntacticVerify(); err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestAddDefaultSubnetDelegatorTxSemanticVerify(t *testing.T) {
|
||
|
vm := defaultVM()
|
||
|
|
||
|
// Case 1: Proposed validator currently validating default subnet
|
||
|
// but stops validating non-default subnet after stops validating default subnet
|
||
|
// (note that defaultKey is a genesis validator)
|
||
|
tx, err := vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
defaultStakeAmount,
|
||
|
uint64(defaultValidateStartTime.Unix()),
|
||
|
uint64(defaultValidateEndTime.Unix())+1,
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
_, _, _, _, err = tx.SemanticVerify(vm.DB)
|
||
|
if err == nil {
|
||
|
t.Fatal("should have failed because validator stops validating default subnet earlier than non-default subnet")
|
||
|
}
|
||
|
|
||
|
// Case 2: Proposed validator currently validating default subnet
|
||
|
// and proposed non-default subnet validation period is subset of
|
||
|
// default subnet validation period
|
||
|
// (note that defaultKey is a genesis validator)
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
defaultStakeAmount,
|
||
|
uint64(defaultValidateStartTime.Unix()),
|
||
|
uint64(defaultValidateEndTime.Unix())+1,
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
_, _, _, _, err = tx.SemanticVerify(vm.DB)
|
||
|
if err == nil {
|
||
|
t.Fatalf("should have failed because the end time is outside the default subnets end time")
|
||
|
}
|
||
|
|
||
|
// Add a validator to pending validator set of default subnet
|
||
|
key, err := vm.factory.NewPrivateKey()
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
pendingDSValidatorID := key.PublicKey().Address()
|
||
|
|
||
|
// starts validating default subnet 10 seconds after genesis
|
||
|
DSStartTime := defaultGenesisTime.Add(10 * time.Second)
|
||
|
DSEndTime := DSStartTime.Add(5 * MinimumStakingDuration)
|
||
|
|
||
|
addDSTx, err := vm.newAddDefaultSubnetValidatorTx(
|
||
|
defaultNonce+1, // nonce
|
||
|
defaultStakeAmount, // stake amount
|
||
|
uint64(DSStartTime.Unix()), // start time
|
||
|
uint64(DSEndTime.Unix()), // end time
|
||
|
pendingDSValidatorID, // node ID
|
||
|
defaultKey.PublicKey().Address(), // destination
|
||
|
NumberOfShares, // subnet
|
||
|
testNetworkID, // network
|
||
|
defaultKey, // key
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
// Case 3: Proposed validator isn't in pending or current validator sets
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
defaultStakeAmount,
|
||
|
uint64(DSStartTime.Unix()),
|
||
|
uint64(DSEndTime.Unix()),
|
||
|
pendingDSValidatorID,
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
_, _, _, _, err = tx.SemanticVerify(vm.DB)
|
||
|
if err == nil {
|
||
|
t.Fatal("should have failed because validator not in the current or pending validator sets of the default subnet")
|
||
|
}
|
||
|
|
||
|
err = vm.putPendingValidators(
|
||
|
vm.DB,
|
||
|
&EventHeap{
|
||
|
SortByStartTime: true,
|
||
|
Txs: []TimedTx{addDSTx},
|
||
|
},
|
||
|
DefaultSubnetID,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
// Node with ID key.PublicKey().Address() now a pending validator for default subnet
|
||
|
|
||
|
// Case 4: Proposed validator is pending validator of default subnet
|
||
|
// but starts validating non-default subnet before default subnet
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
defaultStakeAmount,
|
||
|
uint64(DSStartTime.Unix())-1, // start validating non-default subnet before default subnet
|
||
|
uint64(DSEndTime.Unix()),
|
||
|
pendingDSValidatorID,
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
_, _, _, _, err = tx.SemanticVerify(vm.DB)
|
||
|
if err == nil {
|
||
|
t.Fatal("should have failed because validator starts validating non-default " +
|
||
|
"subnet before starting to validate default subnet")
|
||
|
}
|
||
|
|
||
|
// Case 5: Proposed validator is pending validator of default subnet
|
||
|
// but stops validating non-default subnet after default subnet
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
defaultStakeAmount,
|
||
|
uint64(DSStartTime.Unix()),
|
||
|
uint64(DSEndTime.Unix())+1, // stop validating non-default subnet after stopping validating default subnet
|
||
|
pendingDSValidatorID,
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
_, _, _, _, err = tx.SemanticVerify(vm.DB)
|
||
|
if err == nil {
|
||
|
t.Fatal("should have failed because validator stops validating non-default " +
|
||
|
"subnet after stops validating default subnet")
|
||
|
}
|
||
|
|
||
|
// Case 6: Proposed validator is pending validator of default subnet
|
||
|
// and period validating non-default subnet is subset of time validating default subnet
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1,
|
||
|
defaultStakeAmount,
|
||
|
uint64(DSStartTime.Unix()), // same start time as for default subnet
|
||
|
uint64(DSEndTime.Unix()), // same end time as for default subnet
|
||
|
pendingDSValidatorID,
|
||
|
defaultKey.PublicKey().Address(),
|
||
|
testNetworkID,
|
||
|
defaultKey,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
_, _, _, _, err = tx.SemanticVerify(vm.DB)
|
||
|
if err != nil {
|
||
|
t.Fatalf("should have passed verification")
|
||
|
}
|
||
|
|
||
|
// Case 7: Proposed validator start validating at/before current timestamp
|
||
|
// First, advance the timestamp
|
||
|
newTimestamp := defaultGenesisTime.Add(2 * time.Second)
|
||
|
if err := vm.putTimestamp(vm.DB, newTimestamp); err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
defaultNonce+1, // nonce
|
||
|
defaultStakeAmount, // weight
|
||
|
uint64(newTimestamp.Unix()), // start time
|
||
|
uint64(newTimestamp.Add(MinimumStakingDuration).Unix()), // end time
|
||
|
defaultKey.PublicKey().Address(), // node ID
|
||
|
defaultKey.PublicKey().Address(), // destination
|
||
|
testNetworkID, // network ID
|
||
|
defaultKey, // tx fee payer
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
_, _, _, _, err = tx.SemanticVerify(vm.DB)
|
||
|
if err == nil {
|
||
|
t.Fatal("should have failed verification because starts validating at current timestamp")
|
||
|
}
|
||
|
|
||
|
// reset the timestamp
|
||
|
if err := vm.putTimestamp(vm.DB, defaultGenesisTime); err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
// Case 7: Account that pays tx fee doesn't have enough $AVA to pay tx fee
|
||
|
txFeeSaved := txFee
|
||
|
txFee = 1 // Do this so test works even when txFee is 0
|
||
|
|
||
|
// Create new key whose account has no $AVA
|
||
|
factory := crypto.FactorySECP256K1R{}
|
||
|
newAcctKey, err := factory.NewPrivateKey()
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
tx, err = vm.newAddDefaultSubnetDelegatorTx(
|
||
|
1, // nonce (new account has nonce 0 so use nonce 1)
|
||
|
defaultStakeAmount, // weight
|
||
|
uint64(defaultValidateStartTime.Unix()), // start time
|
||
|
uint64(defaultValidateEndTime.Unix()), // end time
|
||
|
defaultKey.PublicKey().Address(), // node ID
|
||
|
defaultKey.PublicKey().Address(), // destination
|
||
|
testNetworkID, // network ID
|
||
|
newAcctKey.(*crypto.PrivateKeySECP256K1R), // tx fee payer
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
_, _, _, _, err = tx.SemanticVerify(vm.DB)
|
||
|
if err == nil {
|
||
|
t.Fatal("should have failed verification because payer account has no $AVA to pay fee")
|
||
|
}
|
||
|
txFee = txFeeSaved // Reset tx fee
|
||
|
}
|