From 6799dcc3482ce9f2a6dddaf6c1cdc6510965bbe6 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Fri, 1 Mar 2013 19:48:45 +0100 Subject: [PATCH] Refuse to create transactions larger than the max standard size. --- .../com/google/bitcoin/core/Transaction.java | 8 ++++++-- .../java/com/google/bitcoin/core/Wallet.java | 8 ++++++++ .../com/google/bitcoin/core/WalletTest.java | 17 +++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/com/google/bitcoin/core/Transaction.java b/core/src/main/java/com/google/bitcoin/core/Transaction.java index f0c6135a..6d01998b 100644 --- a/core/src/main/java/com/google/bitcoin/core/Transaction.java +++ b/core/src/main/java/com/google/bitcoin/core/Transaction.java @@ -47,8 +47,12 @@ public class Transaction extends ChildMessage implements Serializable { private static final Logger log = LoggerFactory.getLogger(Transaction.class); private static final long serialVersionUID = -8567546957352643140L; - // Threshold for lockTime: below this value it is interpreted as block number, otherwise as timestamp. - static final int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC + /** Threshold for lockTime: below this value it is interpreted as block number, otherwise as timestamp. **/ + public static final int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC + + /** How many bytes a transaction can be before it won't be relayed anymore. */ + public static final int MAX_STANDARD_TX_SIZE = 100 * 1024; + // These are serialized in both bitcoin and java serialization. private long version; diff --git a/core/src/main/java/com/google/bitcoin/core/Wallet.java b/core/src/main/java/com/google/bitcoin/core/Wallet.java index 0182ed70..d8c74222 100644 --- a/core/src/main/java/com/google/bitcoin/core/Wallet.java +++ b/core/src/main/java/com/google/bitcoin/core/Wallet.java @@ -1751,6 +1751,14 @@ public class Wallet implements Serializable, BlockChainListener { throw new RuntimeException(e); } + // Check size. + int size = req.tx.bitcoinSerialize().length; + if (size > Transaction.MAX_STANDARD_TX_SIZE) { + // TODO: Throw an exception here. + log.error("Transaction could not be created without exceeding max size: {} vs {}", size, Transaction.MAX_STANDARD_TX_SIZE); + return false; + } + // Label the transaction as being self created. We can use this later to spend its change output even before // the transaction is confirmed. req.tx.getConfidence().setSource(TransactionConfidence.Source.SELF); diff --git a/core/src/test/java/com/google/bitcoin/core/WalletTest.java b/core/src/test/java/com/google/bitcoin/core/WalletTest.java index 9eba0275..08ac5e52 100644 --- a/core/src/test/java/com/google/bitcoin/core/WalletTest.java +++ b/core/src/test/java/com/google/bitcoin/core/WalletTest.java @@ -32,6 +32,7 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; +import java.util.Random; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -896,6 +897,22 @@ public class WalletTest { } } + @Test + public void respectMaxStandardSize() throws Exception { + // Check that we won't create txns > 100kb. Average tx size is ~220 bytes so this would have to be enormous. + sendMoneyToWallet(Utils.toNanoCoins(100, 0), AbstractBlockChain.NewBlockType.BEST_CHAIN); + Transaction tx = new Transaction(params); + byte[] bits = new byte[20]; + new Random().nextBytes(bits); + BigInteger v = Utils.toNanoCoins(0, 1); + // 3100 outputs to a random address. + for (int i = 0; i < 3100; i++) { + tx.addOutput(v, new Address(params, bits)); + } + Wallet.SendRequest req = Wallet.SendRequest.forTx(tx); + assertFalse(wallet.completeTx(req)); + } + // There is a test for spending a coinbase transaction as it matures in BlockChainTest#coinbaseTransactionAvailability // Support for offline spending is tested in PeerGroupTest