mirror of
https://github.com/sparrowwallet/drongo.git
synced 2024-11-02 18:26:43 +00:00
address and related optimizations
This commit is contained in:
parent
fefebbabb5
commit
9ae1f68dc4
11 changed files with 48 additions and 50 deletions
|
@ -9,14 +9,14 @@ import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public abstract class Address {
|
public abstract class Address {
|
||||||
protected final byte[] hash;
|
protected final byte[] data;
|
||||||
|
|
||||||
public Address(byte[] hash) {
|
public Address(byte[] data) {
|
||||||
this.hash = hash;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getHash() {
|
public byte[] getData() {
|
||||||
return hash;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAddress() {
|
public String getAddress() {
|
||||||
|
@ -24,7 +24,7 @@ public abstract class Address {
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getAddress(Network network) {
|
public String getAddress(Network network) {
|
||||||
return Base58.encodeChecked(getVersion(network), hash);
|
return Base58.encodeChecked(getVersion(network), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
|
@ -50,16 +50,15 @@ public abstract class Address {
|
||||||
public abstract String getOutputScriptDataType();
|
public abstract String getOutputScriptDataType();
|
||||||
|
|
||||||
public boolean equals(Object obj) {
|
public boolean equals(Object obj) {
|
||||||
if(!(obj instanceof Address)) {
|
if(!(obj instanceof Address address)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Address address = (Address)obj;
|
return Arrays.equals(data, address.data) && getVersion(Network.get()) == address.getVersion(Network.get());
|
||||||
return address.getAddress().equals(this.getAddress());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return getAddress().hashCode();
|
return Arrays.hashCode(data) + getVersion(Network.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Address fromString(String address) throws InvalidAddressException {
|
public static Address fromString(String address) throws InvalidAddressException {
|
||||||
|
|
|
@ -6,11 +6,8 @@ import com.sparrowwallet.drongo.protocol.Script;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
|
|
||||||
public class P2PKAddress extends Address {
|
public class P2PKAddress extends Address {
|
||||||
private final byte[] pubKey;
|
|
||||||
|
|
||||||
public P2PKAddress(byte[] pubKey) {
|
public P2PKAddress(byte[] pubKey) {
|
||||||
super(Utils.sha256hash160(pubKey));
|
super(pubKey);
|
||||||
this.pubKey = pubKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -18,17 +15,22 @@ public class P2PKAddress extends Address {
|
||||||
return network.getP2PKHAddressHeader();
|
return network.getP2PKHAddressHeader();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAddress(Network network) {
|
||||||
|
return Utils.bytesToHex(data);
|
||||||
|
}
|
||||||
|
|
||||||
public ScriptType getScriptType() {
|
public ScriptType getScriptType() {
|
||||||
return ScriptType.P2PK;
|
return ScriptType.P2PK;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Script getOutputScript() {
|
public Script getOutputScript() {
|
||||||
return getScriptType().getOutputScript(pubKey);
|
return getScriptType().getOutputScript(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getOutputScriptData() {
|
public byte[] getOutputScriptData() {
|
||||||
return pubKey;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,12 +21,12 @@ public class P2PKHAddress extends Address {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Script getOutputScript() {
|
public Script getOutputScript() {
|
||||||
return getScriptType().getOutputScript(hash);
|
return getScriptType().getOutputScript(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getOutputScriptData() {
|
public byte[] getOutputScriptData() {
|
||||||
return hash;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -22,12 +22,12 @@ public class P2SHAddress extends Address {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Script getOutputScript() {
|
public Script getOutputScript() {
|
||||||
return getScriptType().getOutputScript(hash);
|
return getScriptType().getOutputScript(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getOutputScriptData() {
|
public byte[] getOutputScriptData() {
|
||||||
return hash;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -1,17 +1,13 @@
|
||||||
package com.sparrowwallet.drongo.address;
|
package com.sparrowwallet.drongo.address;
|
||||||
|
|
||||||
import com.sparrowwallet.drongo.Network;
|
import com.sparrowwallet.drongo.Network;
|
||||||
import com.sparrowwallet.drongo.Utils;
|
|
||||||
import com.sparrowwallet.drongo.protocol.Bech32;
|
import com.sparrowwallet.drongo.protocol.Bech32;
|
||||||
import com.sparrowwallet.drongo.protocol.Script;
|
import com.sparrowwallet.drongo.protocol.Script;
|
||||||
import com.sparrowwallet.drongo.protocol.ScriptType;
|
import com.sparrowwallet.drongo.protocol.ScriptType;
|
||||||
|
|
||||||
public class P2TRAddress extends Address {
|
public class P2TRAddress extends Address {
|
||||||
private final byte[] pubKey;
|
|
||||||
|
|
||||||
public P2TRAddress(byte[] pubKey) {
|
public P2TRAddress(byte[] pubKey) {
|
||||||
super(Utils.sha256hash160(pubKey));
|
super(pubKey);
|
||||||
this.pubKey = pubKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -21,7 +17,7 @@ public class P2TRAddress extends Address {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAddress(Network network) {
|
public String getAddress(Network network) {
|
||||||
return Bech32.encode(network.getBech32AddressHRP(), getVersion(), pubKey);
|
return Bech32.encode(network.getBech32AddressHRP(), getVersion(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,12 +27,12 @@ public class P2TRAddress extends Address {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Script getOutputScript() {
|
public Script getOutputScript() {
|
||||||
return getScriptType().getOutputScript(pubKey);
|
return getScriptType().getOutputScript(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getOutputScriptData() {
|
public byte[] getOutputScriptData() {
|
||||||
return pubKey;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,7 +17,7 @@ public class P2WPKHAddress extends Address {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAddress(Network network) {
|
public String getAddress(Network network) {
|
||||||
return Bech32.encode(network.getBech32AddressHRP(), getVersion(), hash);
|
return Bech32.encode(network.getBech32AddressHRP(), getVersion(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -27,12 +27,12 @@ public class P2WPKHAddress extends Address {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Script getOutputScript() {
|
public Script getOutputScript() {
|
||||||
return getScriptType().getOutputScript(hash);
|
return getScriptType().getOutputScript(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getOutputScriptData() {
|
public byte[] getOutputScriptData() {
|
||||||
return hash;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -15,7 +15,7 @@ public class P2WSHAddress extends Address {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getAddress(Network network) {
|
public String getAddress(Network network) {
|
||||||
return Bech32.encode(network.getBech32AddressHRP(), getVersion(), hash);
|
return Bech32.encode(network.getBech32AddressHRP(), getVersion(), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -25,12 +25,12 @@ public class P2WSHAddress extends Address {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Script getOutputScript() {
|
public Script getOutputScript() {
|
||||||
return getScriptType().getOutputScript(hash);
|
return getScriptType().getOutputScript(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] getOutputScriptData() {
|
public byte[] getOutputScriptData() {
|
||||||
return hash;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -275,6 +275,10 @@ public class ECKey {
|
||||||
* use {@code new BigInteger(1, bytes);}
|
* use {@code new BigInteger(1, bytes);}
|
||||||
*/
|
*/
|
||||||
public static ECPoint publicPointFromPrivate(BigInteger privKey) {
|
public static ECPoint publicPointFromPrivate(BigInteger privKey) {
|
||||||
|
if (privKey.bitLength() > CURVE.getN().bitLength()) {
|
||||||
|
privKey = privKey.mod(CURVE.getN());
|
||||||
|
}
|
||||||
|
|
||||||
if(Secp256k1Context.isEnabled()) {
|
if(Secp256k1Context.isEnabled()) {
|
||||||
try {
|
try {
|
||||||
byte[] pubKeyBytes = NativeSecp256k1.computePubkey(Utils.bigIntegerToBytes(privKey, 32), false);
|
byte[] pubKeyBytes = NativeSecp256k1.computePubkey(Utils.bigIntegerToBytes(privKey, 32), false);
|
||||||
|
@ -285,13 +289,6 @@ public class ECKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* TODO: FixedPointCombMultiplier currently doesn't support scalars longer than the group order,
|
|
||||||
* but that could change in future versions.
|
|
||||||
*/
|
|
||||||
if (privKey.bitLength() > CURVE.getN().bitLength()) {
|
|
||||||
privKey = privKey.mod(CURVE.getN());
|
|
||||||
}
|
|
||||||
return new FixedPointCombMultiplier().multiply(CURVE.getG(), privKey);
|
return new FixedPointCombMultiplier().multiply(CURVE.getG(), privKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -134,10 +134,10 @@ public class PSBT {
|
||||||
for(TransactionOutput txOutput : transaction.getOutputs()) {
|
for(TransactionOutput txOutput : transaction.getOutputs()) {
|
||||||
try {
|
try {
|
||||||
Address address = txOutput.getScript().getToAddresses()[0];
|
Address address = txOutput.getScript().getToAddresses()[0];
|
||||||
if(walletTransaction.getPayments().stream().anyMatch(payment -> payment.getAddress().equals(address))) {
|
if(walletTransaction.getAddressNodeMap().containsKey(address)) {
|
||||||
outputNodes.add(wallet.getWalletAddresses().getOrDefault(address, null));
|
outputNodes.add(walletTransaction.getAddressNodeMap().get(address));
|
||||||
} else if(walletTransaction.getChangeMap().keySet().stream().anyMatch(changeNode -> changeNode.getAddress().equals(address))) {
|
} else if(walletTransaction.getChangeMap().keySet().stream().anyMatch(changeNode -> changeNode.getAddress().equals(address))) {
|
||||||
outputNodes.add(wallet.getWalletAddresses().getOrDefault(address, null));
|
outputNodes.add(walletTransaction.getChangeMap().keySet().stream().filter(changeNode -> changeNode.getAddress().equals(address)).findFirst().orElse(null));
|
||||||
}
|
}
|
||||||
} catch(NonStandardScriptException e) {
|
} catch(NonStandardScriptException e) {
|
||||||
//Ignore, likely OP_RETURN output
|
//Ignore, likely OP_RETURN output
|
||||||
|
|
|
@ -154,8 +154,12 @@ public class WalletTransaction {
|
||||||
getAddressNodeMap(wallet);
|
getAddressNodeMap(wallet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<Address, WalletNode> getAddressNodeMap() {
|
||||||
|
return getAddressNodeMap(getWallet());
|
||||||
|
}
|
||||||
|
|
||||||
public Map<Address, WalletNode> getAddressNodeMap(Wallet wallet) {
|
public Map<Address, WalletNode> getAddressNodeMap(Wallet wallet) {
|
||||||
Map<Script, WalletNode> walletOutputScripts = null;
|
Map<Address, WalletNode> walletAddresses = null;
|
||||||
|
|
||||||
Map<Address, WalletNode> walletAddressNodeMap = addressNodeMap.computeIfAbsent(wallet, w -> new LinkedHashMap<>());
|
Map<Address, WalletNode> walletAddressNodeMap = addressNodeMap.computeIfAbsent(wallet, w -> new LinkedHashMap<>());
|
||||||
for(Payment payment : payments) {
|
for(Payment payment : payments) {
|
||||||
|
@ -164,11 +168,11 @@ public class WalletTransaction {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(payment.getAddress() != null && wallet != null) {
|
if(payment.getAddress() != null && wallet != null) {
|
||||||
if(walletOutputScripts == null) {
|
if(walletAddresses == null) {
|
||||||
walletOutputScripts = wallet.getWalletOutputScripts();
|
walletAddresses = wallet.getWalletAddresses();
|
||||||
}
|
}
|
||||||
|
|
||||||
WalletNode walletNode = walletOutputScripts.get(payment.getAddress().getOutputScript());
|
WalletNode walletNode = walletAddresses.get(payment.getAddress());
|
||||||
walletAddressNodeMap.put(payment.getAddress(), walletNode);
|
walletAddressNodeMap.put(payment.getAddress(), walletNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ public class AddressTest {
|
||||||
Address address = (i % 2 == 0 ? new P2PKHAddress(values) : new P2WPKHAddress(values));
|
Address address = (i % 2 == 0 ? new P2PKHAddress(values) : new P2WPKHAddress(values));
|
||||||
String strAddress = address.toString();
|
String strAddress = address.toString();
|
||||||
Address checkAddress = Address.fromString(strAddress);
|
Address checkAddress = Address.fromString(strAddress);
|
||||||
Assert.assertArrayEquals(values, checkAddress.getHash());
|
Assert.assertArrayEquals(values, checkAddress.getData());
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] values32 = new byte[32];
|
byte[] values32 = new byte[32];
|
||||||
|
@ -107,7 +107,7 @@ public class AddressTest {
|
||||||
Address address = new P2WSHAddress(values32);
|
Address address = new P2WSHAddress(values32);
|
||||||
String strAddress = address.toString();
|
String strAddress = address.toString();
|
||||||
Address checkAddress = Address.fromString(strAddress);
|
Address checkAddress = Address.fromString(strAddress);
|
||||||
Assert.assertArrayEquals(values32, checkAddress.getHash());
|
Assert.assertArrayEquals(values32, checkAddress.getData());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue