Search in sources :

Example 6 with CoinDataResult

use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.

the class ContractSdkResource method createContractTx.

@POST
@Path("/sdk/create")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "create contact transaction")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success") })
public RpcClientResult createContractTx(@ApiParam(name = "createForm", value = "create contact transaction", required = true) CreateContractTx createContractTx) {
    if (!AddressTool.validAddress(createContractTx.getSender())) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    if (createContractTx.getGasLimit() < 0 || createContractTx.getPrice() < 0) {
        return Result.getFailed(ContractErrorCode.PARAMETER_ERROR).toRpcClientResult();
    }
    if (createContractTx.getUtxos().isEmpty()) {
        // utxo not null and size not zero.
        return Result.getFailed(AccountErrorCode.DATA_PARSE_ERROR).toRpcClientResult();
    }
    Long gasLimit = createContractTx.getGasLimit();
    Long price = createContractTx.getPrice();
    Na value = Na.ZERO;
    long totalGas = LongUtils.mul(gasLimit, price);
    Na totalNa = Na.valueOf(totalGas);
    byte[] senderBytes = AddressTool.getAddress(createContractTx.getSender());
    /**
     * first create a new contract address.
     */
    Address contractAddress = null;
    try {
        contractAddress = AccountTool.createContractAddress();
    } catch (NulsException e) {
        Log.error(e);
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    byte[] contractAddressBytes = contractAddress.getAddressBytes();
    // 组装txData
    String contractCode = createContractTx.getContractCode();
    byte[] contractCodeBytes = Hex.decode(contractCode);
    CreateContractData txData = new CreateContractData();
    txData.setSender(senderBytes);
    txData.setContractAddress(contractAddressBytes);
    txData.setValue(value.getValue());
    txData.setGasLimit(gasLimit);
    txData.setPrice(price);
    txData.setCodeLen(contractCodeBytes.length);
    txData.setCode(contractCodeBytes);
    Object[] args = createContractTx.getArgs();
    if (args != null) {
        txData.setArgsCount((byte) args.length);
        if (args.length > 0) {
            txData.setArgs(ContractUtil.twoDimensionalArray(args));
        }
    }
    /**
     * create create contract tx data
     */
    CreateContractTransaction tx = new CreateContractTransaction();
    String remark = createContractTx.getRemark();
    if (StringUtils.isNotBlank(remark)) {
        try {
            tx.setRemark(remark.getBytes(NulsConfig.DEFAULT_ENCODING));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
    tx.setTime(TimeService.currentTimeMillis());
    tx.setTxData(txData);
    List<Coin> coinList = ConvertCoinTool.convertCoinList(createContractTx.getUtxos());
    CoinDataResult coinDataResult = CoinDataTool.getCoinData(senderBytes, totalNa, tx.size(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES, coinList);
    if (!coinDataResult.isEnough()) {
        return RpcClientResult.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE);
    }
    /**
     * build coin data
     */
    CoinData coinData = new CoinData();
    coinData.setFrom(coinDataResult.getCoinList());
    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();
    }
    return this.buildReturnInfo(tx, AddressTool.getStringAddressByBytes(contractAddressBytes));
}
Also used : UnsupportedEncodingException(java.io.UnsupportedEncodingException) CreateContractTransaction(io.nuls.contract.entity.tx.CreateContractTransaction) NulsException(io.nuls.kernel.exception.NulsException) CreateContractData(io.nuls.contract.entity.txdata.CreateContractData) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Produces(javax.ws.rs.Produces)

Example 7 with CoinDataResult

use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.

the class ContractSdkResource method callContractTx.

@POST
@Path("/sdk/call")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "call smart contract transaction")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success") })
public RpcClientResult callContractTx(@ApiParam(name = "callForm", value = "call smart contract transaction", required = true) CallContractTx callContractTx) {
    if (!AddressTool.validAddress(callContractTx.getSender())) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    String contractAddress = callContractTx.getContractAddress();
    if (!AddressTool.validAddress(contractAddress)) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    if (callContractTx.getGasLimit() < 0 || callContractTx.getPrice() < 0) {
        return Result.getFailed(ContractErrorCode.PARAMETER_ERROR).toRpcClientResult();
    }
    if (StringUtils.isBlank(callContractTx.getMethodName())) {
        return Result.getFailed(ContractErrorCode.PARAMETER_ERROR).toRpcClientResult();
    }
    if (callContractTx.getUtxos().isEmpty()) {
        // utxo not null and size not zero.
        return Result.getFailed(AccountErrorCode.DATA_PARSE_ERROR).toRpcClientResult();
    }
    Long gasLimit = callContractTx.getGasLimit();
    Long price = callContractTx.getPrice();
    Na value = Na.valueOf(callContractTx.getValue());
    byte[] senderBytes = AddressTool.getAddress(callContractTx.getSender());
    byte[] contractAddressBytes = AddressTool.getAddress(callContractTx.getContractAddress());
    if (value == null) {
        value = Na.ZERO;
    }
    CallContractTransaction tx = new CallContractTransaction();
    String remark = callContractTx.getRemark();
    if (StringUtils.isNotBlank(remark)) {
        try {
            tx.setRemark(remark.getBytes(NulsConfig.DEFAULT_ENCODING));
        } catch (UnsupportedEncodingException e) {
            Log.error(e);
            throw new RuntimeException(e);
        }
    }
    tx.setTime(TimeService.currentTimeMillis());
    long gasUsed = gasLimit.longValue();
    Na imputedNa = Na.valueOf(LongUtils.mul(gasUsed, price));
    Na totalNa = imputedNa.add(value);
    CallContractData callContractData = new CallContractData();
    callContractData.setContractAddress(contractAddressBytes);
    callContractData.setSender(senderBytes);
    callContractData.setValue(value.getValue());
    callContractData.setPrice(price.longValue());
    callContractData.setGasLimit(gasLimit.longValue());
    callContractData.setMethodName(callContractTx.getMethodName());
    callContractData.setMethodDesc(callContractTx.getMethodDesc());
    /**
     * build args
     */
    Object[] args = callContractTx.getArgs();
    if (args != null) {
        callContractData.setArgsCount((byte) args.length);
        callContractData.setArgs(ContractUtil.twoDimensionalArray(args));
    }
    tx.setTxData(callContractData);
    /**
     * build coin data
     */
    CoinData coinData = new CoinData();
    // transfer to contract address.
    if (value.isGreaterThan(Na.ZERO)) {
        Coin toCoin = new Coin(contractAddressBytes, value);
        coinData.getTo().add(toCoin);
    }
    List<Coin> coinList = ConvertCoinTool.convertCoinList(callContractTx.getUtxos());
    CoinDataResult coinDataResult = CoinDataTool.getCoinData(senderBytes, totalNa, tx.size() + coinData.size(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES, coinList);
    if (!coinDataResult.isEnough()) {
        return RpcClientResult.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE);
    }
    coinData.setFrom(coinDataResult.getCoinList());
    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();
    }
    return this.buildReturnInfo(tx, contractAddress);
}
Also used : UnsupportedEncodingException(java.io.UnsupportedEncodingException) CallContractData(io.nuls.contract.entity.txdata.CallContractData) CallContractTransaction(io.nuls.contract.entity.tx.CallContractTransaction) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Produces(javax.ws.rs.Produces)

