private WalletTransaction connectTransactionOutputs( com.fuelcoinj.wallet.Protos.Transaction txProto) throws UnreadableWalletException { Transaction tx = txMap.get(txProto.getHash()); final WalletTransaction.Pool pool; switch (txProto.getPool()) { case DEAD: pool = WalletTransaction.Pool.DEAD; break; case PENDING: pool = WalletTransaction.Pool.PENDING; break; case SPENT: pool = WalletTransaction.Pool.SPENT; break; case UNSPENT: pool = WalletTransaction.Pool.UNSPENT; break; // Upgrade old wallets: inactive pool has been merged with the pending pool. // Remove this some time after 0.9 is old and everyone has upgraded. // There should not be any spent outputs in this tx as old wallets would not allow them to // be spent // in this state. case INACTIVE: case PENDING_INACTIVE: pool = WalletTransaction.Pool.PENDING; break; default: throw new UnreadableWalletException("Unknown transaction pool: " + txProto.getPool()); } for (int i = 0; i < tx.getOutputs().size(); i++) { TransactionOutput output = tx.getOutputs().get(i); final Protos.TransactionOutput transactionOutput = txProto.getTransactionOutput(i); if (transactionOutput.hasSpentByTransactionHash()) { final ByteString spentByTransactionHash = transactionOutput.getSpentByTransactionHash(); Transaction spendingTx = txMap.get(spentByTransactionHash); if (spendingTx == null) { throw new UnreadableWalletException( String.format( "Could not connect %s to %s", tx.getHashAsString(), byteStringToHash(spentByTransactionHash))); } final int spendingIndex = transactionOutput.getSpentByTransactionIndex(); TransactionInput input = checkNotNull(spendingTx.getInput(spendingIndex)); input.connect(output); } } if (txProto.hasConfidence()) { Protos.TransactionConfidence confidenceProto = txProto.getConfidence(); TransactionConfidence confidence = tx.getConfidence(); readConfidence(tx, confidenceProto, confidence); } return new WalletTransaction(pool, tx); }
private void readTransaction(Protos.Transaction txProto, NetworkParameters params) throws UnreadableWalletException { Transaction tx = new Transaction(params); if (txProto.hasUpdatedAt()) { tx.setUpdateTime(new Date(txProto.getUpdatedAt())); } for (Protos.TransactionOutput outputProto : txProto.getTransactionOutputList()) { Coin value = Coin.valueOf(outputProto.getValue()); byte[] scriptBytes = outputProto.getScriptBytes().toByteArray(); TransactionOutput output = new TransactionOutput(params, tx, value, scriptBytes); tx.addOutput(output); } for (Protos.TransactionInput inputProto : txProto.getTransactionInputList()) { byte[] scriptBytes = inputProto.getScriptBytes().toByteArray(); TransactionOutPoint outpoint = new TransactionOutPoint( params, inputProto.getTransactionOutPointIndex() & 0xFFFFFFFFL, byteStringToHash(inputProto.getTransactionOutPointHash())); Coin value = inputProto.hasValue() ? Coin.valueOf(inputProto.getValue()) : null; TransactionInput input = new TransactionInput(params, tx, scriptBytes, outpoint, value); if (inputProto.hasSequence()) { input.setSequenceNumber(inputProto.getSequence()); } tx.addInput(input); } for (int i = 0; i < txProto.getBlockHashCount(); i++) { ByteString blockHash = txProto.getBlockHash(i); int relativityOffset = 0; if (txProto.getBlockRelativityOffsetsCount() > 0) relativityOffset = txProto.getBlockRelativityOffsets(i); tx.addBlockAppearance(byteStringToHash(blockHash), relativityOffset); } if (txProto.hasLockTime()) { tx.setLockTime(0xffffffffL & txProto.getLockTime()); } if (txProto.hasPurpose()) { switch (txProto.getPurpose()) { case UNKNOWN: tx.setPurpose(Transaction.Purpose.UNKNOWN); break; case USER_PAYMENT: tx.setPurpose(Transaction.Purpose.USER_PAYMENT); break; case KEY_ROTATION: tx.setPurpose(Transaction.Purpose.KEY_ROTATION); break; case ASSURANCE_CONTRACT_CLAIM: tx.setPurpose(Transaction.Purpose.ASSURANCE_CONTRACT_CLAIM); break; case ASSURANCE_CONTRACT_PLEDGE: tx.setPurpose(Transaction.Purpose.ASSURANCE_CONTRACT_PLEDGE); break; case ASSURANCE_CONTRACT_STUB: tx.setPurpose(Transaction.Purpose.ASSURANCE_CONTRACT_STUB); break; default: throw new RuntimeException("New purpose serialization not implemented"); } } else { // Old wallet: assume a user payment as that's the only reason a new tx would have been // created back then. tx.setPurpose(Transaction.Purpose.USER_PAYMENT); } if (txProto.hasExchangeRate()) { Protos.ExchangeRate exchangeRateProto = txProto.getExchangeRate(); tx.setExchangeRate( new ExchangeRate( Coin.valueOf(exchangeRateProto.getCoinValue()), Fiat.valueOf( exchangeRateProto.getFiatCurrencyCode(), exchangeRateProto.getFiatValue()))); } if (txProto.hasMemo()) tx.setMemo(txProto.getMemo()); // Peercoin: Include time tx.setTime(txProto.getTime()); // Transaction should now be complete. Sha256Hash protoHash = byteStringToHash(txProto.getHash()); if (!tx.getHash().equals(protoHash)) throw new UnreadableWalletException( String.format( "Transaction did not deserialize completely: %s vs %s", tx.getHash(), protoHash)); if (txMap.containsKey(txProto.getHash())) throw new UnreadableWalletException( "Wallet contained duplicate transaction " + byteStringToHash(txProto.getHash())); txMap.put(txProto.getHash(), tx); }
private static Protos.Transaction makeTxProto(WalletTransaction wtx) { Transaction tx = wtx.getTransaction(); Protos.Transaction.Builder txBuilder = Protos.Transaction.newBuilder(); txBuilder .setPool(getProtoPool(wtx)) .setHash(hashToByteString(tx.getHash())) .setVersion((int) tx.getVersion()) .setTime(tx.getTime()); if (tx.getUpdateTime() != null) { txBuilder.setUpdatedAt(tx.getUpdateTime().getTime()); } if (tx.getLockTime() > 0) { txBuilder.setLockTime((int) tx.getLockTime()); } // Handle inputs. for (TransactionInput input : tx.getInputs()) { Protos.TransactionInput.Builder inputBuilder = Protos.TransactionInput.newBuilder() .setScriptBytes(ByteString.copyFrom(input.getScriptBytes())) .setTransactionOutPointHash(hashToByteString(input.getOutpoint().getHash())) .setTransactionOutPointIndex((int) input.getOutpoint().getIndex()); if (input.hasSequence()) inputBuilder.setSequence((int) input.getSequenceNumber()); if (input.getValue() != null) inputBuilder.setValue(input.getValue().value); txBuilder.addTransactionInput(inputBuilder); } // Handle outputs. for (TransactionOutput output : tx.getOutputs()) { Protos.TransactionOutput.Builder outputBuilder = Protos.TransactionOutput.newBuilder() .setScriptBytes(ByteString.copyFrom(output.getScriptBytes())) .setValue(output.getValue().value); final TransactionInput spentBy = output.getSpentBy(); if (spentBy != null) { Sha256Hash spendingHash = spentBy.getParentTransaction().getHash(); int spentByTransactionIndex = spentBy.getParentTransaction().getInputs().indexOf(spentBy); outputBuilder .setSpentByTransactionHash(hashToByteString(spendingHash)) .setSpentByTransactionIndex(spentByTransactionIndex); } txBuilder.addTransactionOutput(outputBuilder); } // Handle which blocks tx was seen in. final Map<Sha256Hash, Integer> appearsInHashes = tx.getAppearsInHashes(); if (appearsInHashes != null) { for (Map.Entry<Sha256Hash, Integer> entry : appearsInHashes.entrySet()) { txBuilder.addBlockHash(hashToByteString(entry.getKey())); txBuilder.addBlockRelativityOffsets(entry.getValue()); } } if (tx.hasConfidence()) { TransactionConfidence confidence = tx.getConfidence(); Protos.TransactionConfidence.Builder confidenceBuilder = Protos.TransactionConfidence.newBuilder(); writeConfidence(txBuilder, confidence, confidenceBuilder); } Protos.Transaction.Purpose purpose; switch (tx.getPurpose()) { case UNKNOWN: purpose = Protos.Transaction.Purpose.UNKNOWN; break; case USER_PAYMENT: purpose = Protos.Transaction.Purpose.USER_PAYMENT; break; case KEY_ROTATION: purpose = Protos.Transaction.Purpose.KEY_ROTATION; break; case ASSURANCE_CONTRACT_CLAIM: purpose = Protos.Transaction.Purpose.ASSURANCE_CONTRACT_CLAIM; break; case ASSURANCE_CONTRACT_PLEDGE: purpose = Protos.Transaction.Purpose.ASSURANCE_CONTRACT_PLEDGE; break; case ASSURANCE_CONTRACT_STUB: purpose = Protos.Transaction.Purpose.ASSURANCE_CONTRACT_STUB; break; default: throw new RuntimeException("New tx purpose serialization not implemented."); } txBuilder.setPurpose(purpose); ExchangeRate exchangeRate = tx.getExchangeRate(); if (exchangeRate != null) { Protos.ExchangeRate.Builder exchangeRateBuilder = Protos.ExchangeRate.newBuilder() .setCoinValue(exchangeRate.coin.value) .setFiatValue(exchangeRate.fiat.value) .setFiatCurrencyCode(exchangeRate.fiat.currencyCode); txBuilder.setExchangeRate(exchangeRateBuilder); } if (tx.getMemo() != null) txBuilder.setMemo(tx.getMemo()); return txBuilder.build(); }