From 022e7c27fe86e5ea151a2404863c6845a8274ba7 Mon Sep 17 00:00:00 2001 From: Andreas Schildbach Date: Fri, 25 Apr 2014 21:21:11 +0200 Subject: [PATCH] Wrap coin-ish BigIntegers into Coin class. --- .../core/AbstractWalletEventListener.java | 5 +- .../java/com/google/bitcoin/core/Block.java | 10 +- .../java/com/google/bitcoin/core/Coin.java | 132 +++++++ .../bitcoin/core/FullPrunedBlockChain.java | 17 +- .../core/InsufficientMoneyException.java | 7 +- .../bitcoin/core/NetworkParameters.java | 2 +- .../com/google/bitcoin/core/PeerGroup.java | 3 +- .../bitcoin/core/StoredTransactionOutput.java | 11 +- .../com/google/bitcoin/core/Transaction.java | 31 +- .../google/bitcoin/core/TransactionInput.java | 7 +- .../bitcoin/core/TransactionOutput.java | 37 +- .../java/com/google/bitcoin/core/Utils.java | 28 +- .../java/com/google/bitcoin/core/Wallet.java | 134 +++---- .../bitcoin/core/WalletEventListener.java | 5 +- ...ntChannelServerConnectionEventHandler.java | 4 +- .../jni/NativeWalletEventListener.java | 6 +- .../channels/IPaymentChannelClient.java | 8 +- .../channels/PaymentChannelClient.java | 27 +- .../PaymentChannelClientConnection.java | 9 +- .../channels/PaymentChannelClientState.java | 37 +- .../channels/PaymentChannelServer.java | 13 +- .../PaymentChannelServerListener.java | 10 +- .../channels/PaymentChannelServerState.java | 23 +- .../ServerConnectionEventHandler.java | 6 +- .../StoredPaymentChannelClientStates.java | 17 +- .../StoredPaymentChannelServerStates.java | 3 +- .../channels/StoredServerChannel.java | 11 +- .../protocols/payments/PaymentProtocol.java | 12 +- .../protocols/payments/PaymentSession.java | 11 +- .../bitcoin/store/H2FullPrunedBlockStore.java | 2 +- .../store/PostgresFullPrunedBlockStore.java | 2 +- .../store/WalletProtobufSerializer.java | 4 +- .../google/bitcoin/testing/FakeTxBuilder.java | 11 +- .../testing/TestWithNetworkConnections.java | 3 +- .../bitcoin/testing/TestWithWallet.java | 9 +- .../com/google/bitcoin/uri/BitcoinURI.java | 16 +- .../google/bitcoin/wallet/CoinSelection.java | 8 +- .../google/bitcoin/wallet/CoinSelector.java | 4 +- .../bitcoin/wallet/DefaultCoinSelector.java | 13 +- .../bitcoin/wallet/DefaultRiskAnalysis.java | 5 +- .../bitcoin/wallet/KeyTimeCoinSelector.java | 5 +- .../bitcoin/protocols/payments/Protos.java | 2 +- .../google/bitcoin/core/BlockChainTest.java | 8 +- .../com/google/bitcoin/core/BlockTest.java | 2 +- .../google/bitcoin/core/ChainSplitTest.java | 17 +- .../bitcoin/core/CoinbaseBlockTest.java | 6 +- .../bitcoin/core/FullBlockTestGenerator.java | 180 +++++----- .../google/bitcoin/core/PeerGroupTest.java | 3 +- .../com/google/bitcoin/core/PeerTest.java | 13 +- .../com/google/bitcoin/core/UtilsTest.java | 7 +- .../com/google/bitcoin/core/WalletTest.java | 330 +++++++++--------- .../channels/ChannelConnectionTest.java | 33 +- .../protocols/channels/ChannelTestUtils.java | 9 +- .../channels/PaymentChannelStateTest.java | 74 ++-- .../payments/PaymentProtocolTest.java | 6 +- .../payments/PaymentSessionTest.java | 5 +- .../store/WalletProtobufSerializerTest.java | 10 +- .../wallet/DefaultCoinSelectorTest.java | 3 +- .../wallet/DefaultRiskAnalysisTest.java | 4 +- .../google/bitcoin/examples/DoubleSpend.java | 3 +- .../examples/ExamplePaymentChannelClient.java | 13 +- .../examples/ExamplePaymentChannelServer.java | 7 +- .../bitcoin/examples/ForwardingService.java | 9 +- .../bitcoin/examples/RefreshWallet.java | 3 +- .../google/bitcoin/tools/TestFeeLevel.java | 5 +- .../com/google/bitcoin/tools/WalletTool.java | 20 +- 66 files changed, 793 insertions(+), 687 deletions(-) create mode 100644 core/src/main/java/com/google/bitcoin/core/Coin.java diff --git a/core/src/main/java/com/google/bitcoin/core/AbstractWalletEventListener.java b/core/src/main/java/com/google/bitcoin/core/AbstractWalletEventListener.java index acccf17f..7f98d005 100644 --- a/core/src/main/java/com/google/bitcoin/core/AbstractWalletEventListener.java +++ b/core/src/main/java/com/google/bitcoin/core/AbstractWalletEventListener.java @@ -19,7 +19,6 @@ package com.google.bitcoin.core; import com.google.bitcoin.script.Script; import com.google.bitcoin.wallet.AbstractKeyChainEventListener; -import java.math.BigInteger; import java.util.List; /** @@ -27,12 +26,12 @@ import java.util.List; */ public abstract class AbstractWalletEventListener extends AbstractKeyChainEventListener implements WalletEventListener { @Override - public void onCoinsReceived(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) { + public void onCoinsReceived(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { onChange(); } @Override - public void onCoinsSent(Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) { + public void onCoinsSent(Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) { onChange(); } diff --git a/core/src/main/java/com/google/bitcoin/core/Block.java b/core/src/main/java/com/google/bitcoin/core/Block.java index da259c53..a36b3a16 100644 --- a/core/src/main/java/com/google/bitcoin/core/Block.java +++ b/core/src/main/java/com/google/bitcoin/core/Block.java @@ -166,7 +166,7 @@ public class Block extends Message { *

The half-life is controlled by {@link com.google.bitcoin.core.NetworkParameters#getSubsidyDecreaseBlockCount()}. *

*/ - public BigInteger getBlockInflation(int height) { + public Coin getBlockInflation(int height) { return Utils.toNanoCoins(50, 0).shiftRight(height / params.getSubsidyDecreaseBlockCount()); } @@ -953,7 +953,7 @@ public class Block extends Message { static private int txCounter; /** Adds a coinbase transaction to the block. This exists for unit tests. */ - void addCoinbaseTransaction(byte[] pubKeyTo, BigInteger value) { + void addCoinbaseTransaction(byte[] pubKeyTo, Coin value) { unCacheTransactions(); transactions = new ArrayList(); Transaction coinbase = new Transaction(params); @@ -989,7 +989,7 @@ public class Block extends Message { * In this variant you can specify a public key (pubkey) for use in generating coinbase blocks. */ Block createNextBlock(@Nullable Address to, @Nullable TransactionOutPoint prevOut, long time, - byte[] pubKey, BigInteger coinbaseValue) { + byte[] pubKey, Coin coinbaseValue) { Block b = new Block(params); b.setDifficultyTarget(difficultyTarget); b.addCoinbaseTransaction(pubKey, coinbaseValue); @@ -1036,7 +1036,7 @@ public class Block extends Message { } @VisibleForTesting - public Block createNextBlock(@Nullable Address to, BigInteger value) { + public Block createNextBlock(@Nullable Address to, Coin value) { return createNextBlock(to, null, Utils.currentTimeSeconds(), pubkeyForTesting, value); } @@ -1046,7 +1046,7 @@ public class Block extends Message { } @VisibleForTesting - public Block createNextBlockWithCoinbase(byte[] pubKey, BigInteger coinbaseValue) { + public Block createNextBlockWithCoinbase(byte[] pubKey, Coin coinbaseValue) { return createNextBlock(null, null, Utils.currentTimeSeconds(), pubKey, coinbaseValue); } diff --git a/core/src/main/java/com/google/bitcoin/core/Coin.java b/core/src/main/java/com/google/bitcoin/core/Coin.java new file mode 100644 index 00000000..86f11903 --- /dev/null +++ b/core/src/main/java/com/google/bitcoin/core/Coin.java @@ -0,0 +1,132 @@ +/** + * Copyright 2014 Andreas Schildbach + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.bitcoin.core; + +import java.io.Serializable; +import java.math.BigInteger; + +/** + * Represents a monetary Bitcoin value. This class is immutable. + */ +public final class Coin implements Comparable, Serializable { + + public static final Coin ZERO = new Coin(BigInteger.ZERO); + public static final Coin ONE = new Coin(BigInteger.ONE); + public static final Coin TEN = new Coin(BigInteger.TEN); + + private final BigInteger value; + + public Coin(final BigInteger value) { + this.value = value; + } + + public Coin(final String value, final int radix) { + this(new BigInteger(value, radix)); + } + + public Coin(final byte[] value) { + this(new BigInteger(value)); + } + + public static Coin valueOf(final long value) { + return new Coin(BigInteger.valueOf(value)); + } + + public Coin add(final Coin value) { + return new Coin(this.value.add(value.value)); + } + + public Coin subtract(final Coin value) { + return new Coin(this.value.subtract(value.value)); + } + + public Coin multiply(final Coin value) { + return new Coin(this.value.multiply(value.value)); + } + + public Coin multiply(final long value) { + return multiply(Coin.valueOf(value)); + } + + public Coin divide(final Coin value) { + return new Coin(this.value.divide(value.value)); + } + + public Coin[] divideAndRemainder(final Coin value) { + final BigInteger[] result = this.value.divideAndRemainder(value.value); + return new Coin[] { new Coin(result[0]), new Coin(result[1]) }; + } + + public Coin shiftLeft(final int n) { + return new Coin(this.value.shiftLeft(n)); + } + + public Coin shiftRight(final int n) { + return new Coin(this.value.shiftRight(n)); + } + + public int signum() { + return this.value.signum(); + } + + public Coin negate() { + return new Coin(this.value.negate()); + } + + public byte[] toByteArray() { + return this.value.toByteArray(); + } + + public long longValue() { + return this.value.longValue(); + } + + public double doubleValue() { + return this.value.doubleValue(); + } + + public BigInteger toBigInteger() { + return value; + } + + @Override + public String toString() { + return value.toString(); + } + + @Override + public boolean equals(final Object o) { + if (o == this) + return true; + if (o == null || o.getClass() != getClass()) + return false; + final Coin other = (Coin) o; + if (!this.value.equals(other.value)) + return false; + return true; + } + + @Override + public int hashCode() { + return this.value.hashCode(); + } + + @Override + public int compareTo(final Coin other) { + return this.value.compareTo(other.value); + } +} diff --git a/core/src/main/java/com/google/bitcoin/core/FullPrunedBlockChain.java b/core/src/main/java/com/google/bitcoin/core/FullPrunedBlockChain.java index aa008280..cb37323a 100644 --- a/core/src/main/java/com/google/bitcoin/core/FullPrunedBlockChain.java +++ b/core/src/main/java/com/google/bitcoin/core/FullPrunedBlockChain.java @@ -23,7 +23,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nullable; -import java.math.BigInteger; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -175,12 +174,12 @@ public class FullPrunedBlockChain extends AbstractBlockChain { sigOps += tx.getSigOpCount(); } } - BigInteger totalFees = BigInteger.ZERO; - BigInteger coinbaseValue = null; + Coin totalFees = Coin.ZERO; + Coin coinbaseValue = null; for (final Transaction tx : block.transactions) { boolean isCoinBase = tx.isCoinBase(); - BigInteger valueIn = BigInteger.ZERO; - BigInteger valueOut = BigInteger.ZERO; + Coin valueIn = Coin.ZERO; + Coin valueOut = Coin.ZERO; final List