mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00
[NOD-1495] Disallow non native transactions (#988)
* [NOD-1495] Disallow non native transactions * [NOD-1495] Use deserializeUTXOSetBytes * [NOD-1495] Delete checkNoNonNativeTransactions * [NOD-1495] Invert condition in checkTransactionPayload Co-authored-by: Mike Zak <feanorr@gmail.com>
This commit is contained in:
parent
e7a61c7edf
commit
32da4440ba
@ -91,7 +91,13 @@ func (ps *pruningStore) PruningPointSerializedUTXOSet(dbContext model.DBReader)
|
||||
if ps.serializedUTXOSetStaging != nil {
|
||||
return ps.serializedUTXOSetStaging, nil
|
||||
}
|
||||
return dbContext.Get(pruningSerializedUTXOSetkey)
|
||||
|
||||
dbPruningPointUTXOSetBytes, err := dbContext.Get(pruningSerializedUTXOSetkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ps.deserializeUTXOSetBytes(dbPruningPointUTXOSetBytes)
|
||||
}
|
||||
|
||||
func (ps *pruningStore) serializePruningPoint(pruningPoint *externalapi.DomainHash) ([]byte, error) {
|
||||
|
@ -96,6 +96,7 @@ func (f *factory) NewConsensus(dagParams *dagconfig.Params, db infrastructuredat
|
||||
dagTraversalManager,
|
||||
blockHeaderStore)
|
||||
transactionValidator := transactionvalidator.New(dagParams.BlockCoinbaseMaturity,
|
||||
dagParams.EnableNonNativeSubnetworks,
|
||||
dbManager,
|
||||
pastMedianTimeManager,
|
||||
ghostdagDataStore)
|
||||
|
@ -46,6 +46,11 @@ func (v *blockValidator) ValidateBodyInIsolation(blockHash *externalapi.DomainHa
|
||||
return err
|
||||
}
|
||||
|
||||
err = v.checkBlockTransactionOrder(block)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = v.checkTransactionsInIsolation(block)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -122,19 +127,6 @@ func (v *blockValidator) checkBlockTransactionOrder(block *externalapi.DomainBlo
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *blockValidator) checkNoNonNativeTransactions(block *externalapi.DomainBlock) error {
|
||||
// Disallow non-native/coinbase subnetworks in networks that don't allow them
|
||||
if !v.enableNonNativeSubnetworks {
|
||||
for _, tx := range block.Transactions {
|
||||
if !(tx.SubnetworkID == subnetworks.SubnetworkIDNative ||
|
||||
tx.SubnetworkID == subnetworks.SubnetworkIDCoinbase) {
|
||||
return errors.Wrapf(ruleerrors.ErrInvalidSubnetwork, "non-native/coinbase subnetworks are not allowed")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *blockValidator) checkTransactionsInIsolation(block *externalapi.DomainBlock) error {
|
||||
for _, tx := range block.Transactions {
|
||||
err := v.transactionValidator.ValidateTransactionInIsolation(tx)
|
||||
|
@ -4,21 +4,6 @@ import (
|
||||
"github.com/kaspanet/kaspad/domain/consensus/model/externalapi"
|
||||
)
|
||||
|
||||
// futureCoveringTreeNodeSet represents a collection of blocks in the future of
|
||||
// a certain block. Once a block B is added to the DAG, every block A_i in
|
||||
// B's selected parent anticone must register B in its futureCoveringTreeNodeSet. This allows
|
||||
// to relatively quickly (O(log(|futureCoveringTreeNodeSet|))) query whether B
|
||||
// is a descendent (is in the "future") of any block that previously
|
||||
// registered it.
|
||||
//
|
||||
// Note that futureCoveringTreeNodeSet is meant to be queried only if B is not
|
||||
// a reachability tree descendant of the block in question, as reachability
|
||||
// tree queries are always O(1).
|
||||
//
|
||||
// See insertNode, hasAncestorOf, and isInPast for further
|
||||
// details.
|
||||
type futureCoveringTreeNodeSet orderedTreeNodeSet
|
||||
|
||||
// insertToFutureCoveringSet inserts the given block into this node's FutureCoveringSet
|
||||
// while keeping it ordered by interval.
|
||||
// If a block B ∈ node.FutureCoveringSet exists such that its interval
|
||||
@ -116,17 +101,3 @@ func (rt *reachabilityManager) futureCoveringSetHasAncestorOf(this, other *exter
|
||||
candidate := futureCoveringSet[ancestorIndex]
|
||||
return rt.IsReachabilityTreeAncestorOf(candidate, other)
|
||||
}
|
||||
|
||||
// futureCoveringSetString returns a string representation of the intervals in this futureCoveringSet.
|
||||
func (rt *reachabilityManager) futureCoveringSetString(futureCoveringSet []*externalapi.DomainHash) (string, error) {
|
||||
intervalsString := ""
|
||||
for _, node := range futureCoveringSet {
|
||||
nodeInterval, err := rt.interval(node)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
intervalsString += intervalString(nodeInterval)
|
||||
}
|
||||
return intervalsString, nil
|
||||
}
|
||||
|
@ -39,6 +39,12 @@ func (v *transactionValidator) ValidateTransactionInIsolation(tx *externalapi.Do
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = v.checkTransactionPayload(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = v.checkNativeTransactionPayload(tx)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -165,7 +171,14 @@ func (v *transactionValidator) checkNativeTransactionPayload(tx *externalapi.Dom
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *transactionValidator) checkTransactionSubnetwork(tx *externalapi.DomainTransaction, subnetworkID *externalapi.DomainSubnetworkID) error {
|
||||
func (v *transactionValidator) checkTransactionSubnetwork(tx *externalapi.DomainTransaction,
|
||||
subnetworkID *externalapi.DomainSubnetworkID) error {
|
||||
if !v.enableNonNativeSubnetworks && tx.SubnetworkID != subnetworks.SubnetworkIDNative &&
|
||||
tx.SubnetworkID != subnetworks.SubnetworkIDCoinbase {
|
||||
return errors.Wrapf(ruleerrors.ErrSubnetworksDisabled, "transaction has non native or coinbase "+
|
||||
"subnetwork ID")
|
||||
}
|
||||
|
||||
// If we are a partial node, only transactions on built in subnetworks
|
||||
// or our own subnetwork may have a payload
|
||||
isLocalNodeFull := subnetworkID == nil
|
||||
@ -179,7 +192,7 @@ func (v *transactionValidator) checkTransactionSubnetwork(tx *externalapi.Domain
|
||||
}
|
||||
|
||||
func (v *transactionValidator) checkTransactionPayload(tx *externalapi.DomainTransaction) error {
|
||||
if tx.Payload != nil {
|
||||
if tx.Payload == nil {
|
||||
return errors.Wrapf(ruleerrors.ErrInvalidPayload, "nil payload is not allowed")
|
||||
}
|
||||
|
||||
|
@ -7,20 +7,24 @@ import (
|
||||
// transactionValidator exposes a set of validation classes, after which
|
||||
// it's possible to determine whether either a transaction is valid
|
||||
type transactionValidator struct {
|
||||
blockCoinbaseMaturity uint64
|
||||
databaseContext model.DBReader
|
||||
pastMedianTimeManager model.PastMedianTimeManager
|
||||
ghostdagDataStore model.GHOSTDAGDataStore
|
||||
blockCoinbaseMaturity uint64
|
||||
databaseContext model.DBReader
|
||||
pastMedianTimeManager model.PastMedianTimeManager
|
||||
ghostdagDataStore model.GHOSTDAGDataStore
|
||||
enableNonNativeSubnetworks bool
|
||||
}
|
||||
|
||||
// New instantiates a new TransactionValidator
|
||||
func New(blockCoinbaseMaturity uint64,
|
||||
enableNonNativeSubnetworks bool,
|
||||
databaseContext model.DBReader,
|
||||
pastMedianTimeManager model.PastMedianTimeManager,
|
||||
ghostdagDataStore model.GHOSTDAGDataStore) model.TransactionValidator {
|
||||
return &transactionValidator{blockCoinbaseMaturity: blockCoinbaseMaturity,
|
||||
databaseContext: databaseContext,
|
||||
pastMedianTimeManager: pastMedianTimeManager,
|
||||
ghostdagDataStore: ghostdagDataStore,
|
||||
return &transactionValidator{
|
||||
blockCoinbaseMaturity: blockCoinbaseMaturity,
|
||||
enableNonNativeSubnetworks: enableNonNativeSubnetworks,
|
||||
databaseContext: databaseContext,
|
||||
pastMedianTimeManager: pastMedianTimeManager,
|
||||
ghostdagDataStore: ghostdagDataStore,
|
||||
}
|
||||
}
|
||||
|
@ -228,6 +228,7 @@ var (
|
||||
|
||||
ErrKnownInvalid = newRuleError("ErrKnownInvalid")
|
||||
|
||||
ErrSubnetworksDisabled = newRuleError("ErrSubnetworksDisabled")
|
||||
ErrBadPruningPointUTXOSet = newRuleError("ErrBadPruningPointUTXOSet")
|
||||
|
||||
ErrMissingBlockHeaderInIBD = newRuleError("ErrMissingBlockHeaderInIBD")
|
||||
|
@ -13,10 +13,6 @@ var (
|
||||
// littleEndian is a convenience variable since binary.LittleEndian is
|
||||
// quite long.
|
||||
littleEndian = binary.LittleEndian
|
||||
|
||||
// bigEndian is a convenience variable since binary.BigEndian is quite
|
||||
// long.
|
||||
bigEndian = binary.BigEndian
|
||||
)
|
||||
|
||||
// errNoEncodingForType signifies that there's no encoding for the given type.
|
||||
|
Loading…
x
Reference in New Issue
Block a user