Search in sources :

Example 1 with TxInput

use of bisq.core.dao.blockchain.vo.TxInput in project bisq-core by bisq-network.

the class TxInputsController method iterateInputs.

void iterateInputs(Tx tx, int blockHeight, Model model) {
    for (int inputIndex = 0; inputIndex < tx.getInputs().size(); inputIndex++) {
        TxInput input = tx.getInputs().get(inputIndex);
        txInputController.processInput(input, blockHeight, tx.getId(), inputIndex, model, writableBsqBlockChain);
    }
}
Also used : TxInput(bisq.core.dao.blockchain.vo.TxInput)

Example 2 with TxInput

use of bisq.core.dao.blockchain.vo.TxInput in project bisq-core by bisq-network.

the class RpcService method requestTx.

public Tx requestTx(String txId, int blockHeight) throws BsqBlockchainException {
    try {
        RawTransaction rawTransaction = requestRawTransaction(txId);
        // rawTransaction.getTime() is in seconds but we keep it in ms internally
        final long time = rawTransaction.getTime() * 1000;
        final List<TxInput> txInputs = rawTransaction.getVIn().stream().filter(rawInput -> rawInput != null && rawInput.getVOut() != null && rawInput.getTxId() != null).map(rawInput -> new TxInput(rawInput.getTxId(), rawInput.getVOut())).collect(Collectors.toList());
        final List<TxOutput> txOutputs = rawTransaction.getVOut().stream().filter(e -> e != null && e.getN() != null && e.getValue() != null && e.getScriptPubKey() != null).map(rawOutput -> {
            byte[] opReturnData = null;
            final com.neemre.btcdcli4j.core.domain.PubKeyScript scriptPubKey = rawOutput.getScriptPubKey();
            if (scriptPubKey.getType().equals(ScriptTypes.NULL_DATA)) {
                String[] chunks = scriptPubKey.getAsm().split(" ");
                // We get on testnet a lot of "OP_RETURN 0" data, so we filter those away
                if (chunks.length == 2 && chunks[0].equals("OP_RETURN") && !"0".equals(chunks[1])) {
                    try {
                        opReturnData = Utils.HEX.decode(chunks[1]);
                    } catch (Throwable t) {
                        // We get sometimes exceptions, seems BitcoinJ
                        // cannot handle all existing OP_RETURN data, but we ignore them
                        // anyway as our OP_RETURN data is valid in BitcoinJ
                        log.warn("Error at Utils.HEX.decode(chunks[1]): " + t.toString() + " / chunks[1]=" + chunks[1]);
                    }
                }
            }
            // We don't support raw MS which are the only case where scriptPubKey.getAddresses()>1
            String address = scriptPubKey.getAddresses() != null && scriptPubKey.getAddresses().size() == 1 ? scriptPubKey.getAddresses().get(0) : null;
            final PubKeyScript pubKeyScript = dumpBlockchainData ? new PubKeyScript(scriptPubKey) : null;
            return new TxOutput(rawOutput.getN(), rawOutput.getValue().movePointRight(8).longValue(), rawTransaction.getTxId(), pubKeyScript, address, opReturnData, blockHeight);
        }).collect(Collectors.toList());
        return new Tx(txId, blockHeight, rawTransaction.getBlockHash(), time, ImmutableList.copyOf(txInputs), ImmutableList.copyOf(txOutputs));
    } catch (BitcoindException | CommunicationException e) {
        log.error("error at requestTx with txId={}, blockHeight={}", txId, blockHeight);
        throw new BsqBlockchainException(e.getMessage(), e);
    }
}
Also used : BtcdClientImpl(com.neemre.btcdcli4j.core.client.BtcdClientImpl) Coin(org.bitcoinj.core.Coin) Inject(com.google.inject.Inject) LoggerFactory(org.slf4j.LoggerFactory) DaoOptionKeys(bisq.core.dao.DaoOptionKeys) RawTransaction(com.neemre.btcdcli4j.core.domain.RawTransaction) BtcdDaemonImpl(com.neemre.btcdcli4j.daemon.BtcdDaemonImpl) BigDecimal(java.math.BigDecimal) ImmutableList(com.google.common.collect.ImmutableList) Transaction(com.neemre.btcdcli4j.core.domain.Transaction) Map(java.util.Map) PoolingHttpClientConnectionManager(org.apache.http.impl.conn.PoolingHttpClientConnectionManager) PubKeyScript(bisq.core.dao.blockchain.btcd.PubKeyScript) BitcoindException(com.neemre.btcdcli4j.core.BitcoindException) Named(javax.inject.Named) TxInput(bisq.core.dao.blockchain.vo.TxInput) CloseableHttpClient(org.apache.http.impl.client.CloseableHttpClient) Properties(java.util.Properties) Logger(org.slf4j.Logger) Tx(bisq.core.dao.blockchain.vo.Tx) Utils(org.bitcoinj.core.Utils) CommunicationException(com.neemre.btcdcli4j.core.CommunicationException) ScriptTypes(com.neemre.btcdcli4j.core.domain.enums.ScriptTypes) BtcdClient(com.neemre.btcdcli4j.core.client.BtcdClient) TxOutput(bisq.core.dao.blockchain.vo.TxOutput) Collectors(java.util.stream.Collectors) BlockListener(com.neemre.btcdcli4j.daemon.event.BlockListener) Consumer(java.util.function.Consumer) Block(com.neemre.btcdcli4j.core.domain.Block) List(java.util.List) BsqBlockchainException(bisq.core.dao.blockchain.exceptions.BsqBlockchainException) BtcdDaemon(com.neemre.btcdcli4j.daemon.BtcdDaemon) HttpClients(org.apache.http.impl.client.HttpClients) TxOutput(bisq.core.dao.blockchain.vo.TxOutput) Tx(bisq.core.dao.blockchain.vo.Tx) CommunicationException(com.neemre.btcdcli4j.core.CommunicationException) PubKeyScript(bisq.core.dao.blockchain.btcd.PubKeyScript) TxInput(bisq.core.dao.blockchain.vo.TxInput) BsqBlockchainException(bisq.core.dao.blockchain.exceptions.BsqBlockchainException) RawTransaction(com.neemre.btcdcli4j.core.domain.RawTransaction) BitcoindException(com.neemre.btcdcli4j.core.BitcoindException)

