Search in sources :

Example 1 with Script

use of io.nuls.kernel.script.Script in project nuls by nuls-io.

the class AccountLedgerResource method createTransactionSimple.

@POST
@Path("/transaction/simple")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "创建转账交易(不用计算手续费)", notes = "返回交易Hash,交易对象序列化数组Hex编码,本次交易的输入,输出")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success") })
public RpcClientResult createTransactionSimple(@ApiParam(name = "form", value = "转账参数(传入该账户拥有的UTXO)", required = true) TransferSimpleForm form) {
    try {
        if (form == null) {
            return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
        }
        if (form.getUtxos() == null || form.getUtxos().isEmpty()) {
            return RpcClientResult.getFailed("inputs error");
        }
        if (!AddressTool.validAddress(form.getAddress())) {
            return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
        }
        if (!AddressTool.validAddress(form.getToAddress())) {
            return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
        }
        if (form.getAmount() <= 0) {
            return Result.getFailed(AccountLedgerErrorCode.PARAMETER_ERROR).toRpcClientResult();
        }
        byte[] remarkBytes = new byte[0];
        if (form.getRemark() != null && form.getRemark().length() > 0) {
            try {
                remarkBytes = form.getRemark().getBytes(NulsConfig.DEFAULT_ENCODING);
            } catch (UnsupportedEncodingException e) {
                return Result.getFailed(AccountLedgerErrorCode.PARAMETER_ERROR).toRpcClientResult();
            }
        }
        byte[] fromBytes = AddressTool.getAddress(form.getAddress());
        byte[] toBytes = AddressTool.getAddress(form.getToAddress());
        Na values = Na.valueOf(form.getAmount());
        TransferTransaction tx = new TransferTransaction();
        tx.setRemark(remarkBytes);
        tx.setTime(TimeService.currentTimeMillis());
        CoinData coinData = new CoinData();
        // 如果为多签地址则以脚本方式存储
        Coin toCoin;
        if (toBytes[2] == NulsContext.P2SH_ADDRESS_TYPE) {
            Script scriptPubkey = SignatureUtil.createOutputScript(toBytes);
            toCoin = new Coin(scriptPubkey.getProgram(), values);
        } else {
            toCoin = new Coin(toBytes, values);
        }
        coinData.getTo().add(toCoin);
        List<Coin> coinList = ConvertCoinTool.convertCoinList(form.getUtxos());
        CoinDataResult coinDataResult = getCoinData(fromBytes, values, tx.size() + coinData.size(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES, coinList);
        if (!coinDataResult.isEnough()) {
            return Result.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE).toRpcClientResult();
        }
        coinData.setFrom(coinDataResult.getCoinList());
        // 找零的UTXO
        if (coinDataResult.getChange() != null) {
            coinData.getTo().add(coinDataResult.getChange());
        }
        tx.setCoinData(coinData);
        // 重置为0,重新计算交易对象的size
        tx.setSize(0);
        if (tx.getSize() > TxMaxSizeValidator.MAX_TX_SIZE) {
            return Result.getFailed(TransactionErrorCode.DATA_SIZE_ERROR).toRpcClientResult();
        }
        TransactionCreatedReturnInfo returnInfo = LedgerRpcUtil.makeReturnInfo(tx);
        Map<String, TransactionCreatedReturnInfo> map = new HashMap<>();
        map.put("value", returnInfo);
        return Result.getSuccess().setData(map).toRpcClientResult();
    } catch (Exception e) {
        Log.error(e);
        return Result.getFailed(AccountLedgerErrorCode.SYS_UNKOWN_EXCEPTION).toRpcClientResult();
    }
}
Also used : Script(io.nuls.kernel.script.Script) UnsupportedEncodingException(java.io.UnsupportedEncodingException) CryptoException(io.nuls.core.tools.crypto.Exception.CryptoException) NulsException(io.nuls.kernel.exception.NulsException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) IOException(java.io.IOException) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Example 2 with Script

use of io.nuls.kernel.script.Script in project nuls by nuls-io.

the class AccountLedgerResource method createMultipleTx.

