Search in sources :

Example 71 with Transaction

use of org.ethereum.core.Transaction in project eth-propeller-ethj by adridadou.

the class EthereumTest method submit.

@Override
public EthHash submit(TransactionRequest request, Nonce nonce) {
    Transaction tx = createTransaction(request, nonce);
    this.transactions.add(tx);
    return EthHash.of(tx.getHash());
}
Also used : Transaction(org.ethereum.core.Transaction)

Example 72 with Transaction

use of org.ethereum.core.Transaction in project rskj by rsksmart.

the class BridgeSupport method registerBtcTransaction.

/**
 * In case of a lock tx: Transfers some SBTCs to the sender of the btc tx and keeps track of the new UTXOs available for spending.
 * In case of a release tx: Keeps track of the change UTXOs, now available for spending.
 * @param btcTx The bitcoin transaction
 * @param height The height of the bitcoin block that contains the tx
 * @param pmt Partial Merklee Tree that proves the tx is included in the btc block
 * @throws BlockStoreException
 * @throws IOException
 */
public void registerBtcTransaction(Transaction rskTx, BtcTransaction btcTx, int height, PartialMerkleTree pmt) throws BlockStoreException, IOException {
    Context.propagate(btcContext);
    Federation federation = getActiveFederation();
    // Check the tx was not already processed
    if (provider.getBtcTxHashesAlreadyProcessed().keySet().contains(btcTx.getHash())) {
        logger.warn("Supplied tx was already processed");
        return;
    }
    // Check the tx is in the partial merkle tree
    List<Sha256Hash> hashesInPmt = new ArrayList<>();
    Sha256Hash merkleRoot = pmt.getTxnHashAndMerkleRoot(hashesInPmt);
    if (!hashesInPmt.contains(btcTx.getHash())) {
        logger.warn("Supplied tx is not in the supplied partial merkle tree");
        panicProcessor.panic("btclock", "Supplied tx is not in the supplied partial merkle tree");
        return;
    }
    if (height < 0) {
        logger.warn("Height is " + height + " but should be greater than 0");
        panicProcessor.panic("btclock", "Height is " + height + " but should be greater than 0");
        return;
    }
    // Check there are at least N blocks on top of the supplied height
    int headHeight = btcBlockChain.getBestChainHeight();
    if ((headHeight - height + 1) < bridgeConstants.getBtc2RskMinimumAcceptableConfirmations()) {
        logger.warn("At least " + bridgeConstants.getBtc2RskMinimumAcceptableConfirmations() + " confirmations are required, but there are only " + (headHeight - height) + " confirmations");
        return;
    }
    // Check the the merkle root equals merkle root of btc block at specified height in the btc best chain
    BtcBlock blockHeader = BridgeUtils.getStoredBlockAtHeight(btcBlockStore, height).getHeader();
    if (!blockHeader.getMerkleRoot().equals(merkleRoot)) {
        logger.warn("Supplied merkle root " + merkleRoot + "does not match block's merkle root " + blockHeader.getMerkleRoot());
        panicProcessor.panic("btclock", "Supplied merkle root " + merkleRoot + "does not match block's merkle root " + blockHeader.getMerkleRoot());
        return;
    }
    // Checks the transaction contents for sanity
    btcTx.verify();
    if (btcTx.getInputs().isEmpty()) {
        logger.warn("Tx has no inputs " + btcTx);
        panicProcessor.panic("btclock", "Tx has no inputs " + btcTx);
        return;
    }
    boolean locked = true;
    // Specific code for lock/release/none txs
    if (BridgeUtils.isLockTx(btcTx, getLiveFederations(), btcContext, bridgeConstants)) {
        logger.debug("This is a lock tx {}", btcTx);
        Script scriptSig = btcTx.getInput(0).getScriptSig();
        if (scriptSig.getChunks().size() != 2) {
            logger.warn("First input does not spend a Pay-to-PubkeyHash " + btcTx.getInput(0));
            panicProcessor.panic("btclock", "First input does not spend a Pay-to-PubkeyHash " + btcTx.getInput(0));
            return;
        }
        // Compute the total amount sent. Value could have been sent both to the
        // currently active federation as well as to the currently retiring federation.
        // Add both amounts up in that case.
        Coin amountToActive = btcTx.getValueSentToMe(getActiveFederationWallet());
        Coin amountToRetiring = Coin.ZERO;
        Wallet retiringFederationWallet = getRetiringFederationWallet();
        if (retiringFederationWallet != null) {
            amountToRetiring = btcTx.getValueSentToMe(retiringFederationWallet);
        }
        Coin totalAmount = amountToActive.add(amountToRetiring);
        // Get the sender public key
        byte[] data = scriptSig.getChunks().get(1).data;
        // Tx is a lock tx, check whether the sender is whitelisted
        BtcECKey senderBtcKey = BtcECKey.fromPublicOnly(data);
        Address senderBtcAddress = new Address(btcContext.getParams(), senderBtcKey.getPubKeyHash());
        // If the address is not whitelisted, then return the funds
        // using the exact same utxos sent to us.
        // That is, build a release transaction and get it in the release transaction set.
        // Otherwise, transfer SBTC to the sender of the BTC
        // The RSK account to update is the one that matches the pubkey "spent" on the first bitcoin tx input
        LockWhitelist lockWhitelist = provider.getLockWhitelist();
        if (!lockWhitelist.isWhitelistedFor(senderBtcAddress, totalAmount, height)) {
            locked = false;
            // Build the list of UTXOs in the BTC transaction sent to either the active
            // or retiring federation
            List<UTXO> utxosToUs = btcTx.getWalletOutputs(getNoSpendWalletForLiveFederations()).stream().map(output -> new UTXO(btcTx.getHash(), output.getIndex(), output.getValue(), 0, btcTx.isCoinBase(), output.getScriptPubKey())).collect(Collectors.toList());
            // Use the list of UTXOs to build a transaction builder
            // for the return btc transaction generation
            ReleaseTransactionBuilder txBuilder = new ReleaseTransactionBuilder(btcContext.getParams(), getUTXOBasedWalletForLiveFederations(utxosToUs), senderBtcAddress, getFeePerKb());
            Optional<ReleaseTransactionBuilder.BuildResult> buildReturnResult = txBuilder.buildEmptyWalletTo(senderBtcAddress);
            if (buildReturnResult.isPresent()) {
                provider.getReleaseTransactionSet().add(buildReturnResult.get().getBtcTx(), rskExecutionBlock.getNumber());
                logger.info("whitelist money return tx build successful to {}. Tx {}. Value {}.", senderBtcAddress, rskTx, totalAmount);
            } else {
                logger.warn("whitelist money return tx build for btc tx {} error. Return was to {}. Tx {}. Value {}", btcTx.getHash(), senderBtcAddress, rskTx, totalAmount);
                panicProcessor.panic("whitelist-return-funds", String.format("whitelist money return tx build for btc tx {} error. Return was to {}. Tx {}. Value {}", btcTx.getHash(), senderBtcAddress, rskTx, totalAmount));
            }
        } else {
            org.ethereum.crypto.ECKey key = org.ethereum.crypto.ECKey.fromPublicOnly(data);
            RskAddress sender = new RskAddress(key.getAddress());
            rskRepository.transfer(PrecompiledContracts.BRIDGE_ADDR, sender, co.rsk.core.Coin.fromBitcoin(totalAmount));
            lockWhitelist.remove(senderBtcAddress);
        }
    } else if (BridgeUtils.isReleaseTx(btcTx, federation, bridgeConstants)) {
        logger.debug("This is a release tx {}", btcTx);
    // do-nothing
    // We could call removeUsedUTXOs(btcTx) here, but we decided to not do that.
    // Used utxos should had been removed when we created the release tx.
    // Invoking removeUsedUTXOs() here would make "some" sense in theses scenarios:
    // a) In testnet, devnet or local: we restart the RSK blockchain whithout changing the federation address. We don't want to have utxos that were already spent.
    // Open problem: TxA spends TxB. registerBtcTransaction() for TxB is called, it spends a utxo the bridge is not yet aware of,
    // so nothing is removed. Then registerBtcTransaction() for TxA and the "already spent" utxo is added as it was not spent.
    // When is not guaranteed to be called in the chronological order, so a Federator can inform
    // b) In prod: Federator created a tx manually or the federation was compromised and some utxos were spent. Better not try to spend them.
    // Open problem: For performance removeUsedUTXOs() just removes 1 utxo
    } else if (BridgeUtils.isMigrationTx(btcTx, getActiveFederation(), getRetiringFederation(), btcContext, bridgeConstants)) {
        logger.debug("This is a migration tx {}", btcTx);
    } else {
        logger.warn("This is not a lock, a release nor a migration tx {}", btcTx);
        panicProcessor.panic("btclock", "This is not a lock, a release nor a migration tx " + btcTx);
        return;
    }
    Sha256Hash btcTxHash = btcTx.getHash();
    // Mark tx as processed on this block
    provider.getBtcTxHashesAlreadyProcessed().put(btcTxHash, rskExecutionBlock.getNumber());
    // locked the funds.
    if (locked) {
        saveNewUTXOs(btcTx);
    }
    logger.info("BTC Tx {} processed in RSK", btcTxHash);
}
Also used : java.util(java.util) Hex(org.spongycastle.util.encoders.Hex) LoggerFactory(org.slf4j.LoggerFactory) RskAddress(co.rsk.core.RskAddress) Keccak256(co.rsk.crypto.Keccak256) Block(org.ethereum.core.Block) TransactionSignature(co.rsk.bitcoinj.crypto.TransactionSignature) Pair(org.apache.commons.lang3.tuple.Pair) BridgeConstants(co.rsk.config.BridgeConstants) co.rsk.bitcoinj.core(co.rsk.bitcoinj.core) PrecompiledContracts(org.ethereum.vm.PrecompiledContracts) BigInteger(java.math.BigInteger) Nullable(javax.annotation.Nullable) Wallet(co.rsk.bitcoinj.wallet.Wallet) BtcBlockStore(co.rsk.bitcoinj.store.BtcBlockStore) PanicProcessor(co.rsk.panic.PanicProcessor) ScriptChunk(co.rsk.bitcoinj.script.ScriptChunk) Logger(org.slf4j.Logger) IOException(java.io.IOException) Instant(java.time.Instant) Repository(org.ethereum.core.Repository) Collectors(java.util.stream.Collectors) SendRequest(co.rsk.bitcoinj.wallet.SendRequest) Program(org.ethereum.vm.program.Program) ScriptBuilder(co.rsk.bitcoinj.script.ScriptBuilder) Script(co.rsk.bitcoinj.script.Script) BlockStoreException(co.rsk.bitcoinj.store.BlockStoreException) VisibleForTesting(com.google.common.annotations.VisibleForTesting) RskSystemProperties(co.rsk.config.RskSystemProperties) BridgeEventLogger(co.rsk.peg.utils.BridgeEventLogger) Transaction(org.ethereum.core.Transaction) InputStream(java.io.InputStream) Script(co.rsk.bitcoinj.script.Script) RskAddress(co.rsk.core.RskAddress) Wallet(co.rsk.bitcoinj.wallet.Wallet) RskAddress(co.rsk.core.RskAddress)

