Permalink
Browse files

Use Coin rather than BigDecimal in RPC API

* Convert parameters and return types
* Convert tests and related code
  • Loading branch information...
msgilligan committed Sep 11, 2015
1 parent f7fe1a8 commit f8e008e0d6d1865f40ffa554859d4bdb44de48a0
@@ -70,5 +70,4 @@ class NumberCategorySpec extends Specification {
expect:
0 as Byte == 0.byteValue()
}

}
@@ -30,7 +30,7 @@ abstract class BaseRegTestSpec extends Specification implements BTCTestSupport,
assert available

// Make sure we have enough test coins
while (getBalance().btc < minBTCForTests) {
while (getBalance() < minBTCForTests) {
// Mine blocks until we have some coins to spend
client.generateBlocks(1)
}
@@ -20,6 +20,6 @@ class BTCTestSupportIntegrationSpec extends BaseRegTestSpec {
generateBlock()

then:
getBitcoinBalance(requestingAddress).btc == requestedAmount
getBitcoinBalance(requestingAddress) == requestedAmount
}
}
@@ -48,14 +48,14 @@ class BitcoinJRawTxSpec extends BaseRegTestSpec {
fundingAddress = getNewAddress()

and: "coins are sent to the new address from a random source"
sendToAddress(fundingAddress, fundingAmount.getDecimalBtc())
sendToAddress(fundingAddress, fundingAmount)

and: "a new block is mined"
generateBlock()

then: "the address should have that balance"
def balance = getBitcoinBalance(fundingAddress)
balance.btc == fundingAmount
balance == fundingAmount
}

def "Create Signed raw transaction"() {
@@ -107,10 +107,10 @@ class BitcoinJRawTxSpec extends BaseRegTestSpec {

and: "#fundingAddress has a remainder of coins minus transaction fees"
def balanceRemaining = getBitcoinBalance(fundingAddress)
balanceRemaining.btc == fundingAmount - sendingAmount - stdTxFee.btc
balanceRemaining == fundingAmount - sendingAmount - stdTxFee

and: "#destinationAddress has a balance matching the spent amount"
def balanceDestination = getBitcoinBalance(destinationAddress)
balanceDestination.btc == sendingAmount
balanceDestination == sendingAmount
}
}
@@ -28,22 +28,22 @@ class BitcoinRawTransactionSpec extends BaseRegTestSpec {
fundingAddress = getNewAddress()

and: "coins are sent to the new address from a random source"
sendToAddress(fundingAddress, fundingAmount.decimalBtc)
sendToAddress(fundingAddress, fundingAmount)

and: "a new block is mined"
generateBlock()

then: "the address should have that balance"
def balance = getBitcoinBalance(fundingAddress)
balance.btc == fundingAmount
balance == fundingAmount
}

def "Create unsigned raw transaction"() {
given: "a newly created address as destination"
destinationAddress = getNewAddress("destinationAddress")

when: "we create a transaction, spending from #fundingAddress to #destinationAddress"
rawTransactionHex = createRawTransaction(fundingAddress, destinationAddress, sendingAmount.decimalBtc)
rawTransactionHex = createRawTransaction(fundingAddress, destinationAddress, sendingAmount)

then: "there should be a raw transaction"
rawTransactionHex != null
@@ -76,30 +76,30 @@ class BitcoinRawTransactionSpec extends BaseRegTestSpec {

and: "#fundingAddress has a remainder of coins minus transaction fees"
def balanceRemaining = getBitcoinBalance(fundingAddress)
balanceRemaining.btc == fundingAmount - sendingAmount - stdTxFee.btc
balanceRemaining == fundingAmount - sendingAmount - stdTxFee

and: "#destinationAddress has a balance matching the spent amount"
def balanceDestination = getBitcoinBalance(destinationAddress)
balanceDestination.btc == sendingAmount
balanceDestination == sendingAmount
}

def "Send Bitcoin"() {
when: "a new address is created"
def newAddress = getNewAddress()

and: "coins are sent to the new address from #destinationAddress"
Coin amount = sendingAmount - stdTxFee.btc
sendBitcoin(destinationAddress, newAddress, amount.decimalBtc)
Coin amount = sendingAmount - stdTxFee
sendBitcoin(destinationAddress, newAddress, amount)

and: "a new block is mined"
generateBlock()

then: "the sending address should be empty"
def balanceSource = getBitcoinBalance(destinationAddress)
balanceSource == 0.0
balanceSource == 0.btc

and: "the new adress should have the amount sent to"
def balance = getBitcoinBalance(newAddress)
balance.btc == amount
balance == amount
}
}
@@ -44,13 +44,13 @@ class BitcoinSpec extends BaseRegTestSpec {
def destinationAddress = getNewAddress()

when: "we send it testAmount (from coins mined in RegTest mode)"
sendToAddress(destinationAddress, testAmount.getDecimalBtc(), "comment", "comment-to")
sendToAddress(destinationAddress, testAmount, "comment", "comment-to")

and: "we generate 1 new block"
generateBlock()

then: "the new address has a balance of testAmount"
testAmount == getReceivedByAddress(destinationAddress).btc
testAmount == getReceivedByAddress(destinationAddress)
// TODO: check balance of source address/wallet
}