Example 3 with TxInput

use of bisq.core.dao.blockchain.vo.TxInput in project bisq-core by bisq-network.

the class FullNodeParserTest method testIsBsqTx.

@Test
public void testIsBsqTx() {
    // Setup a basic transaction with two inputs
    int height = 200;
    String hash = "abc123";
    long time = new Date().getTime();
    Tx tx = new Tx("vo", height, hash, time, asList(new TxInput("tx1", 0), new TxInput("tx1", 1)), asList(new TxOutput(0, 101, "tx1", null, null, null, height)));
    // Return one spendable txoutputs with value, for three test cases
    // 1) - null, 0     -> not BSQ transaction
    // 2) - 100, null   -> BSQ transaction
    // 3) - 0, 100      -> BSQ transaction
    new Expectations(readModel) {

        {
            // Expectations can be recorded on mocked instances, either with specific matching arguments or catch all
            // http://jmockit.github.io/tutorial/Mocking.html#results
            // Results are returned in the order they're recorded, so in this case for the first call to
            // getSpendableTxOutput("tx1", 0) the return value will be Optional.empty()
            // for the second call the return is Optional.of(new TxOutput(0,... and so on
            readModel.getUnspentAndMatureTxOutput(new TxIdIndexTuple("tx1", 0));
            result = Optional.empty();
            result = Optional.of(new TxOutput(0, 100, "txout1", null, null, null, height));
            result = Optional.of(new TxOutput(0, 0, "txout1", null, null, null, height));
            readModel.getUnspentAndMatureTxOutput(new TxIdIndexTuple("tx1", 1));
            result = Optional.of(new TxOutput(0, 0, "txout2", null, null, null, height));
            result = Optional.empty();
            result = Optional.of(new TxOutput(0, 100, "txout2", null, null, null, height));
        }
    };
    // First time there is no BSQ value to spend so it's not a bsq transaction
    assertFalse(bsqTxController.isBsqTx(height, tx));
    // Second time there is BSQ in the first txout
    assertTrue(bsqTxController.isBsqTx(height, tx));
    // Third time there is BSQ in the second txout
    assertTrue(bsqTxController.isBsqTx(height, tx));
}
Also used : Expectations(mockit.Expectations) TxOutput(bisq.core.dao.blockchain.vo.TxOutput) Tx(bisq.core.dao.blockchain.vo.Tx) TxIdIndexTuple(bisq.core.dao.blockchain.vo.util.TxIdIndexTuple) Date(java.util.Date) TxInput(bisq.core.dao.blockchain.vo.TxInput) Test(org.junit.Test)