Example 8 with CoinDataResult

use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.

the class ContractSdkResource method deleteContractTx.

@POST
@Path("/sdk/delete")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "delete smart contract transaction")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success") })
public RpcClientResult deleteContractTx(@ApiParam(name = "deleteForm", value = "delete smart contract transaction", required = true) DeleteContractTx deleteContractTx) {
    if (!AddressTool.validAddress(deleteContractTx.getSender())) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    String contractAddress = deleteContractTx.getContractAddress();
    if (!AddressTool.validAddress(contractAddress)) {
        return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
    }
    if (deleteContractTx.getUtxos().isEmpty()) {
        // utxo not null and size not zero.
        return Result.getFailed(AccountErrorCode.DATA_PARSE_ERROR).toRpcClientResult();
    }
    DeleteContractTransaction tx = new DeleteContractTransaction();
    if (StringUtils.isNotBlank(deleteContractTx.getRemark())) {
        try {
            tx.setRemark(deleteContractTx.getRemark().getBytes(NulsConfig.DEFAULT_ENCODING));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }
    tx.setTime(TimeService.currentTimeMillis());
    byte[] senderBytes = AddressTool.getAddress(deleteContractTx.getSender());
    byte[] contractAddressBytes = AddressTool.getAddress(deleteContractTx.getContractAddress());
    /**
     * build tx data
     */
    DeleteContractData deleteContractData = new DeleteContractData();
    deleteContractData.setContractAddress(contractAddressBytes);
    deleteContractData.setSender(senderBytes);
    tx.setTxData(deleteContractData);
    List<Coin> coinList = ConvertCoinTool.convertCoinList(deleteContractTx.getUtxos());
    CoinDataResult coinDataResult = CoinDataTool.getCoinData(senderBytes, Na.ZERO, tx.size(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES, coinList);
    if (!coinDataResult.isEnough()) {
        return RpcClientResult.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE);
    }
    /**
     * build coin data
     */
    CoinData coinData = new CoinData();
    coinData.setFrom(coinDataResult.getCoinList());
    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();
    }
    return this.buildReturnInfo(tx, contractAddress);
}
Also used : UnsupportedEncodingException(java.io.UnsupportedEncodingException) DeleteContractData(io.nuls.contract.entity.txdata.DeleteContractData) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult) DeleteContractTransaction(io.nuls.contract.entity.tx.DeleteContractTransaction) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Produces(javax.ws.rs.Produces)

