From 2119f233ea4c892fdd00c78bf1c1f0333a8bafae Mon Sep 17 00:00:00 2001
From: Acha Bill <57879913+acha-bill@users.noreply.github.com>
Date: Thu, 16 Jul 2020 09:33:25 +0100
Subject: [PATCH] validate max transaction inputs count (#620)

* validate max transaction inputs count

* add tests for tx.InputsCountValid

* fix linting
---
 .../valuetransfers/packages/tangle/errors.go  |  2 ++
 .../valuetransfers/packages/tangle/tangle.go  |  5 ++++
 .../packages/transaction/transaction.go       | 10 ++++++++
 .../packages/transaction/transaction_test.go  | 25 +++++++++++++++++++
 4 files changed, 42 insertions(+)

diff --git a/dapps/valuetransfers/packages/tangle/errors.go b/dapps/valuetransfers/packages/tangle/errors.go
index 124ee4c6..901bb744 100644
--- a/dapps/valuetransfers/packages/tangle/errors.go
+++ b/dapps/valuetransfers/packages/tangle/errors.go
@@ -19,4 +19,6 @@ var (
 	ErrTransactionDoesNotSpendAllFunds = errors.New("transaction does not spend all funds from inputs")
 	// ErrInvalidTransactionSignature is returned if the signature of a transaction is invalid.
 	ErrInvalidTransactionSignature = errors.New("missing or invalid transaction signature")
+	// ErrMaxTransactionInputCountExceeded is returned if the max number of inputs of the transaction is exceeded.
+	ErrMaxTransactionInputCountExceeded = errors.New("maximum transaction input count exceeded")
 )
diff --git a/dapps/valuetransfers/packages/tangle/tangle.go b/dapps/valuetransfers/packages/tangle/tangle.go
index 8a2a9386..bd262f57 100644
--- a/dapps/valuetransfers/packages/tangle/tangle.go
+++ b/dapps/valuetransfers/packages/tangle/tangle.go
@@ -1593,6 +1593,11 @@ func (tangle *Tangle) ValidateTransactionToAttach(tx *transaction.Transaction) (
 		return
 	}
 
+	if !tx.InputsCountValid() {
+		err = ErrMaxTransactionInputCountExceeded
+		return
+	}
+
 	if !tx.SignaturesValid() {
 		err = ErrInvalidTransactionSignature
 		return
diff --git a/dapps/valuetransfers/packages/transaction/transaction.go b/dapps/valuetransfers/packages/transaction/transaction.go
index 760ded1d..928827a1 100644
--- a/dapps/valuetransfers/packages/transaction/transaction.go
+++ b/dapps/valuetransfers/packages/transaction/transaction.go
@@ -20,6 +20,11 @@ var (
 	ErrMaxDataPayloadSizeExceeded = errors.New("maximum data payload size exceeded")
 )
 
+const (
+	// MaxTransactionInputCount is the maximum number of inputs a transaction can have
+	MaxTransactionInputCount = 100
+)
+
 // region IMPLEMENT Transaction ////////////////////////////////////////////////////////////////////////////////////////////
 
 // Transaction represents a value transfer for IOTA. It consists out of a number of inputs, a number of outputs and their
@@ -172,6 +177,11 @@ func (transaction *Transaction) SignaturesValid() bool {
 	return signaturesValid
 }
 
+// InputsCountValid returns true if the number of inputs in this transaction is not greater than MaxTransactionInputCount.
+func (transaction *Transaction) InputsCountValid() bool {
+	return transaction.inputs.Size() <= MaxTransactionInputCount
+}
+
 // EssenceBytes return the bytes of the transaction excluding the Signatures. These bytes are later signed and used to
 // generate the Signatures.
 func (transaction *Transaction) EssenceBytes() []byte {
diff --git a/dapps/valuetransfers/packages/transaction/transaction_test.go b/dapps/valuetransfers/packages/transaction/transaction_test.go
index d2600171..164beb5e 100644
--- a/dapps/valuetransfers/packages/transaction/transaction_test.go
+++ b/dapps/valuetransfers/packages/transaction/transaction_test.go
@@ -204,3 +204,28 @@ func TestPutSignatureInvalid(t *testing.T) {
 	// valid signatures expected
 	assert.Equal(t, true, tx.SignaturesValid())
 }
+
+func TestInputCounts(t *testing.T) {
+	tx1 := createTransaction(MaxTransactionInputCount + 1, 1)
+	assert.False(t, tx1.InputsCountValid())
+
+	tx2 := createTransaction(MaxTransactionInputCount - 1, 1)
+	assert.True(t, tx2.InputsCountValid())
+}
+
+func createTransaction(inputCount int, outputCount int) *Transaction {
+	outputIds := make([]OutputID, 0)
+	for i := 0; i < inputCount; i++ {
+		outputIds = append(outputIds, NewOutputID(address.Random(), RandomID()))
+	}
+	inputs := NewInputs(outputIds...)
+
+	bal := balance.New(balance.ColorIOTA, 1)
+	outputMap := make(map[address.Address][]*balance.Balance)
+	for i := 0; i < outputCount; i++ {
+		outputMap[address.Random()] = []*balance.Balance{bal}
+	}
+	outputs := NewOutputs(outputMap)
+
+	return New(inputs, outputs)
+}
\ No newline at end of file
-- 
GitLab