Example 73 with Transaction

use of org.ethereum.core.Transaction in project rskj by rsksmart.

the class PersonalModuleWalletEnabled method sendTransaction.

private String sendTransaction(Web3.CallArguments args, Account account) throws Exception {
    if (account == null) {
        throw new Exception("From address private key could not be found in this node");
    }
    String toAddress = args.to != null ? Hex.toHexString(TypeConverter.stringHexToByteArray(args.to)) : null;
    BigInteger accountNonce = args.nonce != null ? TypeConverter.stringNumberAsBigInt(args.nonce) : transactionPool.getRepository().getNonce(account.getAddress());
    BigInteger value = args.value != null ? TypeConverter.stringNumberAsBigInt(args.value) : BigInteger.ZERO;
    BigInteger gasPrice = args.gasPrice != null ? TypeConverter.stringNumberAsBigInt(args.gasPrice) : BigInteger.ZERO;
    BigInteger gasLimit = args.gas != null ? TypeConverter.stringNumberAsBigInt(args.gas) : BigInteger.valueOf(GasCost.TRANSACTION);
    if (args.data != null && args.data.startsWith("0x")) {
        args.data = args.data.substring(2);
    }
    Transaction tx = Transaction.create(config, toAddress, value, accountNonce, gasPrice, gasLimit, args.data);
    tx.sign(account.getEcKey().getPrivKeyBytes());
    eth.submitTransaction(tx);
    return tx.getHash().toJsonString();
}
Also used : Transaction(org.ethereum.core.Transaction) BigInteger(java.math.BigInteger) JsonRpcInvalidParamException(org.ethereum.rpc.exception.JsonRpcInvalidParamException)

