private void parsePaymentRequest(Protos.PaymentRequest request) throws PaymentProtocolException { try { if (request == null) throw new PaymentProtocolException("request cannot be null"); if (request.getPaymentDetailsVersion() != 1) throw new PaymentProtocolException.InvalidVersion( "Version 1 required. Received version " + request.getPaymentDetailsVersion()); paymentRequest = request; if (!request.hasSerializedPaymentDetails()) throw new PaymentProtocolException("No PaymentDetails"); paymentDetails = Protos.PaymentDetails.newBuilder() .mergeFrom(request.getSerializedPaymentDetails()) .build(); if (paymentDetails == null) throw new PaymentProtocolException("Invalid PaymentDetails"); if (!paymentDetails.hasNetwork()) params = MainNetParams.get(); else params = NetworkParameters.fromPmtProtocolID(paymentDetails.getNetwork()); if (params == null) throw new PaymentProtocolException.InvalidNetwork( "Invalid network " + paymentDetails.getNetwork()); if (paymentDetails.getOutputsCount() < 1) throw new PaymentProtocolException.InvalidOutputs("No outputs"); for (Protos.Output output : paymentDetails.getOutputsList()) { if (output.hasAmount()) totalValue = totalValue.add(Coin.valueOf(output.getAmount())); } // This won't ever happen in practice. It would only happen if the user provided outputs // that are obviously invalid. Still, we don't want to silently overflow. if (params.hasMaxMoney() && totalValue.compareTo(params.getMaxMoney()) > 0) throw new PaymentProtocolException.InvalidOutputs("The outputs are way too big."); } catch (InvalidProtocolBufferException e) { throw new PaymentProtocolException(e); } }
public void processChange(int change) { if (change == 0) { return; } else { int availableQty = getQuantity(); Coin c = (Coin) getContent(); int denoCoin = c.getValue(); int neededQty = change / denoCoin; if ((change >= denoCoin) && (availableQty > 0)) { if (availableQty >= neededQty) { availableQty -= neededQty; setHandledAmount(neededQty); change -= neededQty * denoCoin; } else if (availableQty < neededQty) { setHandledAmount(availableQty); change -= availableQty * denoCoin; availableQty = 0; } setQuantity(availableQty); System.out.println("CHANGE GIVEN :- " + denoCoin); } if ((successor == null) && (change > 0)) { System.out.println("Not enough coin to dispense"); } else successor.processChange(change); return; } // end of if }
/** @see com.anji.roshambo.RoshamboPlayer#nextMove() */ public int nextMove() { int nextmove; // sets unbeatable flag if no pattern is found unbeatable = true; for (int i = 0; i < nrofpatterns; i++) { if ((patternscore(i) > movenr / 5) || (patternscore(i) > historylength / 5)) { unbeatable = false; break; } } // determine the next move if (movenr < 3 || unbeatable) nextmove = Coin.flip(); else { int best_p = bestpattern(); p_chosen[best_p]++; nextmove = prediction(best_p); } // check op mogelijke illegale zet if ((nextmove > 2) || (nextmove < 0)) { nextmove = Coin.flip(); } // store move history[MINE][movenr] = nextmove; if (!unbeatable) bp++; else ubp++; return nextmove; }
private int calculateCoins() { int sum = 0; if (this.coins == null || this.coins.size() == 0) return sum; for (Coin c : this.coins) { sum += c.getValue(); } return sum; }
/** * Creates the initial multisig contract and incomplete refund transaction which can be requested * at the appropriate time using {@link PaymentChannelClientState#getIncompleteRefundTransaction} * and {@link PaymentChannelClientState#getMultisigContract()}. The way the contract is crafted * can be adjusted by overriding {@link * PaymentChannelClientState#editContractSendRequest(com.google.bitcoin.core.Wallet.SendRequest)}. * By default unconfirmed coins are allowed to be used, as for micropayments the risk should be * relatively low. * * @throws ValueOutOfRangeException if the value being used is too small to be accepted by the * network * @throws InsufficientMoneyException if the wallet doesn't contain enough balance to initiate */ public synchronized void initiate() throws ValueOutOfRangeException, InsufficientMoneyException { final NetworkParameters params = wallet.getParams(); Transaction template = new Transaction(params); // We always place the client key before the server key because, if either side wants some // privacy, they can // use a fresh key for the the multisig contract and nowhere else List<ECKey> keys = Lists.newArrayList(myKey, serverMultisigKey); // There is also probably a change output, but we don't bother shuffling them as it's obvious // from the // format which one is the change. If we start obfuscating the change output better in future // this may // be worth revisiting. TransactionOutput multisigOutput = template.addOutput(totalValue, ScriptBuilder.createMultiSigOutputScript(2, keys)); if (multisigOutput.getMinNonDustValue().compareTo(totalValue) > 0) throw new ValueOutOfRangeException("totalValue too small to use"); Wallet.SendRequest req = Wallet.SendRequest.forTx(template); req.coinSelector = AllowUnconfirmedCoinSelector.get(); editContractSendRequest(req); req.shuffleOutputs = false; // TODO: Fix things so shuffling is usable. wallet.completeTx(req); Coin multisigFee = req.tx.getFee(); multisigContract = req.tx; // Build a refund transaction that protects us in the case of a bad server that's just trying to // cause havoc // by locking up peoples money (perhaps as a precursor to a ransom attempt). We time lock it so // the server // has an assurance that we cannot take back our money by claiming a refund before the channel // closes - this // relies on the fact that since Bitcoin 0.8 time locked transactions are non-final. This will // need to change // in future as it breaks the intended design of timelocking/tx replacement, but for now it // simplifies this // specific protocol somewhat. refundTx = new Transaction(params); refundTx .addInput(multisigOutput) .setSequenceNumber(0); // Allow replacement when it's eventually reactivated. refundTx.setLockTime(expiryTime); if (totalValue.compareTo(Coin.CENT) < 0) { // Must pay min fee. final Coin valueAfterFee = totalValue.subtract(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE); if (Transaction.MIN_NONDUST_OUTPUT.compareTo(valueAfterFee) > 0) throw new ValueOutOfRangeException("totalValue too small to use"); refundTx.addOutput(valueAfterFee, myKey.toAddress(params)); refundFees = multisigFee.add(Transaction.REFERENCE_DEFAULT_MIN_TX_FEE); } else { refundTx.addOutput(totalValue, myKey.toAddress(params)); refundFees = multisigFee; } refundTx.getConfidence().setSource(TransactionConfidence.Source.SELF); log.info( "initiated channel with multi-sig contract {}, refund {}", multisigContract.getHashAsString(), refundTx.getHashAsString()); state = State.INITIATED; // Client should now call getIncompleteRefundTransaction() and send it to the server. }
// Create a payment transaction with valueToMe going back to us private synchronized Wallet.SendRequest makeUnsignedChannelContract(Coin valueToMe) { Transaction tx = new Transaction(wallet.getParams()); if (!totalValue.subtract(valueToMe).equals(Coin.ZERO)) { clientOutput.setValue(totalValue.subtract(valueToMe)); tx.addOutput(clientOutput); } tx.addInput(multisigContract.getOutput(0)); return Wallet.SendRequest.forTx(tx); }
private List<Coin> refundCoins(int total) { List<Coin> returnCoins = new ArrayList<Coin>(); for (Coin c : Coin.LARGETOSMALL) { int numCoins = total / c.getValue(); for (int i = 0; i < numCoins; i++) { returnCoins.add(c); } total = total % c.getValue(); } return returnCoins; }
private void validate(List<Coin> coins) { this.invalidCoins = new ArrayList<Coin>(); this.coins = new ArrayList<Coin>(); for (Coin coin : coins) { if (coin.isValid()) { this.coins.add(coin); } else { this.invalidCoins.add(coin); } } }
// ------------------------------------------------------------------------------------------------------------------------------------------------------- // Drawing public void drawCoin(Graphics g) { // draws the coins for (Coin i : coinList) { g.drawImage( i.getPics().get(i.getCounter()), i.getX(), i.getY(), i.getWidth(), i.getHeight(), null); i.count(); i.setDirection(); } }
/** * Returns the outstanding amount of money sent back to us for all channels to this server added * together. */ public Coin getBalanceForServer(Sha256Hash id) { Coin balance = Coin.ZERO; lock.lock(); try { Set<StoredClientChannel> setChannels = mapChannels.get(id); for (StoredClientChannel channel : setChannels) { synchronized (channel) { if (channel.close != null) continue; balance = balance.add(channel.valueToMe); } } return balance; } finally { lock.unlock(); } }
/** * Returns the value of this output. This is the amount of currency that the destination address * receives. */ public Coin getValue() { maybeParse(); try { return Coin.valueOf(value); } catch (IllegalArgumentException e) { throw new IllegalStateException(e.getMessage(), e); } }
public TransactionOutput( NetworkParameters params, @Nullable Transaction parent, Coin value, byte[] scriptBytes) { super(params); // Negative values obviously make no sense, except for -1 which is used as a sentinel value when // calculating // SIGHASH_SINGLE signatures, so unfortunately we have to allow that here. checkArgument( value.signum() >= 0 || value.equals(Coin.NEGATIVE_SATOSHI), "Negative values not allowed"); checkArgument( value.compareTo(NetworkParameters.MAX_MONEY) < 0, "Values larger than MAX_MONEY not allowed"); this.value = value.value; this.scriptBytes = scriptBytes; parentTransaction = parent; availableForSpending = true; length = 8 + VarInt.sizeOf(scriptBytes.length) + scriptBytes.length; }
/** Returns a {@link Wallet.SendRequest} suitable for broadcasting to the network. */ public Wallet.SendRequest getSendRequest() { Transaction tx = new Transaction(params); for (Protos.Output output : paymentDetails.getOutputsList()) tx.addOutput( new TransactionOutput( params, tx, Coin.valueOf(output.getAmount()), output.getScript().toByteArray())); return Wallet.SendRequest.forTx(tx).fromPaymentDetails(paymentDetails); }
public void scrollCoins() { for (Coin i : coinList) { i.setY(i.getY() + (int) (player1.getVelocity() * 0.3)); i.setYPos(i.getYPos() + (int) (player1.getVelocity() * 0.3)); i.setYMax(i.getYMax() + (int) (player1.getVelocity() * 0.3)); } }
/** * Updates the outputs on the payment contract transaction and re-signs it. The state must be * READY in order to call this method. The signature that is returned should be sent to the server * so it has the ability to broadcast the best seen payment when the channel closes or times out. * * <p>The returned signature is over the payment transaction, which we never have a valid copy of * and thus there is no accessor for it on this object. * * <p>To spend the whole channel increment by {@link PaymentChannelClientState#getTotalValue()} - * {@link PaymentChannelClientState#getValueRefunded()} * * @param size How many satoshis to increment the payment by (note: not the new total). * @throws ValueOutOfRangeException If size is negative or the channel does not have sufficient * money in it to complete this payment. */ public synchronized IncrementedPayment incrementPaymentBy(Coin size) throws ValueOutOfRangeException { checkState(state == State.READY); checkNotExpired(); checkNotNull(size); // Validity of size will be checked by makeUnsignedChannelContract. if (size.signum() < 0) throw new ValueOutOfRangeException("Tried to decrement payment"); Coin newValueToMe = valueToMe.subtract(size); if (newValueToMe.compareTo(Transaction.MIN_NONDUST_OUTPUT) < 0 && newValueToMe.signum() > 0) { log.info( "New value being sent back as change was smaller than minimum nondust output, sending all"); size = valueToMe; newValueToMe = Coin.ZERO; } if (newValueToMe.signum() < 0) throw new ValueOutOfRangeException( "Channel has too little money to pay " + size + " satoshis"); Transaction tx = makeUnsignedChannelContract(newValueToMe); log.info("Signing new payment tx {}", tx); Transaction.SigHash mode; // If we spent all the money we put into this channel, we (by definition) don't care what the // outputs are, so // we sign with SIGHASH_NONE to let the server do what it wants. if (newValueToMe.equals(Coin.ZERO)) mode = Transaction.SigHash.NONE; else mode = Transaction.SigHash.SINGLE; TransactionSignature sig = tx.calculateSignature(0, myKey, multisigScript, mode, true); valueToMe = newValueToMe; updateChannelInWallet(); IncrementedPayment payment = new IncrementedPayment(); payment.signature = sig; payment.amount = size; return payment; }
public static void main(String[] args) { final int FLIPS = 1000; int heads = 0; int tails = 0; Coin myCoin = new Coin(); for (int count = 1; count <= FLIPS; count++) { myCoin.flip(); if (myCoin.isHeads()) heads++; else tails++; } System.out.println("Number of flips: " + FLIPS); System.out.println("Number of heads: " + heads); System.out.println("Number of tails: " + tails); }
/** Returns the outputs of the payment request. */ public List<PaymentProtocol.Output> getOutputs() { List<PaymentProtocol.Output> outputs = new ArrayList<PaymentProtocol.Output>(paymentDetails.getOutputsCount()); for (Protos.Output output : paymentDetails.getOutputsList()) { Coin amount = output.hasAmount() ? Coin.valueOf(output.getAmount()) : null; outputs.add(new PaymentProtocol.Output(amount, output.getScript().toByteArray())); } return outputs; }
public static void main(String[] args) throws Exception { Scanner in = new Scanner(System.in); System.out.print("Enter Product Name: "); String productName = in.next(); System.out.print("Enter Product value: "); int productValue = in.nextInt(); if (StringUtils.isEmpty(productName) || productValue <= 0) { System.out.println("invalid product --->"); return; } Product p = new Product(productName, productValue); List<Coin> coins = new ArrayList<Coin>(); int sum = 0; while (true) { System.out.print("Enter Coin Name or type exit: "); String coinName = in.next().toLowerCase(); if (coinName.equalsIgnoreCase("exit")) { break; } System.out.print("Enter Coin value: "); int coinValue = in.nextInt(); coins.add(new Coin(coinName, coinValue)); } try { Vending v = new Vending(); v.acceptCoins(coins); List<Coin> invalids = v.getInvalidCoins(); if (invalids.size() > 0) { System.out.println("invalid coins:--->"); for (Coin c : invalids) System.out.println(c.getName()); } System.out.println("Product:---------------->" + v.Vend(p)); List<Coin> refunds = v.getRefundCoins(); if (refunds.size() > 0) { System.out.println("refund Coins:--->"); for (Coin c : refunds) System.out.println(c.getName()); } } catch (Exception ex) { System.out.println(ex.getMessage()); } }
public void takeCoin() { if (findSelectedObject() instanceof Pirate && ((Pirate) findSelectedObject()).isOn_plane()) { for (Coin O : GameData.Coins) { if (O.x_on_map == findSelectedObject().x_on_map && O.y_on_map == findSelectedObject().y_on_map && O.fields_left == findSelectedObject().fields_left) { O.takeOrPut(); } } } else { for (Coin O : GameData.Coins) { if (O.x_on_map == findSelectedObject().x_on_map && O.y_on_map == findSelectedObject().y_on_map && O.fields_left == findSelectedObject().fields_left) { O.takeOrPut(); break; } } } }
@Override public void deserializeWalletExtension(Wallet containingWallet, byte[] data) throws Exception { lock.lock(); try { checkState(this.containingWallet == null || this.containingWallet == containingWallet); this.containingWallet = containingWallet; NetworkParameters params = containingWallet.getParams(); ClientState.StoredClientPaymentChannels states = ClientState.StoredClientPaymentChannels.parseFrom(data); for (ClientState.StoredClientPaymentChannel storedState : states.getChannelsList()) { Transaction refundTransaction = params .getDefaultSerializer() .makeTransaction(storedState.getRefundTransaction().toByteArray()); refundTransaction.getConfidence().setSource(TransactionConfidence.Source.SELF); ECKey myKey = (storedState.getMyKey().isEmpty()) ? containingWallet.findKeyFromPubKey(storedState.getMyPublicKey().toByteArray()) : ECKey.fromPrivate(storedState.getMyKey().toByteArray()); StoredClientChannel channel = new StoredClientChannel( Sha256Hash.wrap(storedState.getId().toByteArray()), params .getDefaultSerializer() .makeTransaction(storedState.getContractTransaction().toByteArray()), refundTransaction, myKey, Coin.valueOf(storedState.getValueToMe()), Coin.valueOf(storedState.getRefundFees()), false); if (storedState.hasCloseTransactionHash()) { Sha256Hash closeTxHash = Sha256Hash.wrap(storedState.getCloseTransactionHash().toByteArray()); channel.close = containingWallet.getTransaction(closeTxHash); } putChannel(channel, false); } } finally { lock.unlock(); } }
/** * Creates a state object for a payment channel client. It is expected that you be ready to {@link * PaymentChannelClientState#initiate()} after construction (to avoid creating objects for * channels which are not going to finish opening) and thus some parameters provided here are only * used in {@link PaymentChannelClientState#initiate()} to create the Multisig contract and refund * transaction. * * @param wallet a wallet that contains at least the specified amount of value. * @param myKey a freshly generated private key for this channel. * @param serverMultisigKey a public key retrieved from the server used for the initial multisig * contract * @param value how many satoshis to put into this contract. If the channel reaches this limit, it * must be closed. It is suggested you use at least {@link Utils#CENT} to avoid paying fees if * you need to spend the refund transaction * @param expiryTimeInSeconds At what point (UNIX timestamp +/- a few hours) the channel will * expire * @throws VerificationException If either myKey's pubkey or serverMultisigKey's pubkey are * non-canonical (ie invalid) */ public PaymentChannelClientState( Wallet wallet, ECKey myKey, ECKey serverMultisigKey, Coin value, long expiryTimeInSeconds) throws VerificationException { checkArgument(value.signum() > 0); this.wallet = checkNotNull(wallet); initWalletListeners(); this.serverMultisigKey = checkNotNull(serverMultisigKey); this.myKey = checkNotNull(myKey); this.valueToMe = this.totalValue = checkNotNull(value); this.expiryTime = expiryTimeInSeconds; this.state = State.NEW; }
public void checkPupCollision() { // pretty much the same thing as before, however it alsoe does the powerup effects for (Powerup p : pupList) { if (p.getOnScreen()) { // can be removed later on if (p.checkCollision(player1)) { pupRemove.add(p); player1.setPower(p.getType()); player1.setVelo(50); } } else { pupRemove.add(p); } } if (player1.getPower().equals("Lucky")) { // changes everything to stars for (Coin c : coinList) { starList.add(new Star(c.getX(), c.getY(), 2)); cRemove.add(c); } for (Box b : boxList) { starList.add(new Star(b.getX(), b.getY(), 2)); bRemove.add(b); } for (Enemy e : enemyList) { starList.add(new Star(e.getX(), e.getY(), 2)); eRemove.add(e); } } else if (player1.getPower().equals("Magnet")) { // moves the coins towards the player for (Coin c : coinList) { c.moveTowards(player1); } } else { // else do nothing } for (Powerup p : pupRemove) { poofList.add(new Poof(p.getX(), p.getY(), 2)); pupList.remove(p); } pupRemove = new ArrayList<Powerup>(); }
/** * Create a standard pay to address output for usage in {@link #createPaymentRequest} and {@link * #createPaymentMessage}. * * @param amount amount to pay, or null * @param address address to pay to * @return output */ public static Protos.Output createPayToAddressOutput(@Nullable Coin amount, Address address) { Protos.Output.Builder output = Protos.Output.newBuilder(); if (amount != null) { final NetworkParameters params = address.getParameters(); if (params.hasMaxMoney() && amount.compareTo(params.getMaxMoney()) > 0) throw new IllegalArgumentException("Amount too big: " + amount); output.setAmount(amount.value); } else { output.setAmount(0); } output.setScript(ByteString.copyFrom(ScriptBuilder.createOutputScript(address).getProgram())); return output.build(); }
public void save(Button.ClickEvent event) { try { formFieldBindings.commit(); service.saveAsNewCoin(coin, crawlerResult); String msg = String.format("Saved '%s'.", coin.getName()); Notification.show(msg, Notification.Type.TRAY_NOTIFICATION); parentTable.refreshResults(); } catch (FieldGroup.CommitException e) { e.printStackTrace(); } }
@Override public CoinSelection select(Coin target, List<TransactionOutput> candidates) { try { LinkedList<TransactionOutput> gathered = Lists.newLinkedList(); Coin valueGathered = Coin.ZERO; for (TransactionOutput output : candidates) { if (ignorePending && !isConfirmed(output)) continue; // Find the key that controls output, assuming it's a regular pay-to-pubkey or // pay-to-address output. // We ignore any other kind of exotic output on the assumption we can't spend it ourselves. final Script scriptPubKey = output.getScriptPubKey(); ECKey controllingKey; if (scriptPubKey.isSentToRawPubKey()) { controllingKey = wallet.findKeyFromPubKey(scriptPubKey.getPubKey()); } else if (scriptPubKey.isSentToAddress()) { controllingKey = wallet.findKeyFromPubHash(scriptPubKey.getPubKeyHash()); } else { log.info("Skipping tx output {} because it's not of simple form.", output); continue; } checkNotNull( controllingKey, "Coin selector given output as candidate for which we lack the key"); if (controllingKey.getCreationTimeSeconds() >= unixTimeSeconds) continue; // It's older than the cutoff time so select. valueGathered = valueGathered.add(output.getValue()); gathered.push(output); if (gathered.size() >= MAX_SIMULTANEOUS_INPUTS) { log.warn( "Reached {} inputs, going further would yield a tx that is too large, stopping here.", gathered.size()); break; } } return new CoinSelection(valueGathered, gathered); } catch (ScriptException e) { throw new RuntimeException( e); // We should never have problems understanding scripts in our wallet. } }
public void edit(CrawlerResult crawlerResult) { this.crawlerResult = crawlerResult; if (crawlerResult != null) { coin = new Coin(); coin.setName(crawlerResult.getName()); coin.setNominal(NameUtils.parseNominal(crawlerResult.getName())); CoinVariant variant = new CoinVariant(); // variant.setReleaseDate(LocalDate.now()); variant.setVariant(NameUtils.parseVariant(crawlerResult.getVariant())); if (variant.getVariant() == Variant.UNKNOWN) { variant.setVariant(NameUtils.parseVariant(crawlerResult.getName())); } coin.addVariant(variant); variantField.setValue(variant.getVariant()); CoinVariantHistory history = new CoinVariantHistory(); history.setDate(crawlerResult.getProcessed()); history.setSource(crawlerResult.getSource().toString()); Money price = PriceUtils.parse(crawlerResult.getPrice()); if (price == null) { price = Money.euros(0.0); } history.setPrice(price); variant.addHistory(history); priceField.setValue(price.toString()); formFieldBindings = BeanFieldGroup.bindFieldsBuffered(coin, this); sourceLink.setCaption(LinkUtils.getSourceUrl(crawlerResult)); sourceLink.setResource(new ExternalResource(LinkUtils.getUrl(crawlerResult))); sourceLink.setTargetName("_blank"); name.focus(); } setVisible(crawlerResult != null); }
public void checkCoinCollision() { for (Coin c : coinList) { if (c.getOnScreen()) { // check if the coin is on the screen if (c.checkCollision( c.getPics().get(c.getCounter()), player1)) { // if the player collides with the coin cRemove.add(c); // remove the coin player1.setVelo(50); // set the velocity so the player moves up player1.setDown(false); // set the down false (players moving up) coins += c.getValue(); // check the coins collected score += c.getPoints(); // get the score if (musicOn) { coinSound.play(); // play the sound } } } else { cRemove.add(c); // remove the coin } } for (Coin c : cRemove) { poofList.add(new Poof(c.getX(), c.getY(), 0)); coinList.remove(c); } cRemove = new ArrayList<Coin>(); }
private int detectcopy(int who) { if (movenr < 2) return Coin.flip(); int length = 10; if (movenr < 5) length = movenr - 1; if (movenr < 10) length = movenr - 3; int other = (who + 1) % 2; for (int i = 1; i < 5; i++) { int a = historySearch(who, other, other, length, length, i, i, 1, 0, 1); if (a != -3) return a; int b = historySearch(who, other, other, length, length, i, i, 1, 1, 1); if (b != -3) return b; int c = historySearch(who, other, other, length, length, i, i, 1, 2, 1); if (c != -3) return c; } return -3; }
/** * Gets the minimum value for a txout of this size to be considered non-dust by a reference client * (and thus relayed). See: CTxOut::IsDust() in the reference client. The assumption is that any * output that would consume more than a third of its value in fees is not something the Bitcoin * system wants to deal with right now, so we call them "dust outputs" and they're made non * standard. The choice of one third is somewhat arbitrary and may change in future. * * <p>You probably should use {@link * com.google.bitcoin.core.TransactionOutput#getMinNonDustValue()} which uses a safe fee-per-kb by * default. * * @param feePerKbRequired The fee required per kilobyte. Note that this is the same as the * reference client's -minrelaytxfee * 3 If you want a safe default, use {@link * Transaction#REFERENCE_DEFAULT_MIN_TX_FEE}*3 */ public Coin getMinNonDustValue(Coin feePerKbRequired) { // A typical output is 33 bytes (pubkey hash + opcodes) and requires an input of 148 bytes to // spend so we add // that together to find out the total amount of data used to transfer this amount of value. // Note that this // formula is wrong for anything that's not a pay-to-address output, unfortunately, we must // follow the reference // clients wrongness in order to ensure we're considered standard. A better formula would either // estimate the // size of data needed to satisfy all different script types, or just hard code 33 below. final long size = this.bitcoinSerialize().length + 148; Coin[] nonDustAndRemainder = feePerKbRequired.multiply(size).divideAndRemainder(1000); return nonDustAndRemainder[1].equals(Coin.ZERO) ? nonDustAndRemainder[0] : nonDustAndRemainder[0].add(Coin.SATOSHI); }
@Test public void testReceiveCoinbaseTransaction() throws Exception { // Block 169482 (hash 0000000000000756935f1ee9d5987857b604046f846d3df56d024cdb5f368665) // contains coinbase transactions that are mining pool shares. // The private key MINERS_KEY is used to check transactions are received by a wallet correctly. // The address for this private key is 1GqtGtn4fctXuKxsVzRPSLmYWN1YioLi9y. final String MINING_PRIVATE_KEY = "5JDxPrBRghF1EvSBjDigywqfmAjpHPmTJxYtQTYJxJRHLLQA4mG"; final long BLOCK_NONCE = 3973947400L; final Coin BALANCE_AFTER_BLOCK = Coin.valueOf(22223642); final NetworkParameters PARAMS = MainNetParams.get(); Block block169482 = PARAMS .getDefaultSerializer() .makeBlock(ByteStreams.toByteArray(getClass().getResourceAsStream("block169482.dat"))); // Check block. assertNotNull(block169482); block169482.verify(169482, EnumSet.noneOf(Block.VerifyFlag.class)); assertEquals(BLOCK_NONCE, block169482.getNonce()); StoredBlock storedBlock = new StoredBlock(block169482, BigInteger.ONE, 169482); // Nonsense work - not used in test. // Create a wallet contain the miner's key that receives a spend from a coinbase. ECKey miningKey = DumpedPrivateKey.fromBase58(PARAMS, MINING_PRIVATE_KEY).getKey(); assertNotNull(miningKey); Context context = new Context(PARAMS); Wallet wallet = new Wallet(context); wallet.importKey(miningKey); // Initial balance should be zero by construction. assertEquals(Coin.ZERO, wallet.getBalance()); // Give the wallet the first transaction in the block - this is the coinbase tx. List<Transaction> transactions = block169482.getTransactions(); assertNotNull(transactions); wallet.receiveFromBlock(transactions.get(0), storedBlock, NewBlockType.BEST_CHAIN, 0); // Coinbase transaction should have been received successfully but be unavailable to spend (too // young). assertEquals(BALANCE_AFTER_BLOCK, wallet.getBalance(BalanceType.ESTIMATED)); assertEquals(Coin.ZERO, wallet.getBalance(BalanceType.AVAILABLE)); }