@POST
@Path("/createMultipleTx")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "创建多账户转账交易", notes = "result.data: resultJson 返回交易Hex")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success") })
public RpcClientResult createMultipleTx(@ApiParam(name = "form", value = "交易输入输出", required = true) TransactionForm form) {
    if (form.getInputs() == null || form.getInputs().isEmpty()) {
        return RpcClientResult.getFailed("inputs error");
    }
    if (form.getOutputs() == null || form.getOutputs().isEmpty()) {
        return RpcClientResult.getFailed("outputs error");
    }
    byte[] remark = null;
    if (!StringUtils.isBlank(form.getRemark())) {
        try {
            remark = form.getRemark().getBytes(NulsConfig.DEFAULT_ENCODING);
        } catch (UnsupportedEncodingException e) {
            return RpcClientResult.getFailed("remark error");
        }
    }
    List<Coin> outputList = new ArrayList<>();
    for (int i = 0; i < form.getOutputs().size(); i++) {
        OutputDto outputDto = form.getOutputs().get(i);
        Coin to = new Coin();
        try {
            if (!AddressTool.validAddress(outputDto.getAddress())) {
                return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
            }
            byte[] owner = AddressTool.getAddress(outputDto.getAddress());
            if (owner[2] == 3) {
                Script scriptPubkey = SignatureUtil.createOutputScript(to.getAddress());
                to.setOwner(scriptPubkey.getProgram());
            } else {
                to.setOwner(AddressTool.getAddress(outputDto.getAddress()));
            }
        } catch (Exception e) {
            return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
        }
        try {
            to.setNa(Na.valueOf(outputDto.getValue()));
        } catch (Exception e) {
            return Result.getFailed(AccountErrorCode.DATA_PARSE_ERROR).toRpcClientResult();
        }
        if (outputDto.getLockTime() < 0) {
            return RpcClientResult.getFailed("lockTime error");
        }
        to.setLockTime(outputDto.getLockTime());
        outputList.add(to);
    }
    List<Coin> inputsList = new ArrayList<>();
    Set<String> addressSet = new HashSet<>();
    for (int i = 0; i < form.getInputs().size(); i++) {
        InputDto inputDto = form.getInputs().get(i);
        if (inputDto.getAddress() == null) {
            return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
        }
        addressSet.add(inputDto.getAddress());
        byte[] key = Arrays.concatenate(Hex.decode(inputDto.getFromHash()), new VarInt(inputDto.getFromIndex()).encode());
        Coin coin = new Coin();
        coin.setOwner(key);
        coin.setNa(Na.valueOf(inputDto.getValue()));
        coin.setLockTime(inputDto.getLockTime());
        inputsList.add(coin);
    }
    TransferTransaction tx = new TransferTransaction();
    CoinData coinData = new CoinData();
    coinData.setFrom(inputsList);
    coinData.setTo(outputList);
    tx.setCoinData(coinData);
    tx.setTime(TimeService.currentTimeMillis());
    tx.setRemark(remark);
    if (!isFeeEnough(tx, P2PHKSignature.SERIALIZE_LENGTH * addressSet.size())) {
        return Result.getFailed(TransactionErrorCode.FEE_NOT_RIGHT).toRpcClientResult();
    }
    try {
        String txHex = Hex.encode(tx.serialize());
        Map<String, String> map = new HashMap<>();
        map.put("value", txHex);
        return Result.getSuccess().setData(map).toRpcClientResult();
    } catch (IOException e) {
        Log.error(e);
        return RpcClientResult.getFailed(e.getMessage());
    }
}
Also used : Script(io.nuls.kernel.script.Script) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) CryptoException(io.nuls.core.tools.crypto.Exception.CryptoException) NulsException(io.nuls.kernel.exception.NulsException) UnsupportedEncodingException(java.io.UnsupportedEncodingException) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) IOException(java.io.IOException) TransferTransaction(io.nuls.protocol.model.tx.TransferTransaction)

Example 3 with Script

use of io.nuls.kernel.script.Script in project nuls by nuls-io.

the class UtxoLedgerServiceImpl method verifyCoinData.

/**
 * 此txList是待打包的块中的交易,所以toList是下一步的UTXO,应该校验它
 * coinData的交易和txList同处一个块中,txList中的to可能是coinData的from,
 * 也就是可能存在,在同一个块中,下一笔输入就是上一笔的输出,所以需要校验它
 * bestHeight is used when switch chain.
 *
 * @return ValidateResult
 */