Example 74 with Transaction

use of org.ethereum.core.Transaction in project rskj by rsksmart.

the class TxPoolModuleImpl method inspect.

/**
 * This method should return 2 dictionaries containing pending and queued transactions
 * Each entry is an origin-address to a batch of scheduled transactions
 * These batches themselves are maps associating nonces with transactions summary strings.
 * When there are no transactions the answer would be
 * "{"pending": {}, "queued": {}}"
 */
@Override
public String inspect() {
    Map<String, JsonNode> contentProps = new HashMap<>();
    Map<RskAddress, Map<BigInteger, List<Transaction>>> pendingGrouped = groupTransactions(transactionPool.getPendingTransactions());
    Map<RskAddress, Map<BigInteger, List<Transaction>>> queuedGrouped = groupTransactions(transactionPool.getQueuedTransactions());
    contentProps.put(PENDING, serializeTransactions(pendingGrouped, this::summarySerializer));
    contentProps.put(QUEUED, serializeTransactions(queuedGrouped, this::summarySerializer));
    JsonNode node = jsonNodeFactory.objectNode().setAll(contentProps);
    return node.toString();
}
Also used : Transaction(org.ethereum.core.Transaction) RskAddress(co.rsk.core.RskAddress) JsonNode(com.fasterxml.jackson.databind.JsonNode)