Example 9 with CoinDataResult

use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.

the class ContractServiceImpl method transfer.

/**
 * @param from
 * @param to
 * @param values
 * @param fee
 * @param isSendBack
 * @param orginHash
 * @param blockTime
 * @param toMaps
 * @param contractUsedCoinMap 组装时不操作toMaps, 用 contractUsedCoinMap 来检查UTXO是否已经被使用,如果已使用则跳过
 *                            (合约转账(从合约转出)不同于普通转账,普通转账有本地账本来维护UTXO,并且在打包前已经组装好UTXO,
 *                            而合约转账(从合约转出)是在打包时才组装,此时从合约账本[DB]及打包交易[toMaps]中拿到所有的utxo来组装,
 *                            用 contractUsedCoinMap 来代表已使用的UTXO)
 * @param bestHeight
 * @return
 */
private Result<ContractTransferTransaction> transfer(byte[] from, byte[] to, Na values, Na fee, boolean isSendBack, NulsDigestData orginHash, long blockTime, Map<String, Coin> toMaps, Map<String, Coin> contractUsedCoinMap, Long bestHeight) {
    try {
        if (!ContractLedgerUtil.isExistContractAddress(from)) {
            return Result.getFailed(ContractErrorCode.CONTRACT_ADDRESS_NOT_EXIST);
        }
        ContractTransferTransaction tx = new ContractTransferTransaction();
        tx.setTime(blockTime);
        CoinData coinData = new CoinData();
        List<Coin> tos = coinData.getTo();
        Coin toCoin = new Coin(to, values.subtract(fee));
        tos.add(toCoin);
        // 加入toMaps、contractUsedCoinMap组装UTXO
        // 组装时不操作toMaps, 用 contractUsedCoinMap 来检查UTXO是否已经被使用,如果已使用则跳过
        CoinDataResult coinDataResult = getContractSpecialTransferCoinData(from, values, toMaps, contractUsedCoinMap, bestHeight);
        if (!coinDataResult.isEnough()) {
            return Result.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE);
        }
        coinData.setFrom(coinDataResult.getCoinList());
        if (coinDataResult.getChange() != null) {
            tos.add(coinDataResult.getChange());
        }
        tx.setCoinData(coinData);
        byte successByte;
        byte[] remark = null;
        if (isSendBack) {
            successByte = 0;
            remark = ContractConstant.SEND_BACK_REMARK.getBytes(NulsConfig.DEFAULT_ENCODING);
        } else {
            successByte = 1;
        }
        tx.setRemark(remark);
        tx.setTxData(new ContractTransferData(orginHash, from, successByte));
        tx.setHash(NulsDigestData.calcDigestData(tx.serializeForHash()));
        // 维护合约地址连续转出交易的未花费UTXO
        byte[] txBytes = tx.getHash().serialize();
        for (int i = 0, size = tos.size(); i < size; i++) {
            if (toMaps != null) {
                toMaps.put(LedgerUtil.asString(ArraysTool.concatenate(txBytes, new VarInt(i).encode())), tos.get(i));
            }
        }
        // 合约转账(从合约转出)交易不需要签名
        return Result.getSuccess().setData(tx);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}
Also used : VarInt(io.nuls.kernel.utils.VarInt) IOException(java.io.IOException) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Example 10 with CoinDataResult

use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.

the class ContractServiceImpl method getContractSpecialTransferCoinData.

/**
 * @param address
 * @param amount
 * @param bestHeight
 * @return
 * @throws NulsException
 */
