3
0
mirror of https://github.com/Qortal/altcoinj.git synced 2025-01-31 15:22:16 +00:00

Married wallets: extending fee calculation

This commit is contained in:
Kosta Korenkov 2014-06-25 23:19:02 +04:00 committed by Mike Hearn
parent fd0c6a27f4
commit 12bfa5f5ee
2 changed files with 44 additions and 9 deletions

View File

@ -491,7 +491,7 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
/** Returns the address used for change outputs. Note: this will probably go away in future. */
public Address getChangeAddress() {
return currentKey(KeyChain.KeyPurpose.CHANGE).toAddress(params);
return keychain.currentAddress(KeyChain.KeyPurpose.CHANGE);
}
/**
@ -3895,14 +3895,17 @@ public class Wallet extends BaseTaggableObject implements Serializable, BlockCha
int size = 0;
for (TransactionOutput output : selection.gathered) {
try {
if (output.getScriptPubKey().isSentToAddress()) {
// Send-to-address spends usually take maximum pubkey.length (as it may be compressed or not) + 75 bytes
final ECKey key = findKeyFromPubHash(output.getScriptPubKey().getPubKeyHash());
size += checkNotNull(key, "Coin selection includes unspendable outputs").getPubKey().length + 75;
} else if (output.getScriptPubKey().isSentToRawPubKey())
size += 74; // Send-to-pubkey spends usually take maximum 74 bytes to spend
else
throw new IllegalStateException("Unknown output type returned in coin selection");
Script script = output.getScriptPubKey();
ECKey key = null;
Script redeemScript = null;
if (script.isSentToAddress()) {
key = findKeyFromPubHash(script.getPubKeyHash());
checkNotNull(key, "Coin selection includes unspendable outputs");
} else if (script.isPayToScriptHash()) {
redeemScript = keychain.findRedeemScriptFromPubHash(script.getPubKeyHash());
checkNotNull(redeemScript, "Coin selection includes unspendable outputs");
}
size += script.getNumberOfBytesRequiredToSpend(key, redeemScript);
} catch (ScriptException e) {
// If this happens it means an output script in a wallet tx could not be understood. That should never
// happen, if it does it means the wallet has got into an inconsistent state.

View File

@ -25,6 +25,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.crypto.digests.RIPEMD160Digest;
import javax.annotation.Nullable;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@ -54,6 +55,7 @@ import static com.google.common.base.Preconditions.checkState;
public class Script {
private static final Logger log = LoggerFactory.getLogger(Script.class);
public static final long MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
public static final int SIG_SIZE = 75;
// The program is a set of chunks where each element is either [opcode] or [data, data, data ...]
protected List<ScriptChunk> chunks;
@ -446,6 +448,36 @@ public class Script {
return 0;
}
/**
* Returns number of bytes required to spend this script. It accepts optional ECKey and redeemScript that may
* be required for certain types of script to estimate target size.
*/
public int getNumberOfBytesRequiredToSpend(@Nullable ECKey pubKey, @Nullable Script redeemScript) {
if (isPayToScriptHash()) {
// scriptSig: <sig> [sig] [sig...] <redeemscript>
checkArgument(redeemScript != null, "P2SH script requires redeemScript to be spent");
// for N of M CHECKMULTISIG redeem script we will need N signatures to spend
ScriptChunk nChunk = redeemScript.getChunks().get(0);
int n = Script.decodeFromOpN(nChunk.opcode);
return n * SIG_SIZE + getProgram().length;
} else if (isSentToMultiSig()) {
// scriptSig: OP_0 <sig> [sig] [sig...]
// for N of M CHECKMULTISIG script we will need N signatures to spend
ScriptChunk nChunk = chunks.get(0);
int n = Script.decodeFromOpN(nChunk.opcode);
return n * SIG_SIZE + 1;
} else if (isSentToRawPubKey()) {
// scriptSig: <sig>
return SIG_SIZE;
} else if (isSentToAddress()) {
// scriptSig: <sig> <pubkey>
int uncompressedPubKeySize = 65;
return SIG_SIZE + (pubKey != null ? pubKey.getPubKey().length : uncompressedPubKeySize);
} else {
throw new IllegalStateException("Unsupported script type");
}
}
/**
* <p>Whether or not this is a scriptPubKey representing a pay-to-script-hash output. In such outputs, the logic that
* controls reclamation is not actually in the output at all. Instead there's just a hash, and it's up to the