Example 4 with TxInput

use of bisq.core.dao.blockchain.vo.TxInput in project bisq-core by bisq-network.

the class FullNodeParserTest method testParseBlocks.

@Test
public void testParseBlocks() throws BitcoindException, CommunicationException, BlockNotConnectingException, BsqBlockchainException {
    // Setup blocks to test, starting before genesis
    // Only the transactions related to bsq are relevant, no checks are done on correctness of blocks or other txs
    // so hashes and most other data don't matter
    long time = new Date().getTime();
    int genesisHeight = 200;
    int startHeight = 199;
    int headHeight = 201;
    Coin issuance = Coin.parseCoin("2.5");
    // Blockhashes
    String bh199 = "blockhash199";
    String bh200 = "blockhash200";
    String bh201 = "blockhash201";
    // Block 199
    String cbId199 = "cbid199";
    Tx cbTx199 = new Tx(cbId199, 199, bh199, time, new ArrayList<TxInput>(), asList(new TxOutput(0, 25, cbId199, null, null, null, 199)));
    Block block199 = new Block(bh199, 10, 10, 199, 2, "root", asList(cbId199), time, Long.parseLong("1234"), "bits", BigDecimal.valueOf(1), "chainwork", "previousBlockHash", bh200);
    // Genesis Block
    String cbId200 = "cbid200";
    Tx cbTx200 = new Tx(cbId200, 200, bh200, time, new ArrayList<TxInput>(), asList(new TxOutput(0, 25, cbId200, null, null, null, 200)));
    Tx genesisTx = new Tx(genesisTxId, 200, bh200, time, asList(new TxInput("someoldtx", 0)), asList(new TxOutput(0, issuance.getValue(), genesisTxId, null, null, null, 200)));
    Block block200 = new Block(bh200, 10, 10, 200, 2, "root", asList(cbId200, genesisTxId), time, Long.parseLong("1234"), "bits", BigDecimal.valueOf(1), "chainwork", bh199, bh201);
    // Block 201
    // Make a bsq transaction
    String cbId201 = "cbid201";
    String bsqTx1Id = "bsqtx1";
    long bsqTx1Value1 = Coin.parseCoin("2.4").getValue();
    long bsqTx1Value2 = Coin.parseCoin("0.04").getValue();
    Tx cbTx201 = new Tx(cbId201, 201, bh201, time, new ArrayList<TxInput>(), asList(new TxOutput(0, 25, cbId201, null, null, null, 201)));
    Tx bsqTx1 = new Tx(bsqTx1Id, 201, bh201, time, asList(new TxInput(genesisTxId, 0)), asList(new TxOutput(0, bsqTx1Value1, bsqTx1Id, null, null, null, 201), new TxOutput(1, bsqTx1Value2, bsqTx1Id, null, null, null, 201)));
    Block block201 = new Block(bh201, 10, 10, 201, 2, "root", asList(cbId201, bsqTx1Id), time, Long.parseLong("1234"), "bits", BigDecimal.valueOf(1), "chainwork", bh200, "nextBlockHash");
    new Expectations(rpcService) {

        {
            rpcService.requestBlock(199);
            result = block199;
            rpcService.requestBlock(200);
            result = block200;
            rpcService.requestBlock(201);
            result = block201;
            rpcService.requestTx(cbId199, 199);
            result = cbTx199;
            rpcService.requestTx(cbId200, genesisHeight);
            result = cbTx200;
            rpcService.requestTx(genesisTxId, genesisHeight);
            result = genesisTx;
            rpcService.requestTx(cbId201, 201);
            result = cbTx201;
            rpcService.requestTx(bsqTx1Id, 201);
            result = bsqTx1;
        }
    };
    // Running parseBlocks to build the bsq blockchain
    fullNodeParser.parseBlocks(startHeight, headHeight, block -> {
    });
    // Verify that the genesis tx has been added to the bsq blockchain with the correct issuance amount
    assertTrue(readModel.getGenesisTx() == genesisTx);
    assertTrue(readModel.getIssuedAmountAtGenesis().getValue() == issuance.getValue());
    // And that other txs are not added
    assertFalse(readModel.containsTx(cbId199));
    assertFalse(readModel.containsTx(cbId200));
    assertFalse(readModel.containsTx(cbId201));
    // But bsq txs are added
    assertTrue(readModel.containsTx(bsqTx1Id));
    TxOutput bsqOut1 = readModel.getUnspentAndMatureTxOutput(bsqTx1Id, 0).get();
    assertTrue(bsqOut1.isUnspent());
    assertTrue(bsqOut1.getValue() == bsqTx1Value1);
    TxOutput bsqOut2 = readModel.getUnspentAndMatureTxOutput(bsqTx1Id, 1).get();
    assertTrue(bsqOut2.isUnspent());
    assertTrue(bsqOut2.getValue() == bsqTx1Value2);
    assertFalse(readModel.isTxOutputSpendable(genesisTxId, 0));
    assertTrue(readModel.isTxOutputSpendable(bsqTx1Id, 0));
    assertTrue(readModel.isTxOutputSpendable(bsqTx1Id, 1));
}
Also used : Expectations(mockit.Expectations) Coin(org.bitcoinj.core.Coin) TxOutput(bisq.core.dao.blockchain.vo.TxOutput) Tx(bisq.core.dao.blockchain.vo.Tx) Block(com.neemre.btcdcli4j.core.domain.Block) Date(java.util.Date) TxInput(bisq.core.dao.blockchain.vo.TxInput) Test(org.junit.Test)

