Skip to content

Commit

Permalink
Upgrade to bitcoinj-0.17-alpha2
Browse files Browse the repository at this point in the history
* Transaction constructors no longer use NetworkParameters
* Transaction.read to create a Transaction from a ByteBuffer
* Script.parse to read a script from a byte[]
* Changes to AddressParser
* RpcClientModule no longer requires a network to construct
* BitcoinClient now always initializes JSON mapper in constructor
* Much less use of NetworkParameters in general
* RxBlockchainService interface no longer includes network()
  • Loading branch information
msgilligan committed Jul 28, 2023
1 parent 067c33c commit d7eb5c5
Show file tree
Hide file tree
Showing 46 changed files with 151 additions and 212 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package org.consensusj.bitcoinj.dsl.groovy.categories

import org.bitcoinj.base.Address
import org.bitcoinj.base.AddressParser
import org.bitcoinj.base.DefaultAddressParser
import org.bitcoinj.base.ScriptType
import org.bitcoinj.crypto.ECKey
import spock.lang.Specification
Expand All @@ -13,13 +12,13 @@ import static org.bitcoinj.base.BitcoinNetwork.MAINNET
* Test specification for ECKey static extension methods
*/
class StaticECKeyExtensionSpec extends Specification {
static final private AddressParser addressParser = new DefaultAddressParser();
static final private AddressParser addressParser = AddressParser.getDefault(MAINNET);
// WIF for private key used in Bitcoins the Hard Way
static final fromKeyWIF = "5HusYj2b2x4nroApgfvaSfKYZhRbKFH41bVyPooymbC6KfgSXdD"

// Expected P2PKH address for test WIF
static final expectedAddress = addressParser.parseAddress("1MMMMSUb1piy2ufrSguNUdFmAcvqrQF8M5", MAINNET)
static final expectedSegWitAddress = addressParser.parseAddress("bc1qqgde67hj65u4vcpfrhxq8mjemr05n2kklx68g4", MAINNET)
static final expectedAddress = addressParser.parseAddress("1MMMMSUb1piy2ufrSguNUdFmAcvqrQF8M5")
static final expectedSegWitAddress = addressParser.parseAddress("bc1qqgde67hj65u4vcpfrhxq8mjemr05n2kklx68g4")

def "Can create key and address from private key WIF"() {
when: "we create a private key from WIF format string in the article"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package org.consensusj.bitcoinj.spock

import org.bitcoinj.base.BitcoinNetwork
import org.bitcoinj.base.ScriptType
import org.bitcoinj.core.NetworkParameters
import org.bitcoinj.wallet.Wallet
import spock.lang.Specification

Expand All @@ -12,7 +11,7 @@ import spock.lang.Specification
class CreateWalletSpec extends Specification {
def "quick test"() {
when:
def wallet = Wallet.createDeterministic(NetworkParameters.of(BitcoinNetwork.MAINNET), ScriptType.P2WPKH)
def wallet = Wallet.createDeterministic(BitcoinNetwork.MAINNET, ScriptType.P2WPKH)

then:
wallet != null
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package org.consensusj.bitcoinj.spock

import org.bitcoinj.base.Address
import org.bitcoinj.base.AddressParser
import org.bitcoinj.base.Coin
import org.bitcoinj.base.DefaultAddressParser
import org.bitcoinj.base.ScriptType
import org.bitcoinj.base.Sha256Hash
import org.bitcoinj.core.NetworkParameters
import org.bitcoinj.crypto.ECKey
import org.bitcoinj.core.Transaction
import org.bitcoinj.core.TransactionInput
Expand All @@ -25,32 +24,31 @@ import static org.bitcoinj.base.BitcoinNetwork.MAINNET
* http://www.righto.com/2014/02/bitcoins-hard-way-using-raw-bitcoin.html
*/
class TransactionSpec extends Specification {
static final addressParser = new DefaultAddressParser()
static final mainNetParams = NetworkParameters.of(MAINNET)
static final addressParser = AddressParser.getDefault(MAINNET)

// Input Values
static final ECKey fromKey = ECKey.fromWIF("5HusYj2b2x4nroApgfvaSfKYZhRbKFH41bVyPooymbC6KfgSXdD", false)
static final Address toAddr = addressParser.parseAddress("1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa", MAINNET)
static final Address toAddr = addressParser.parseAddress("1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa")
static final Sha256Hash utxo_id = Sha256Hash.wrap("81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48")
static final Coin txAmount = 0.00091234.btc

// Values used for Verification
static final fromAddrVerify = addressParser.parseAddress("1MMMMSUb1piy2ufrSguNUdFmAcvqrQF8M5", MAINNET)
static final fromAddrVerify = addressParser.parseAddress("1MMMMSUb1piy2ufrSguNUdFmAcvqrQF8M5")

def "Can create and serialize a transaction"() {

when: "We create a signed transaction"
Address fromAddress = fromKey.toAddress(ScriptType.P2PKH, MAINNET)
Transaction tx = new Transaction(mainNetParams)
TransactionOutPoint outPoint = new TransactionOutPoint(mainNetParams, 0, utxo_id)
Transaction tx = new Transaction()
TransactionOutPoint outPoint = new TransactionOutPoint(0, utxo_id)
tx.addOutput(txAmount, toAddr)
tx.addSignedInput(outPoint, ScriptBuilder.createOutputScript(fromAddress), fromKey);

and: "We serialize the transaction"
var rawTx = ByteBuffer.wrap(tx.bitcoinSerialize())

and: "We parse it into a new Transaction object"
Transaction parsedTx = new Transaction(mainNetParams, rawTx)
Transaction parsedTx = Transaction.read(rawTx)

then: "Parsed transaction is as expected"
// We can't do a byte-by-byte comparison because there is a random component to the signature
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package org.consensusj.bitcoinj.spock

import org.bitcoinj.base.Address
import org.bitcoinj.base.DefaultAddressParser
import org.bitcoinj.base.AddressParser
import org.bitcoinj.base.Network
import org.bitcoinj.base.ScriptType
import org.bitcoinj.core.NetworkParameters
import org.bitcoinj.crypto.ECKey
import org.bitcoinj.wallet.Wallet
import spock.lang.Shared
Expand All @@ -16,8 +15,7 @@ import static org.bitcoinj.base.BitcoinNetwork.MAINNET
* Basic tests of wallet serialization/deserialization
*/
class WalletSpec extends Specification {
static final addressParser = new DefaultAddressParser()
static final Address roAddress = addressParser.parseAddress( "1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa", MAINNET);
static final Address roAddress = AddressParser.getDefault(MAINNET).parseAddress( "1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa");

@Shared
Network network
Expand Down Expand Up @@ -72,6 +70,6 @@ class WalletSpec extends Specification {
}

Wallet newEmptyWallet() {
wallet = Wallet.createDeterministic(NetworkParameters.of(network), ScriptType.P2PKH)
wallet = Wallet.createDeterministic(network, ScriptType.P2PKH)
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package org.consensusj.bitcoinj.spock.tx

import org.bitcoinj.base.BitcoinNetwork
import org.bitcoinj.base.DefaultAddressParser
import org.bitcoinj.base.AddressParser
import org.bitcoinj.base.ScriptType
import org.bitcoinj.base.Sha256Hash
import org.bitcoinj.core.NetworkParameters
import org.bitcoinj.crypto.ECKey
import spock.lang.Specification

Expand All @@ -13,11 +12,10 @@ import spock.lang.Specification
* Constants (and later methods) that can be used for multiple transaction tests
*/
abstract class BaseTransactionSpec extends Specification {
static final mainNetParams = NetworkParameters.of(BitcoinNetwork.MAINNET)
static final NotSoPrivatePrivateKey = new BigInteger(1, "180cb41c7c600be951b5d3d0a7334acc7506173875834f7a6c4c786a28fcbb19".decodeHex())
static final utxo_id = Sha256Hash.wrap("81b4c832d70cb56ff957589752eb4125a4cab78a25a8fc52d6a09e5bd4404d48")
static final utxo_amount = 0.00091234.btc
static final fromKey = ECKey.fromPrivate(NotSoPrivatePrivateKey, false)
static final fromAddr = fromKey.toAddress(ScriptType.P2PKH, BitcoinNetwork.MAINNET)
static final toAddr = new DefaultAddressParser().parseAddress("1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa", BitcoinNetwork.MAINNET)
static final toAddr = AddressParser.getDefault(BitcoinNetwork.MAINNET).parseAddress("1KKKK6N21XKo48zWKuQKXdvSsCf95ibHFa")
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import org.bitcoinj.script.ScriptOpCodes
import org.bitcoinj.script.Script
import spock.lang.Unroll

import java.nio.ByteBuffer


/**
* Test/Demonstration of OP_RETURN transaction
Expand All @@ -21,8 +23,8 @@ class OpReturnSpec extends BaseTransactionSpec {
def testData = 0..<length as byte[]

when: "we build an OP_RETURN transaction"
Transaction tx = new Transaction(mainNetParams)
TransactionOutPoint outPoint = new TransactionOutPoint(mainNetParams, 0, utxo_id)
Transaction tx = new Transaction()
TransactionOutPoint outPoint = new TransactionOutPoint( 0, utxo_id)
Script script = new ScriptBuilder()
.op(ScriptOpCodes.OP_RETURN)
.data(testData)
Expand All @@ -35,7 +37,7 @@ class OpReturnSpec extends BaseTransactionSpec {
byte[] rawTx = tx.bitcoinSerialize()

and: "We parse it into a new Transaction object"
Transaction parsedTx = new Transaction(mainNetParams, rawTx)
Transaction parsedTx = Transaction.read(ByteBuffer.wrap(rawTx))

then: "we can retrieve the data"
with (parsedTx.getOutput(0).scriptPubKey.chunks.get(0)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.consensusj.bitcoinj.signing;

import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.crypto.ECKey;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.script.ScriptException;
Expand Down Expand Up @@ -30,7 +29,7 @@ public interface BaseTransactionSigner extends TransactionSigner {
@Override
default CompletableFuture<Transaction> signTransaction(SigningRequest request) {
// Create a new, empty (mutable) bitcoinj transaction
Transaction transaction = new Transaction(NetworkParameters.of(request.network()));
Transaction transaction = new Transaction();

// For each output in the signing request, add an output to the bitcoinj transaction
request.outputs().forEach(
Expand Down Expand Up @@ -74,7 +73,7 @@ default Optional<Exception> verifyInput(Transaction tx, int index, TransactionIn
* @param exceptionSupplier exception to throw if key is not available.
*/
default void addSignedInput(Transaction tx, TransactionInputData in, Supplier<? extends RuntimeException> exceptionSupplier) {
tx.addSignedInput(in.toOutPoint(tx.getParams().network()),
tx.addSignedInput(in.toOutPoint(),
in.script(),
in.amount(),
keyForInput(in).orElseThrow(exceptionSupplier),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,13 @@ public List<TransactionOutputData> outputs() {
* @return an unsigned bitcoinj transaction
*/
public Transaction toUnsignedTransaction() {
NetworkParameters params = NetworkParameters.of(network);
Transaction utx = new Transaction(params);
Transaction utx = new Transaction();
this.inputs().forEach(in ->
utx.addInput(in.toOutPoint(network).getHash(),
in.toOutPoint(network).getIndex(),
utx.addInput(in.toOutPoint().getHash(),
in.toOutPoint().getIndex(),
ScriptBuilder.createEmpty()));
this.outputs().forEach(out ->
utx.addOutput(new TransactionOutput(params,
utx,
utx.addOutput(new TransactionOutput(utx,
out.amount(),
out.scriptPubKey().getProgram())));
return utx;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import org.bitcoinj.base.Address;
import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.crypto.ECKey;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.Transaction;
import org.bitcoinj.core.TransactionOutPoint;
import org.bitcoinj.core.TransactionOutput;
Expand Down Expand Up @@ -47,10 +46,9 @@ private CompletableFuture<Transaction> signTransaction(List<Address> addresses,
if (addresses.size() != unsignedTx.getInputs().size()) {
throw new IllegalArgumentException("addresses and inputs must be 1:1 mapped");
}
NetworkParameters netParams = unsignedTx.getParams();

// Create a new, empty bitcoinj transaction
Transaction tx = new Transaction(netParams);
Transaction tx = new Transaction();

// For each output in the signing request, add an output to the bitcoinj transaction
// TODO: Transaction validation
Expand All @@ -62,7 +60,7 @@ private CompletableFuture<Transaction> signTransaction(List<Address> addresses,
for (int index = 0; index < unsignedTx.getInputs().size(); index++) {
Address address = addresses.get(index);
TransactionInput input = unsignedTx.getInputs().get(index);
TransactionOutPoint outPoint = input.duplicateDetached().getOutpoint();
TransactionOutPoint outPoint = input.getOutpoint().disconnectOutput();
DeterministicKey fromKey = keyChain.findKeyFromPubHash(address.getHash());
tx.addSignedInput(outPoint, ScriptBuilder.createOutputScript(address), input.getValue(), fromKey);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public interface TransactionInputData {
* This probably shouldn't be here but is needed for proper operation with bitcoinj
* @return A Transaction "outpoint" pointing to the utxo this input will spend.
*/
TransactionOutPoint toOutPoint(Network network);
TransactionOutPoint toOutPoint();

Utxo toUtxo();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import org.bitcoinj.base.Coin;
import org.bitcoinj.base.Network;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.base.Sha256Hash;
import org.bitcoinj.core.TransactionInput;
import org.bitcoinj.core.TransactionOutPoint;
Expand Down Expand Up @@ -50,7 +49,7 @@ public Script script() {
}

public TransactionInput toMutableInput(Network network) {
return createTransactionInput(toOutPoint(network), Coin.ofSat(amount), script);
return createTransactionInput(toOutPoint(), Coin.ofSat(amount), script);
}

@Override
Expand All @@ -59,11 +58,11 @@ public Utxo.Complete toUtxo() {
}

@Override
public TransactionOutPoint toOutPoint(Network network) {
return new TransactionOutPoint(NetworkParameters.of(network), index, txId);
public TransactionOutPoint toOutPoint() {
return new TransactionOutPoint(index, txId);
}

private static TransactionInput createTransactionInput(TransactionOutPoint outPoint, Coin amount, Script script) {
return new TransactionInput(outPoint.getParams(), null, script.getProgram(), outPoint, amount);
return new TransactionInput( null, script.getProgram(), outPoint, amount);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.consensusj.bitcoinj.signing;

import org.bitcoinj.base.Address;
import org.bitcoinj.base.AddressParser;
import org.bitcoinj.base.Coin;
import org.bitcoinj.base.DefaultAddressParser;
import org.bitcoinj.script.Script;
import org.bitcoinj.script.ScriptBuilder;

Expand All @@ -25,7 +25,7 @@ public TransactionOutputAddress(long amount, Address address) {

public TransactionOutputAddress(long amount, String address) {
this.amount = amount;
this.address = new DefaultAddressParser().parseAddressAnyNetwork(address);
this.address = AddressParser.getDefault().parseAddress(address);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import org.bitcoinj.base.Address;
import org.bitcoinj.base.Coin;
import org.bitcoinj.base.Network;
import org.bitcoinj.core.NetworkParameters;
import org.bitcoinj.core.TransactionOutput;
import org.bitcoinj.script.Script;

Expand All @@ -25,6 +24,6 @@ static TransactionOutputData fromTxOutput(TransactionOutput out) {
}

default TransactionOutput toMutableOutput(Network network) {
return new TransactionOutput(NetworkParameters.of(network), null, amount(), scriptPubKey().getProgram());
return new TransactionOutput(null, amount(), scriptPubKey().getProgram());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,9 @@ package org.consensusj.bitcoinj.signing

import org.bitcoinj.base.Address
import org.bitcoinj.base.BitcoinNetwork
import org.bitcoinj.base.Coin
import org.bitcoinj.base.LegacyAddress
import org.bitcoinj.base.Network
import org.bitcoinj.core.NetworkParameters
import org.bitcoinj.core.Transaction
import org.bitcoinj.core.TransactionInput
import org.bitcoinj.core.TransactionOutput
import org.bitcoinj.script.Script
import org.bitcoinj.script.ScriptBuilder
import org.bitcoinj.script.ScriptException
import org.bitcoinj.wallet.DeterministicSeed
import spock.lang.Specification

Expand Down Expand Up @@ -45,6 +38,6 @@ abstract class DeterministicKeychainBaseSpec extends Specification {

protected static Transaction firstChangeTransaction() {
final byte[] change_tx_bytes = "0100000001cc652689b217db0cec03cab18a629437a0f1e308db9ee30b934b6989be50641f000000006b4830450221008f9abcda51669dc501a68d2778e2fc33f25d62d74ec791b2776733e14c39aba502201f79445d6eb4364ae83a0579ee0414abe285df034a5e42d0e15938f3f4861c91012102878641346f6ccfa4ed0a50f1786bfbd1891ff200b4c040040a804abc2c5ad69affffffff0240420f00000000001976a9145ab93563a289b74c355a9b9258b86f12bb84affb88acafe34f01000000001976a9149b1077b9d102fcc105e99a906cfd34285928b03e88ac00000000".decodeHex()
return new Transaction(NetworkParameters.of(BitcoinNetwork.TESTNET), ByteBuffer.wrap(change_tx_bytes))
return Transaction.read(ByteBuffer.wrap(change_tx_bytes))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class ECKeySignerSpec extends DeterministicKeychainBaseSpec {

then:
signedTx != null
signedTx.verify()
Transaction.verify(network, signedTx)

when: "We validate the signature on the input"
TransactionVerification.correctlySpendsInput(signedTx, 0, fromAddress)
Expand Down
Loading

0 comments on commit d7eb5c5

Please sign in to comment.