Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bitcoin Core 0.18 RPC #550

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -183,24 +183,6 @@ class TestRpcUtilTest extends BitcoindRpcTest {
}
}

it should "be able to wait for disconnected nodes" in {
for {
(first, second) <- BitcoindRpcTestUtil.createUnconnectedNodePair(
clientAccum)
_ <- first.addNode(second.instance.uri, AddNodeArgument.Add)
_ <- BitcoindRpcTestUtil.awaitConnection(first, second)

peerInfo <- first.getPeerInfo
_ = assert(peerInfo.length == 1)
_ = assert(peerInfo.head.addnode)
_ = assert(peerInfo.head.networkInfo.addr == second.instance.uri)

_ <- first.disconnectNode(peerInfo.head.networkInfo.addr)
_ <- BitcoindRpcTestUtil.awaitDisconnected(first, second)
newPeerInfo <- first.getPeerInfo
} yield assert(newPeerInfo.isEmpty)
}

it should "be able to find outputs of previous transactions" in {
for {
(first, second, _) <- clientsF
Expand Down
Expand Up @@ -19,18 +19,6 @@ class P2PRpcTest extends BitcoindRpcTest {

behavior of "P2PRpcTest"

it should "be able to get peer info" in {
for {
(freshClient, otherFreshClient) <- clientPairF
infoList <- freshClient.getPeerInfo
} yield {
assert(infoList.length >= 0)
val info = infoList.head
assert(info.addnode)
assert(info.networkInfo.addr == otherFreshClient.getDaemon.uri)
}
}

it should "be able to get the added node info" in {
for {

Expand Down
Expand Up @@ -4,22 +4,14 @@ import java.io.File
import java.util.Scanner

import org.bitcoins.core.crypto.{ECPrivateKey, ECPublicKey}
import org.bitcoins.core.currency.{Bitcoins, Satoshis}
import org.bitcoins.core.currency.{Bitcoins, CurrencyUnit, Satoshis}
import org.bitcoins.core.number.{Int64, UInt32}
import org.bitcoins.core.protocol.P2PKHAddress
import org.bitcoins.core.protocol.script.ScriptSignature
import org.bitcoins.core.protocol.transaction.{
TransactionInput,
TransactionOutPoint
}
import org.bitcoins.core.protocol.transaction.{TransactionInput, TransactionOutPoint}
import org.bitcoins.core.protocol.{BitcoinAddress, P2PKHAddress}
import org.bitcoins.core.wallet.fee.SatoshisPerByte
import org.bitcoins.rpc.client.common.RpcOpts.AddressType
import org.bitcoins.rpc.client.common.{
BitcoindRpcClient,
BitcoindVersion,
RpcOpts
}
import org.bitcoins.rpc.jsonmodels.RpcAddress
import org.bitcoins.rpc.client.common.{BitcoindRpcClient, BitcoindVersion, RpcOpts}
import org.bitcoins.rpc.util.RpcUtil
import org.bitcoins.testkit.rpc.BitcoindRpcTestUtil
import org.bitcoins.testkit.util.BitcoindRpcTest
Expand Down Expand Up @@ -78,8 +70,8 @@ class WalletRpcTest extends BitcoindRpcTest {
} yield {

val expectedFileName =
if (client.instance.getVersion == BitcoindVersion.V17) ""
else "wallet.dat"
if (client.instance.getVersion == BitcoindVersion.V16) "wallet.dat"
else ""

assert(wallets == Vector(expectedFileName))
}
Expand Down Expand Up @@ -247,30 +239,51 @@ class WalletRpcTest extends BitcoindRpcTest {
}

it should "be able to list address groupings" in {

val amount = Bitcoins(1.25)

def getChangeAddressAndAmount(client: BitcoindRpcClient, address: BitcoinAddress): Future[(BitcoinAddress, CurrencyUnit)] = {
for {
listTx <- client.listTransactions().map(_.filter(tx => tx.address.contains(address) && tx.category == "send"))
_ = assert(listTx.nonEmpty)
tx = listTx.head
_ = assert(tx.txid.nonEmpty)
rawTx <- client.getRawTransactionRaw(tx.txid.get)
} yield {
val outs = rawTx.outputs.filterNot(_.value == amount)
val changeAddresses = outs
.map(out => (BitcoinAddress.fromScriptPubKey(out.scriptPubKey, networkParam), out.value))
assert(changeAddresses.size == 1)
(changeAddresses.head._1.get, changeAddresses.head._2)
}
}

for {
(client, _, _) <- clientsF
groupingsBefore <- client.listAddressGroupings

address <- client.getNewAddress

_ <- BitcoindRpcTestUtil
.fundBlockChainTransaction(client, address, Bitcoins(1.25))
groupings <- client.listAddressGroupings
block <- BitcoindRpcTestUtil.getFirstBlock(client)
} yield {
val rpcAddress =
groupings.find(vec => vec.head.address == address).get.head
assert(rpcAddress.address == address)
assert(rpcAddress.balance == Bitcoins(1.25))
.fundBlockChainTransaction(client, address, amount)

val firstAddress =
block.tx.head.vout.head.scriptPubKey.addresses.get.head
(changeAddress, changeAmount) <- getChangeAddressAndAmount(client, address)

val maxGroup =
groupings
.max(Ordering.by[Vector[RpcAddress], BigDecimal](addr =>
addr.head.balance.toBigDecimal))
.head
groupingsAfter <- client.listAddressGroupings
} yield {

assert(maxGroup.address == firstAddress)
// the address should appear in a new address grouping
val rpcAddress =
groupingsAfter.find(vec => vec.head.address == address).get.head
assert(rpcAddress.address == address)
assert(rpcAddress.balance == amount)

// the change address should be added to an exiting address grouping
val changeGrouping = groupingsAfter.find(after =>
groupingsBefore.exists(before => before.head == after.head && before.size + 1 == after.size)).get
val rpcChangeAddress = changeGrouping.find(addr => addr.address == changeAddress).get
assert(rpcChangeAddress.address == changeAddress)
assert(rpcChangeAddress.balance == changeAmount)
}
}

Expand Down
Expand Up @@ -26,7 +26,19 @@ class BitcoindV16RpcClientTest extends BitcoindRpcTest {
lazy val clientsF: Future[(BitcoindV16RpcClient, BitcoindV16RpcClient)] =
BitcoindRpcTestUtil.createNodePairV16(clientAccum)

behavior of "BitoindV16RpcClient"
behavior of "BitcoindV16RpcClient"

it should "be able to get peer info" in {
for {
(freshClient, otherFreshClient) <- clientsF
infoList <- freshClient.getPeerInfo
} yield {
assert(infoList.length >= 0)
val info = infoList.head
assert(info.addnode)
assert(info.networkInfo.addr == otherFreshClient.getDaemon.uri)
}
}

it should "be able to start a V16 bitcoind" in {
for {
Expand Down
Expand Up @@ -29,6 +29,18 @@ class BitcoindV17RpcClientTest extends BitcoindRpcTest {

behavior of "BitcoindV17RpcClient"

it should "be able to get peer info" in {
for {
(freshClient, otherFreshClient) <- clientsF
infoList <- freshClient.getPeerInfo
} yield {
assert(infoList.length >= 0)
val info = infoList.head
assert(info.addnode)
assert(info.networkInfo.addr == otherFreshClient.getDaemon.uri)
}
}

it should "test mempool acceptance" in {
for {
(client, otherClient) <- clientsF
Expand Down
Expand Up @@ -52,7 +52,8 @@ class PsbtRpcTest extends BitcoindRpcTest {
processedPsbt <- client.walletProcessPsbt(psbt)
decoded <- client.decodePsbt(processedPsbt.psbt)
} yield {
assert(decoded.inputs.exists(_.nonWitnessUtxo.isDefined))
assert(decoded.inputs.exists(inputs =>
inputs.nonWitnessUtxo.isDefined || inputs.witnessUtxo.isDefined))
}

}
Expand Down
@@ -0,0 +1,101 @@
package org.bitcoins.rpc.v18
import org.bitcoins.chain.models.BlockHeaderDbHelper
import org.bitcoins.core.protocol.blockchain.RegTestNetChainParams
import org.bitcoins.rpc.client.common.BitcoindVersion
import org.bitcoins.rpc.client.common.RpcOpts.AddNodeArgument
import org.bitcoins.rpc.client.v18.BitcoindV18RpcClient
import org.bitcoins.testkit.chain.BlockHeaderHelper
import org.bitcoins.testkit.rpc.BitcoindRpcTestUtil
import org.bitcoins.testkit.util.BitcoindRpcTest

import scala.concurrent.Future

class BitcoindV18RpcClientTest extends BitcoindRpcTest {
lazy val clientF: Future[BitcoindV18RpcClient] = {
val client = new BitcoindV18RpcClient(BitcoindRpcTestUtil.v18Instance())
val clientIsStartedF = BitcoindRpcTestUtil.startServers(Vector(client))
clientIsStartedF.map(_ => client)
}
lazy val clientPairF: Future[(BitcoindV18RpcClient, BitcoindV18RpcClient)] =
BitcoindRpcTestUtil.createNodePairV18(clientAccum)

clientF.foreach(c => clientAccum.+=(c))

behavior of "BitcoindV18RpcClient"

it should "be able to start a V18 bitcoind instance" in {

clientF.map { client =>
assert(client.version == BitcoindVersion.V18)
}

}

it should "return active rpc commands" in {
val generatedF = clientF.flatMap(client =>
client.getNewAddress.flatMap(addr => client.generateToAddress(100, addr)))
val rpcinfoF =
generatedF.flatMap(_ => clientF.flatMap(client => client.getRpcInfo()))

rpcinfoF.map { result =>
assert(result.active_commands.length == 1)
}
}

it should "return a list of wallets" in {
for {
client <- clientF
_ <- client.createWallet("Suredbits")
list <- client.listWalletDir()
} yield {
assert(list.wallets.exists(_.name.contains("Suredbits")))
}
}

it should "analyze a descriptor" in {

val descriptor =
"pk(0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798)"

val descriptorF =
clientF.flatMap(client => client.getDescriptorInfo(descriptor))

descriptorF.map { result =>
assert(result.isrange.==(false))
assert(result.issolvable.==(true))
assert(result.hasprivatekeys.==(false))
}
}

it should "get node address given a null parameter" in {
val nodeF = clientF.flatMap(client => client.getNodeAddresses())
cwaldron97 marked this conversation as resolved.
Show resolved Hide resolved

nodeF.map { result =>
assert(result.isEmpty)
}
}

//TODO: currently the test doesn't work because of how known nodes work (remove ignore and implement test)
it should "get node addresses given a count" ignore {
cwaldron97 marked this conversation as resolved.
Show resolved Hide resolved
for {
(freshClient, otherFreshClient) <- clientPairF
freshclientnode <- freshClient.addNode(freshClient.getDaemon.uri,
AddNodeArgument.Add)
nodeaddress <- freshClient.getNodeAddresses(1)
} yield {
assert(nodeaddress.head.address == otherFreshClient.instance.uri)
assert(nodeaddress.head.services == 1)
}

}

it should "successfully submit a header" in {
val genesisHeader = RegTestNetChainParams.genesisBlock.blockHeader
val genesisHeaderDb =
BlockHeaderDbHelper.fromBlockHeader(height = 1, genesisHeader)
val nextHeader = BlockHeaderHelper.buildNextHeader(genesisHeaderDb)
clientF.flatMap(client =>
client.submitHeader(nextHeader.blockHeader).map(_ => succeed))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible, you should add to this test and make sure that the submitted header was accepted (i.e. that you can get it)

}

}