mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-10-14 00:59:33 +00:00
[NOD-1560] Add TestValidateTransactionInIsolation (#1140)
* [NOD-1560] Add TestValidateTransactionInIsolation * [NOD-1560] Make ForAllNets copy the params before mutating them * [NOD-1560] Remove redundant continue * [NOD-1560] Don't change finality duration
This commit is contained in:
parent
c1505b4748
commit
bb2d7f72ac
@ -0,0 +1,162 @@
|
|||||||
|
package transactionvalidator_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/ruleerrors"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/constants"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/testutils"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/transactionhelper"
|
||||||
|
"github.com/kaspanet/kaspad/domain/dagconfig"
|
||||||
|
"github.com/kaspanet/kaspad/util"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type txSubnetworkData struct {
|
||||||
|
subnetworkID externalapi.DomainSubnetworkID
|
||||||
|
gas uint64
|
||||||
|
payload []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateTransactionInIsolation(t *testing.T) {
|
||||||
|
testutils.ForAllNets(t, true, func(t *testing.T, params *dagconfig.Params) {
|
||||||
|
factory := consensus.NewFactory()
|
||||||
|
tc, teardown, err := factory.NewTestConsensus(params, "TestValidateTransactionInIsolation")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error setting up consensus: %+v", err)
|
||||||
|
}
|
||||||
|
defer teardown()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
numInputs uint32
|
||||||
|
numOutputs uint32
|
||||||
|
outputValue uint64
|
||||||
|
nodeSubnetworkID externalapi.DomainSubnetworkID
|
||||||
|
txSubnetworkData *txSubnetworkData
|
||||||
|
extraModificationsFunc func(*externalapi.DomainTransaction)
|
||||||
|
expectedErr error
|
||||||
|
}{
|
||||||
|
{"good one", 1, 1, 1, subnetworks.SubnetworkIDNative, nil, nil, nil},
|
||||||
|
{"no inputs", 0, 1, 1, subnetworks.SubnetworkIDNative, nil, nil, ruleerrors.ErrNoTxInputs},
|
||||||
|
{"no outputs", 1, 0, 1, subnetworks.SubnetworkIDNative, nil, nil, nil},
|
||||||
|
{"too much sompi in one output", 1, 1, util.MaxSompi + 1,
|
||||||
|
subnetworks.SubnetworkIDNative,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
ruleerrors.ErrBadTxOutValue},
|
||||||
|
{"too much sompi in total outputs", 1, 2, util.MaxSompi - 1,
|
||||||
|
subnetworks.SubnetworkIDNative,
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
ruleerrors.ErrBadTxOutValue},
|
||||||
|
{"duplicate inputs", 2, 1, 1,
|
||||||
|
subnetworks.SubnetworkIDNative,
|
||||||
|
nil,
|
||||||
|
func(tx *externalapi.DomainTransaction) { tx.Inputs[1].PreviousOutpoint.Index = 0 },
|
||||||
|
ruleerrors.ErrDuplicateTxInputs},
|
||||||
|
{"1 input coinbase",
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
subnetworks.SubnetworkIDNative,
|
||||||
|
&txSubnetworkData{subnetworks.SubnetworkIDCoinbase, 0, nil},
|
||||||
|
nil,
|
||||||
|
nil},
|
||||||
|
{"no inputs coinbase",
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
subnetworks.SubnetworkIDNative,
|
||||||
|
&txSubnetworkData{subnetworks.SubnetworkIDCoinbase, 0, nil},
|
||||||
|
nil,
|
||||||
|
nil},
|
||||||
|
{"too long payload coinbase",
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
subnetworks.SubnetworkIDNative,
|
||||||
|
&txSubnetworkData{subnetworks.SubnetworkIDCoinbase, 0, make([]byte, constants.MaxCoinbasePayloadLength+1)},
|
||||||
|
nil,
|
||||||
|
ruleerrors.ErrBadCoinbasePayloadLen},
|
||||||
|
{"non-zero gas in Kaspa", 1, 1, 0,
|
||||||
|
subnetworks.SubnetworkIDNative,
|
||||||
|
nil,
|
||||||
|
func(tx *externalapi.DomainTransaction) {
|
||||||
|
tx.Gas = 1
|
||||||
|
},
|
||||||
|
ruleerrors.ErrInvalidGas},
|
||||||
|
{"non-zero gas in subnetwork registry", 1, 1, 0,
|
||||||
|
subnetworks.SubnetworkIDRegistry,
|
||||||
|
&txSubnetworkData{subnetworks.SubnetworkIDRegistry, 1, []byte{}},
|
||||||
|
nil,
|
||||||
|
ruleerrors.ErrInvalidGas},
|
||||||
|
{"non-zero payload in Kaspa", 1, 1, 0,
|
||||||
|
subnetworks.SubnetworkIDNative,
|
||||||
|
nil,
|
||||||
|
func(tx *externalapi.DomainTransaction) {
|
||||||
|
tx.Payload = []byte{1}
|
||||||
|
},
|
||||||
|
ruleerrors.ErrInvalidPayload},
|
||||||
|
{"invalid payload hash", 1, 1, 0,
|
||||||
|
externalapi.DomainSubnetworkID{123},
|
||||||
|
&txSubnetworkData{externalapi.DomainSubnetworkID{123}, 0, []byte{1}},
|
||||||
|
func(tx *externalapi.DomainTransaction) {
|
||||||
|
tx.PayloadHash = externalapi.DomainHash{}
|
||||||
|
},
|
||||||
|
ruleerrors.ErrInvalidPayloadHash},
|
||||||
|
{"invalid payload hash in native subnetwork", 1, 1, 0,
|
||||||
|
subnetworks.SubnetworkIDNative,
|
||||||
|
nil,
|
||||||
|
func(tx *externalapi.DomainTransaction) {
|
||||||
|
tx.PayloadHash = *hashes.HashData(tx.Payload)
|
||||||
|
},
|
||||||
|
ruleerrors.ErrInvalidPayloadHash},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
tx := createTxForTest(test.numInputs, test.numOutputs, test.outputValue, test.txSubnetworkData)
|
||||||
|
|
||||||
|
if test.extraModificationsFunc != nil {
|
||||||
|
test.extraModificationsFunc(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := tc.TransactionValidator().ValidateTransactionInIsolation(tx)
|
||||||
|
if !errors.Is(err, test.expectedErr) {
|
||||||
|
t.Errorf("TestValidateTransactionInIsolation: '%s': unexpected error %+v", test.name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTxForTest(numInputs uint32, numOutputs uint32, outputValue uint64, subnetworkData *txSubnetworkData) *externalapi.DomainTransaction {
|
||||||
|
txIns := []*externalapi.DomainTransactionInput{}
|
||||||
|
txOuts := []*externalapi.DomainTransactionOutput{}
|
||||||
|
|
||||||
|
for i := uint32(0); i < numInputs; i++ {
|
||||||
|
txIns = append(txIns, &externalapi.DomainTransactionInput{
|
||||||
|
PreviousOutpoint: externalapi.DomainOutpoint{
|
||||||
|
TransactionID: externalapi.DomainTransactionID{},
|
||||||
|
Index: i,
|
||||||
|
},
|
||||||
|
SignatureScript: []byte{},
|
||||||
|
Sequence: constants.MaxTxInSequenceNum,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := uint32(0); i < numOutputs; i++ {
|
||||||
|
txOuts = append(txOuts, &externalapi.DomainTransactionOutput{
|
||||||
|
ScriptPublicKey: []byte{},
|
||||||
|
Value: outputValue,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if subnetworkData != nil {
|
||||||
|
return transactionhelper.NewSubnetworkTransaction(constants.TransactionVersion, txIns, txOuts, &subnetworkData.subnetworkID, subnetworkData.gas, subnetworkData.payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
return transactionhelper.NewNativeTransaction(constants.TransactionVersion, txIns, txOuts)
|
||||||
|
}
|
@ -17,8 +17,9 @@ func ForAllNets(t *testing.T, skipPow bool, testFunc func(*testing.T, *dagconfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, params := range allParams {
|
for _, params := range allParams {
|
||||||
params.SkipProofOfWork = skipPow
|
paramsCopy := params
|
||||||
|
paramsCopy.SkipProofOfWork = skipPow
|
||||||
t.Logf("Running test for %s", params.Name)
|
t.Logf("Running test for %s", params.Name)
|
||||||
testFunc(t, ¶ms)
|
testFunc(t, ¶msCopy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package transactionhelper
|
|||||||
import (
|
import (
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||||
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
"github.com/kaspanet/kaspad/domain/consensus/utils/hashes"
|
||||||
|
"github.com/kaspanet/kaspad/domain/consensus/utils/subnetworks"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewSubnetworkTransaction returns a new trsnactions in the specified subnetwork with specified gas and payload
|
// NewSubnetworkTransaction returns a new trsnactions in the specified subnetwork with specified gas and payload
|
||||||
@ -24,3 +25,19 @@ func NewSubnetworkTransaction(version int32, inputs []*externalapi.DomainTransac
|
|||||||
Mass: 0,
|
Mass: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewNativeTransaction returns a new native transaction
|
||||||
|
func NewNativeTransaction(version int32, inputs []*externalapi.DomainTransactionInput,
|
||||||
|
outputs []*externalapi.DomainTransactionOutput) *externalapi.DomainTransaction {
|
||||||
|
return &externalapi.DomainTransaction{
|
||||||
|
Version: version,
|
||||||
|
Inputs: inputs,
|
||||||
|
Outputs: outputs,
|
||||||
|
LockTime: 0,
|
||||||
|
SubnetworkID: subnetworks.SubnetworkIDNative,
|
||||||
|
Gas: 0,
|
||||||
|
Payload: []byte{},
|
||||||
|
Fee: 0,
|
||||||
|
Mass: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user