co.rsk.peg.BridgeUtils.java Source code

Java tutorial

Introduction

Here is the source code for co.rsk.peg.BridgeUtils.java

Source

/*
 * This file is part of RskJ
 * Copyright (C) 2017 RSK Labs Ltd.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package co.rsk.peg;

import co.rsk.config.BridgeConstants;
import org.apache.commons.lang3.StringUtils;
import co.rsk.bitcoinj.core.*;
import co.rsk.bitcoinj.script.Script;
import co.rsk.bitcoinj.store.BtcBlockStore;
import co.rsk.bitcoinj.store.BlockStoreException;
import org.ethereum.config.BlockchainNetConfig;
import org.ethereum.config.SystemProperties;
import org.ethereum.vm.PrecompiledContracts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;

public class BridgeUtils {

    private static final Logger logger = LoggerFactory.getLogger("BridgeUtils");

    public static StoredBlock getStoredBlockAtHeight(BtcBlockStore blockStore, int height)
            throws BlockStoreException {
        StoredBlock storedBlock = blockStore.getChainHead();
        int headHeight = storedBlock.getHeight();
        if (height > headHeight) {
            return null;
        }
        for (int i = 0; i < (headHeight - height); i++) {
            if (storedBlock == null)
                return null;
            Sha256Hash prevBlockHash = storedBlock.getHeader().getPrevBlockHash();
            storedBlock = blockStore.get(prevBlockHash);
        }
        if (storedBlock != null) {
            if (storedBlock.getHeight() != height) {
                throw new IllegalStateException(
                        "Block height is " + storedBlock.getHeight() + " but should be " + headHeight);
            }
            return storedBlock;
        } else {
            return null;
        }
    }

    public static boolean isLockTx(BtcTransaction tx, TransactionBag wallet, BridgeConstants bridgeConstants) {
        // First, check tx is not a typical release tx (tx spending from the federation address and
        // optionally sending some change to the federation address)
        int i = 0;
        for (TransactionInput transactionInput : tx.getInputs()) {
            try {
                transactionInput.getScriptSig().correctlySpends(tx, i, bridgeConstants.getFederationPubScript(),
                        Script.ALL_VERIFY_FLAGS);
                // There is an input spending from the federation address, this is not a lock tx
                return false;
            } catch (ScriptException se) {
                // do-nothing, input does not spends from the federation address
            }
            i++;
        }
        Coin valueSentToMe = tx.getValueSentToMe(wallet);

        int valueSentToMeSignum = valueSentToMe.signum();
        if (valueSentToMe.isLessThan(bridgeConstants.getMinimumLockTxValue())) {
            logger.warn("Someone sent to the federation less than {} satoshis",
                    bridgeConstants.getMinimumLockTxValue());
        }
        return (valueSentToMeSignum > 0 && !valueSentToMe.isLessThan(bridgeConstants.getMinimumLockTxValue()));
    }

    public static boolean isReleaseTx(BtcTransaction tx, BridgeConstants bridgeConstants) {
        int i = 0;
        for (TransactionInput transactionInput : tx.getInputs()) {
            try {
                transactionInput.getScriptSig().correctlySpends(tx, i, bridgeConstants.getFederationPubScript(),
                        Script.ALL_VERIFY_FLAGS);
                // There is an input spending from the federation address, this is a release tx
                return true;
            } catch (ScriptException se) {
                // do-nothing, input does not spends from the federation address
            }
            i++;
        }
        return false;
    }

    public static Address recoverBtcAddressFromEthTransaction(org.ethereum.core.Transaction tx,
            NetworkParameters networkParameters) {
        org.ethereum.crypto.ECKey key = tx.getKey();
        byte[] pubKey = key.getPubKey(true);
        return BtcECKey.fromPublicOnly(pubKey).toAddress(networkParameters);
    }

    public static boolean isFreeBridgeTx(org.ethereum.core.Transaction rskTx, long blockNumber) {
        BlockchainNetConfig blockchainConfig = SystemProperties.CONFIG.getBlockchainConfig();
        byte[] receiveAddress = rskTx.getReceiveAddress();

        if (receiveAddress == null)
            return false;

        return StringUtils.equals(Hex.toHexString(receiveAddress), PrecompiledContracts.BRIDGE_ADDR)
                && blockchainConfig.getConfigForBlock(blockNumber).areBridgeTxsFree()
                && rskTx.getSignature() != null
                && blockchainConfig.getCommonConstants().getBridgeConstants().getFederatorPublicKeys()
                        .contains(co.rsk.bitcoinj.core.BtcECKey.fromPublicOnly(rskTx.getKey().getPubKey()));
    }
}