@@ -65,7 +65,7 @@ class BitcoinSpec extends BaseRegTestSpec {
def "Get a filtered list of unconfirmed transaction outputs"() {
when: "we create a new address and send #testAmount to it"
def destinationAddress = getNewAddress()
sendToAddress(destinationAddress, testAmount.decimalBtc, "comment", "comment-to")
sendToAddress(destinationAddress, testAmount, "comment", "comment-to")

and: "we request unconfirmed unspent outputs for #destinationAddress"
def unspent = listUnspent(0, 0, [destinationAddress])
@@ -19,38 +19,38 @@ class BitcoinStepwiseSpec extends BaseRegTestSpec {
def "Send some funds to an address (that may also get block reward)"() {
when: "we send some BTC to a newly created address"
def throwAwayAddress = getNewAddress()
sendToAddress(throwAwayAddress, 25.0)
sendToAddress(throwAwayAddress, 25.btc)
generateBlock()
then: "we have the correct amount of BTC there, or possibly more due to block reward"
getBitcoinBalance(throwAwayAddress) >= 25.0
getBitcoinBalance(throwAwayAddress) >= 25.btc
}
def "Be able to fund wealthy account from mining profits"() {
when: "we send some BTC to an address"
wealthyAddress = getNewAddress(testAccount1Name)
sendToAddress(wealthyAddress, (sendAmount*2 + extraAmount).decimalBtc)
sendToAddress(wealthyAddress, sendAmount*2 + extraAmount)
generateBlock()
then: "we have the correct amount of BTC there"
getBitcoinBalance(wealthyAddress).btc == sendAmount*2 + extraAmount
getBitcoinBalance(wealthyAddress) == sendAmount*2 + extraAmount
}
def "Send an amount to a newly created address"() {
setup: "initial balance"
Coin wealthyStartBalance = getBitcoinBalance(wealthyAddress).btc
Coin wealthyStartBalance = getBitcoinBalance(wealthyAddress)
Coin testAmount = 1.btc
when: "we create a new address and send testAmount to it"
Address destinationAddress = getNewAddress(testAccount2Name)
sendBitcoin(wealthyAddress, destinationAddress, testAmount.decimalBtc)
sendBitcoin(wealthyAddress, destinationAddress, testAmount)
generateBlock()

then: "the new address has a balance of testAmount"
getBitcoinBalance(destinationAddress).btc == testAmount
getBitcoinBalance(destinationAddress) == testAmount

and: "the source address is poorer by the correct amount"
getBitcoinBalance(wealthyAddress).btc == wealthyStartBalance - testAmount - stdTxFee.btc
getBitcoinBalance(wealthyAddress) == wealthyStartBalance - testAmount - stdTxFee
}

}
@@ -24,10 +24,10 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
private final NetworkParameters netParams = RegTestParams.get()
private static final BigDecimal satoshisPerBTCDecimal = new BigDecimal(Coin.COIN.value);
private static final BigDecimal bdSatoshiPerCoin = new BigDecimal(Coin.COIN.longValue());
final BigDecimal stdTxFee = 0.00010000
final BigDecimal stdRelayTxFee = 0.00001000
final Coin stdTxFee = 0.00010000.btc
final Coin stdRelayTxFee = 0.00001000.btc
final Integer defaultMaxConf = 9999999
final long stdTxFeeSatoshis = btcToSatoshi(stdTxFee)
final long stdTxFeeSatoshis = stdTxFee.value

@Deprecated
Sha256Hash requestBitcoin(Address toAddress, BigDecimal requestedBTC) {
@@ -44,8 +44,10 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
* @return
*/
Sha256Hash requestBitcoin(Address toAddress, Coin requestedAmount) {
long requestedSatoshi = requestedAmount.longValue()
log.debug "requestBitcoin requesting {} satoshi ({} BTC)", requestedSatoshi, satoshiToBtc(requestedSatoshi)
log.debug "requestBitcoin requesting {}", requestedAmount
if (requestedAmount.value > NetworkParameters.MAX_MONEY.value) {
throw new IllegalArgumentException("request exceeds MAX_MONEY")
}
long amountGatheredSoFar = 0
def inputs = new ArrayList<Outpoint>()

@@ -56,7 +58,7 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
generateBlocks(minCoinAge - blockCount)
}

while (amountGatheredSoFar < requestedSatoshi) {
while (amountGatheredSoFar < requestedAmount.value) {
generateBlock()
def blockIndex = blockCount - minCoinAge
def block = client.getBlock(blockIndex)
@@ -76,8 +78,8 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
}

// Don't care about change, we mine it anyway
def outputs = new HashMap<Address, BigDecimal>()
outputs.put(toAddress, satoshiToBtc(requestedSatoshi))
def outputs = new HashMap<Address, Coin>()
outputs.put(toAddress, requestedAmount)

def unsignedTxHex = client.createRawTransaction(inputs, outputs)
def signingResult = client.signRawTransaction(unsignedTxHex)
@@ -101,21 +103,21 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
* @param outputs The destinations and amounts to transfer
* @return The hex-encoded raw transaction
*/
String createRawTransaction(Address fromAddress, Map<Address, BigDecimal> outputs) {
String createRawTransaction(Address fromAddress, Map<Address, Coin> outputs) {
// Get unspent outputs via RPC
def unspentOutputs = listUnspent(0, defaultMaxConf, [fromAddress])

// Gather inputs
def inputs = unspentOutputs.collect { new Outpoint(it.txid, it.vout) }

// Calculate change
BigDecimal amountIn = (BigDecimal) unspentOutputs.sum { it.amount }
BigDecimal amountOut = (BigDecimal) outputs.values().sum()
BigDecimal amountChange = amountIn - amountOut - stdTxFee
Coin amountIn = Coin.valueOf((long) unspentOutputs.sum { it.amount.value })
Coin amountOut = Coin.valueOf((long) outputs.values().sum { it.value } )
Coin amountChange = amountIn - amountOut - stdTxFee
if (amountIn < (amountOut + stdTxFee)) {
println "Insufficient funds: ${amountIn} < ${amountOut + stdTxFee}"
}
if (amountChange > 0) {
if (amountChange.value > 0) {
outputs[fromAddress] = amountChange
}

@@ -134,8 +136,8 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
* @param amount The amount
* @return The hex-encoded raw transaction
*/
String createRawTransaction(Address fromAddress, Address toAddress, BigDecimal amount) {
def outputs = new HashMap<Address, BigDecimal>()
String createRawTransaction(Address fromAddress, Address toAddress, Coin amount) {
def outputs = new HashMap<Address, Coin>()
outputs[toAddress] = amount
return createRawTransaction(fromAddress, outputs)
}
@@ -148,7 +150,7 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
* @param address The address
* @return The balance
*/
BigDecimal getBitcoinBalance(Address address) {
Coin getBitcoinBalance(Address address) {
// NOTE: because null is currently removed from the argument lists passed via RPC, using it here for default
// values would result in the RPC call "listunspent" with arguments [["address"]], which is invalid, similar
// to a call with arguments [null, null, ["address"]], as expected arguments are either [], [int], [int, int]
@@ -163,7 +165,7 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
* @param minConf Minimum amount of confirmations
* @return The balance
*/
BigDecimal getBitcoinBalance(Address address, Integer minConf) {
Coin getBitcoinBalance(Address address, Integer minConf) {
return getBitcoinBalance(address, minConf, defaultMaxConf)
}

@@ -176,15 +178,15 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
* @param maxConf Maximum amount of confirmations
* @return The balance
*/
BigDecimal getBitcoinBalance(Address address, Integer minConf, Integer maxConf) {
def btcBalance = new BigDecimal(0)
Coin getBitcoinBalance(Address address, Integer minConf, Integer maxConf) {
Coin btcBalance = Coin.ZERO
def unspentOutputs = listUnspent(minConf, maxConf, [address])

for (unspentOutput in unspentOutputs) {
btcBalance += unspentOutput.amount
}

return btcBalance
return btcBalance;
}

/**
@@ -196,7 +198,7 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
* @param amount The amount to transfer
* @return The transaction hash
*/
Sha256Hash sendBitcoin(Address fromAddress, Address toAddress, BigDecimal amount) {
Sha256Hash sendBitcoin(Address fromAddress, Address toAddress, Coin amount) {
def outputs = new HashMap<Address, BigDecimal>()
outputs[toAddress] = amount
return sendBitcoin(fromAddress, outputs)
@@ -210,7 +212,7 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
* @param outputs The destinations and amounts to transfer
* @return The transaction hash
*/
Sha256Hash sendBitcoin(Address fromAddress, Map<Address, BigDecimal> outputs) {
Sha256Hash sendBitcoin(Address fromAddress, Map<Address, Coin> outputs) {
def unsignedTxHex = createRawTransaction(fromAddress, outputs)
def signingResult = signRawTransaction(unsignedTxHex)

@@ -234,7 +236,7 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
* @return True, if enough outputs with a value of at least {@code stdRelayTxFee} were spent
*/
Boolean consolidateCoins() {
def amountIn = new BigDecimal(0)
Coin amountIn = 0.btc
def inputs = new ArrayList<Outpoint>()
def unspentOutputs = listUnspent(1, defaultMaxConf)

@@ -250,7 +252,7 @@ trait BTCTestSupport implements BitcoinClientDelegate, Loggable {
}

// No receiver, just spend most of it as fee (!)
def outputs = new HashMap<Address, BigDecimal>()
def outputs = new HashMap<Address, Coin>()
outputs[newAddress] = stdRelayTxFee

def unsignedTxHex = client.createRawTransaction(inputs, outputs)
Oops, something went wrong.

0 comments on commit f8e008e

Please sign in to comment.