Example 75 with Transaction

use of org.ethereum.core.Transaction in project rskj by rsksmart.

the class TxPoolModuleImpl method groupTransactions.

private Map<RskAddress, Map<BigInteger, List<Transaction>>> groupTransactions(List<Transaction> transactions) {
    Map<RskAddress, Map<BigInteger, List<Transaction>>> groupedTransactions = new HashMap<>();
    for (Transaction tx : transactions) {
        Map<BigInteger, List<Transaction>> txsBySender = groupedTransactions.get(tx.getSender());
        if (txsBySender == null) {
            txsBySender = new HashMap<>();
            groupedTransactions.put(tx.getSender(), txsBySender);
        }
        List<Transaction> txsByNonce = txsBySender.get(tx.getNonceAsInteger());
        if (txsByNonce == null) {
            List<Transaction> txs = new ArrayList<>();
            txs.add(tx);
            txsBySender.put(tx.getNonceAsInteger(), txs);
        } else {
            txsByNonce.add(tx);
        }
    }
    return groupedTransactions;
}
Also used : Transaction(org.ethereum.core.Transaction) RskAddress(co.rsk.core.RskAddress) BigInteger(java.math.BigInteger)

Aggregations

Transaction (org.ethereum.core.Transaction)131 Test (org.junit.Test)82 BigInteger (java.math.BigInteger)33 Coin (co.rsk.core.Coin)23 Account (org.ethereum.core.Account)20 ArrayList (java.util.ArrayList)17 Block (org.ethereum.core.Block)17 RskAddress (co.rsk.core.RskAddress)15 JsonNode (com.fasterxml.jackson.databind.JsonNode)15 Repository (org.ethereum.core.Repository)12 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)11 AccountState (org.ethereum.core.AccountState)10 RemascTransaction (co.rsk.remasc.RemascTransaction)9 TransactionBuilder (co.rsk.test.builders.TransactionBuilder)9 ImmutableTransaction (org.ethereum.core.ImmutableTransaction)8 ECKey (org.ethereum.crypto.ECKey)8 Keccak256 (co.rsk.crypto.Keccak256)7 AccountBuilder (co.rsk.test.builders.AccountBuilder)7 DslParser (co.rsk.test.dsl.DslParser)6 WorldDslProcessor (co.rsk.test.dsl.WorldDslProcessor)6