public CoinDataResult getContractSpecialTransferCoinData(byte[] address, Na amount, Map<String, Coin> toMaps, Map<String, Coin> contractUsedCoinMap, Long bestHeight) {
    lock.lock();
    try {
        CoinDataResult coinDataResult = new CoinDataResult();
        List<Coin> coinList = contractBalanceManager.getCoinListByAddress(address);
        // pierre add contract coin key
        Set<Map.Entry<String, Coin>> toMapsEntries = toMaps.entrySet();
        Coin toCoin;
        Coin cloneCoin;
        String key;
        for (Map.Entry<String, Coin> toMapsEntry : toMapsEntries) {
            key = toMapsEntry.getKey();
            toCoin = toMapsEntry.getValue();
            if (Arrays.equals(toCoin.getAddress(), address) && !contractUsedCoinMap.containsKey(key)) {
                cloneCoin = new Coin(asBytes(key), toCoin.getNa(), toCoin.getLockTime());
                cloneCoin.setFrom(toCoin);
                cloneCoin.setKey(key);
                coinList.add(cloneCoin);
            }
        }
        if (coinList.isEmpty()) {
            coinDataResult.setEnough(false);
            return coinDataResult;
        }
        // 将所有余额从小到大排序
        Collections.sort(coinList, ContractCoinComparator.getInstance());
        boolean enough = false;
        List<Coin> coins = new ArrayList<>();
        Na values = Na.ZERO;
        Coin coin;
        // 将所有余额从小到大排序后,累计未花费的余额
        for (int i = 0, length = coinList.size(); i < length; i++) {
            coin = coinList.get(i);
            if (bestHeight != null) {
                if (!coin.usable(bestHeight)) {
                    continue;
                }
            } else {
                if (!coin.usable()) {
                    continue;
                }
            }
            if (coin.getNa().equals(Na.ZERO)) {
                continue;
            }
            // for contract, 使用过的UTXO不能再使用
            if (StringUtils.isNotBlank(coin.getKey())) {
                if (contractUsedCoinMap.containsKey(coin.getKey())) {
                    continue;
                }
                contractUsedCoinMap.put(coin.getKey(), coin);
            }
            coins.add(coin);
            // 每次累加一条未花费余额
            values = values.add(coin.getNa());
            if (values.isGreaterOrEquals(amount)) {
                // 余额足够后,需要判断是否找零
                Na change = values.subtract(amount);
                if (change.isGreaterThan(Na.ZERO)) {
                    Coin changeCoin = new Coin();
                    changeCoin.setOwner(address);
                    changeCoin.setNa(change);
                    coinDataResult.setChange(changeCoin);
                }
                enough = true;
                coinDataResult.setEnough(true);
                coinDataResult.setFee(Na.ZERO);
                coinDataResult.setCoinList(coins);
                break;
            }
        }
        if (!enough) {
            coinDataResult.setEnough(false);
            return coinDataResult;
        }
        return coinDataResult;
    } finally {
        lock.unlock();
    }
}
Also used : LedgerUtil.asString(io.nuls.ledger.util.LedgerUtil.asString) CoinDataResult(io.nuls.account.ledger.model.CoinDataResult)

Aggregations

CoinDataResult (io.nuls.account.ledger.model.CoinDataResult)35 Account (io.nuls.account.model.Account)22 NulsException (io.nuls.kernel.exception.NulsException)22 MultiSigAccount (io.nuls.account.model.MultiSigAccount)20 IOException (java.io.IOException)20 UnsupportedEncodingException (java.io.UnsupportedEncodingException)15 ECKey (io.nuls.core.tools.crypto.ECKey)14 NulsRuntimeException (io.nuls.kernel.exception.NulsRuntimeException)10 TransferTransaction (io.nuls.protocol.model.tx.TransferTransaction)8 TransactionDataResult (io.nuls.account.ledger.model.TransactionDataResult)7 AliasTransaction (io.nuls.account.tx.AliasTransaction)7 ValidateResult (io.nuls.kernel.validate.ValidateResult)7 MultipleAddressTransferModel (io.nuls.account.ledger.model.MultipleAddressTransferModel)6 ArrayList (java.util.ArrayList)6 Alias (io.nuls.account.model.Alias)5 NulsByteBuffer (io.nuls.kernel.utils.NulsByteBuffer)5 DataTransaction (io.nuls.protocol.model.tx.DataTransaction)4 LogicData (io.nuls.protocol.model.tx.LogicData)4 AccountConstant (io.nuls.account.constant.AccountConstant)3 AccountErrorCode (io.nuls.account.constant.AccountErrorCode)3