@Override
public ValidateResult verifyCoinData(Transaction transaction, Map<String, Coin> temporaryToMap, Set<String> temporaryFromSet, Long bestHeight) {
    if (transaction == null || transaction.getCoinData() == null) {
        return ValidateResult.getFailedResult(CLASS_NAME, LedgerErrorCode.NULL_PARAMETER);
    }
    try {
        /*
            校验开始
             */
        CoinData coinData = transaction.getCoinData();
        List<Coin> froms = coinData.getFrom();
        int fromSize = froms.size();
        TransactionSignature transactionSignature = new TransactionSignature();
        // 交易签名反序列化
        if (transaction.needVerifySignature() && fromSize > 0) {
            try {
                transactionSignature.parse(transaction.getTransactionSignature(), 0);
            } catch (NulsException e) {
                return ValidateResult.getFailedResult(CLASS_NAME, LedgerErrorCode.LEDGER_P2PKH_SCRIPT_ERROR);
            }
        }
        // 保存Set用于验证自身双花
        if (temporaryFromSet == null) {
            temporaryFromSet = new HashSet<>();
        }
        Na fromTotal = Na.ZERO;
        byte[] fromBytes;
        // 保存在数据库中或者txList中的utxo数据
        Coin fromOfFromCoin = null;
        byte[] fromAddressBytes = null;
        /**
         * 存放真实地址(如果为脚本验证的情况fromAddressBytes存的是脚本信息)
         */
        byte[] realAddressBytes = null;
        for (int i = 0; i < froms.size(); i++) {
            Coin from = froms.get(i);
            fromBytes = from.getOwner();
            // 验证是否可花费, 校验的coinData的fromUTXO,检查数据库中是否存在此UTXO
            fromOfFromCoin = utxoLedgerUtxoStorageService.getUtxo(fromBytes);
            // 检查txList中是否存在此UTXO
            if (temporaryToMap != null && fromOfFromCoin == null) {
                fromOfFromCoin = temporaryToMap.get(asString(fromBytes));
            }
            if (null == fromOfFromCoin) {
                // 如果既不存在于txList的to中(如果txList不为空),又不存在于数据库中,那么这是一笔问题数据,进一步检查是否存在这笔交易,交易有就是双花,没有就是孤儿交易,则返回失败
                if (null != utxoLedgerTransactionStorageService.getTxBytes(LedgerUtil.getTxHashBytes(fromBytes))) {
                    return ValidateResult.getFailedResult(CLASS_NAME, TransactionErrorCode.TRANSACTION_REPEATED);
                } else {
                    return ValidateResult.getFailedResult(CLASS_NAME, LedgerErrorCode.ORPHAN_TX);
                }
            } else {
                fromAddressBytes = fromOfFromCoin.getOwner();
                realAddressBytes = fromOfFromCoin.getAddress();
                // pierre add 非合约转账(从合约转出)交易,验证fromAdress是否是合约地址,如果是,则返回失败,非合约转账(从合约转出)交易不能转出合约地址资产
                if (transaction.getType() != ContractConstant.TX_TYPE_CONTRACT_TRANSFER) {
                    boolean isContractAddress = contractService.isContractAddress(realAddressBytes);
                    if (isContractAddress) {
                        return ValidateResult.getFailedResult(CLASS_NAME, LedgerErrorCode.DATA_ERROR);
                    }
                }
                // 验证地址中的公钥hash160和交易中的公钥hash160是否相等,不相等则说明这笔utxo不属于交易发出者
                boolean signtureValidFlag = false;
                if (transaction.needVerifySignature()) {
                    if (transactionSignature != null) {
                        if (fromAddressBytes != null && transactionSignature.getScripts() != null && transactionSignature.getScripts().size() > 0) {
                            if (fromAddressBytes.length != Address.ADDRESS_LENGTH) {
                                Script scriptPubkey = new Script(fromAddressBytes);
                                for (Script scriptSig : transactionSignature.getScripts()) {
                                    signtureValidFlag = scriptSig.correctlyNulsSpends(transaction, 0, scriptPubkey);
                                    if (signtureValidFlag) {
                                        break;
                                    }
                                }
                            } else {
                                for (Script scriptSig : transactionSignature.getScripts()) {
                                    Script redeemScript = new Script(scriptSig.getChunks().get(scriptSig.getChunks().size() - 1).data);
                                    Address address = new Address(NulsContext.getInstance().getDefaultChainId(), NulsContext.P2SH_ADDRESS_TYPE, SerializeUtils.sha256hash160(redeemScript.getProgram()));
                                    Script publicScript = SignatureUtil.createOutputScript(address.getAddressBytes());
                                    signtureValidFlag = scriptSig.correctlyNulsSpends(transaction, 0, publicScript);
                                    if (signtureValidFlag) {
                                        break;
                                    }
                                }
                            }
                        } else {
                            if (transactionSignature.getP2PHKSignatures() != null && transactionSignature.getP2PHKSignatures().size() != 0) {
                                for (P2PHKSignature signature : transactionSignature.getP2PHKSignatures()) {
                                    signtureValidFlag = AddressTool.checkPublicKeyHash(realAddressBytes, signature.getSignerHash160());
                                    if (signtureValidFlag) {
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    if (!signtureValidFlag) {
                        Log.warn("public key hash160 check error.");
                        return ValidateResult.getFailedResult(CLASS_NAME, LedgerErrorCode.INVALID_INPUT);
                    }
                }
                if (java.util.Arrays.equals(realAddressBytes, NulsConstant.BLACK_HOLE_ADDRESS) || java.util.Arrays.equals(realAddressBytes, NulsConstant.BLACK_HOLE_ADDRESS_TEST_NET)) {
                    return ValidateResult.getFailedResult(CLASS_NAME, KernelErrorCode.ADDRESS_IS_BLOCK_HOLE);
                }
                if (NulsContext.getInstance().getDefaultChainId() != SerializeUtils.bytes2Short(realAddressBytes)) {
                    return ValidateResult.getFailedResult(CLASS_NAME, KernelErrorCode.ADDRESS_IS_NOT_BELONGS_TO_CHAIN);
                }
            }
            // 验证非解锁类型的交易及解锁类型的交易
            if (!transaction.isUnlockTx()) {
                // 验证非解锁类型的交易,验证是否可用,检查是否还在锁定时间内
                if (bestHeight == null) {
                    if (!fromOfFromCoin.usable()) {
                        return ValidateResult.getFailedResult(CLASS_NAME, LedgerErrorCode.UTXO_UNUSABLE);
                    }
                } else {
                    if (!fromOfFromCoin.usable(bestHeight)) {
                        return ValidateResult.getFailedResult(CLASS_NAME, LedgerErrorCode.UTXO_UNUSABLE);
                    }
                }
            } else {
                // 验证解锁类型的交易
                if (fromOfFromCoin.getLockTime() != -1) {
                    return ValidateResult.getFailedResult(CLASS_NAME, LedgerErrorCode.UTXO_STATUS_CHANGE);
                }
            }
            // 验证与待确认交易列表中是否有双花,既是待校验交易的fromUtxo是否和txList中的fromUtxo重复,有重复则是双花
            if (temporaryFromSet != null && !temporaryFromSet.add(asString(fromBytes))) {
                if (i > 0) {
                    for (int x = 0; x < i; x++) {
                        Coin theFrom = froms.get(i);
                        temporaryFromSet.remove(asString(theFrom.getOwner()));
                    }
                }
                return ValidateResult.getFailedResult(CLASS_NAME, TransactionErrorCode.TRANSACTION_REPEATED);
            }
            // 验证from的锁定时间和金额
            if (!(fromOfFromCoin.getNa().equals(from.getNa()) && fromOfFromCoin.getLockTime() == from.getLockTime())) {
                return ValidateResult.getFailedResult(CLASS_NAME, LedgerErrorCode.DATA_ERROR);
            }
            fromTotal = fromTotal.add(fromOfFromCoin.getNa());
            from.setFrom(fromOfFromCoin);
        }
        List<Coin> tos = coinData.getTo();
        Na toTotal = Na.ZERO;
        byte[] txBytes = transaction.getHash().serialize();
        for (int i = 0; i < tos.size(); i++) {
            Coin to = tos.get(i);
            // 如果不是调用合约的类型,并且合约地址作为nuls接收者,则返回错误,非合约交易不能转入nuls(CoinBase交易不过此验证)
            if (ContractConstant.TX_TYPE_CALL_CONTRACT != transaction.getType() && AddressTool.validContractAddress(to.getOwner())) {
                Log.error("Ledger verify error: {}.", ContractErrorCode.NON_CONTRACTUAL_TRANSACTION_NO_TRANSFER.getEnMsg());
                return ValidateResult.getFailedResult(CLASS_NAME, ContractErrorCode.NON_CONTRACTUAL_TRANSACTION_NO_TRANSFER);
            }
            toTotal = toTotal.add(to.getNa());
            if (temporaryToMap != null) {
                temporaryToMap.put(asString(ArraysTool.concatenate(txBytes, new VarInt(i).encode())), to);
            }
        }
        // 验证输出不能大于输入
        if (fromTotal.compareTo(toTotal) < 0) {
            return ValidateResult.getFailedResult(CLASS_NAME, LedgerErrorCode.INVALID_AMOUNT);
        }
    } catch (Exception e) {
        Log.error(e);
        return ValidateResult.getFailedResult(CLASS_NAME, KernelErrorCode.SYS_UNKOWN_EXCEPTION);
    }
    return ValidateResult.getSuccessResult();
}
Also used : Script(io.nuls.kernel.script.Script) VarInt(io.nuls.kernel.utils.VarInt) TransactionSignature(io.nuls.kernel.script.TransactionSignature) IOException(java.io.IOException) NulsException(io.nuls.kernel.exception.NulsException) NulsException(io.nuls.kernel.exception.NulsException) P2PHKSignature(io.nuls.kernel.script.P2PHKSignature)

Example 4 with Script

use of io.nuls.kernel.script.Script in project nuls by nuls-io.

the class AccountServiceImpl method saveMultiSigAccount.

/**
 * 导入一个跟本地地址相关的多签账户
 *
 * @param addressStr 多签地址
 * @param pubkeys    多签组成公钥列表
 * @param m          最小签名数
 * @return 是否成功
 */
@Override
public Result<Boolean> saveMultiSigAccount(String addressStr, List<String> pubkeys, int m) {
    Script redeemScript = ScriptBuilder.createNulsRedeemScript(m, pubkeys);
    Address address = new Address(NulsContext.getInstance().getDefaultChainId(), NulsContext.P2SH_ADDRESS_TYPE, SerializeUtils.sha256hash160(redeemScript.getProgram()));
    if (!AddressTool.getStringAddressByBytes(address.getAddressBytes()).equals(addressStr)) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR);
    }
    MultiSigAccount account = new MultiSigAccount();
    account.setAddress(address);
    account.setM(m);
    account.addPubkeys(pubkeys);
    Result result = null;
    try {
        result = this.multiSigAccountStorageService.saveAccount(account.getAddress(), account.serialize());
    } catch (IOException e) {
        Log.error(e);
        return Result.getFailed(KernelErrorCode.SERIALIZE_ERROR);
    }
    if (result.isFailed()) {
        return result;
    }
    return result.setData(addressStr);
}
Also used : Script(io.nuls.kernel.script.Script) Address(io.nuls.kernel.model.Address) IOException(java.io.IOException) Result(io.nuls.kernel.model.Result)

Example 5 with Script

use of io.nuls.kernel.script.Script in project nuls by nuls-io.

the class AccountServiceImpl method createMultiAccount.

@Override
public Result<Address> createMultiAccount(List<String> pubkeys, int m) {
    locker.lock();
    try {
        Script redeemScript = ScriptBuilder.createNulsRedeemScript(m, pubkeys);
        Address address = new Address(NulsContext.getInstance().getDefaultChainId(), NulsContext.P2SH_ADDRESS_TYPE, SerializeUtils.sha256hash160(redeemScript.getProgram()));
        MultiSigAccount account = new MultiSigAccount();
        account.setAddress(address);
        account.setM(m);
        account.addPubkeys(pubkeys);
        Result result = this.multiSigAccountStorageService.saveAccount(account.getAddress(), account.serialize());
        if (result.isFailed()) {
            return result;
        }
        return result.setData(account);
    } catch (Exception e) {
        Log.error(e);
        throw new NulsRuntimeException(KernelErrorCode.FAILED);
    } finally {
        locker.unlock();
    }
}
Also used : Script(io.nuls.kernel.script.Script) Address(io.nuls.kernel.model.Address) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) CryptoException(io.nuls.core.tools.crypto.Exception.CryptoException) NulsRuntimeException(io.nuls.kernel.exception.NulsRuntimeException) SignatureException(java.security.SignatureException) IOException(java.io.IOException) NulsException(io.nuls.kernel.exception.NulsException) Result(io.nuls.kernel.model.Result)

Aggregations

Script (io.nuls.kernel.script.Script)11 NulsException (io.nuls.kernel.exception.NulsException)5 IOException (java.io.IOException)5 NulsRuntimeException (io.nuls.kernel.exception.NulsRuntimeException)4 TransferTransaction (io.nuls.protocol.model.tx.TransferTransaction)4 CryptoException (io.nuls.core.tools.crypto.Exception.CryptoException)3 CoinDataResult (io.nuls.account.ledger.model.CoinDataResult)2 ECKey (io.nuls.core.tools.crypto.ECKey)2 Address (io.nuls.kernel.model.Address)2 Coin (io.nuls.kernel.model.Coin)2 CoinData (io.nuls.kernel.model.CoinData)2 Result (io.nuls.kernel.model.Result)2 VarInt (io.nuls.kernel.utils.VarInt)2 UnsupportedEncodingException (java.io.UnsupportedEncodingException)2 BigInteger (java.math.BigInteger)2 ArrayList (java.util.ArrayList)2 AliasTransaction (io.nuls.account.tx.AliasTransaction)1 Deposit (io.nuls.consensus.poc.protocol.entity.Deposit)1 CreateAgentTransaction (io.nuls.consensus.poc.protocol.tx.CreateAgentTransaction)1 DepositTransaction (io.nuls.consensus.poc.protocol.tx.DepositTransaction)1