Aggregations

TxInput (bisq.core.dao.blockchain.vo.TxInput)4 Tx (bisq.core.dao.blockchain.vo.Tx)3 TxOutput (bisq.core.dao.blockchain.vo.TxOutput)3 Block (com.neemre.btcdcli4j.core.domain.Block)2 Date (java.util.Date)2 Expectations (mockit.Expectations)2 Coin (org.bitcoinj.core.Coin)2 Test (org.junit.Test)2 DaoOptionKeys (bisq.core.dao.DaoOptionKeys)1 PubKeyScript (bisq.core.dao.blockchain.btcd.PubKeyScript)1 BsqBlockchainException (bisq.core.dao.blockchain.exceptions.BsqBlockchainException)1 TxIdIndexTuple (bisq.core.dao.blockchain.vo.util.TxIdIndexTuple)1 ImmutableList (com.google.common.collect.ImmutableList)1 Inject (com.google.inject.Inject)1 BitcoindException (com.neemre.btcdcli4j.core.BitcoindException)1 CommunicationException (com.neemre.btcdcli4j.core.CommunicationException)1 BtcdClient (com.neemre.btcdcli4j.core.client.BtcdClient)1 BtcdClientImpl (com.neemre.btcdcli4j.core.client.BtcdClientImpl)1 RawTransaction (com.neemre.btcdcli4j.core.domain.RawTransaction)1 Transaction (com.neemre.btcdcli4j.core.domain.Transaction)1