use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.
the class ContractTxServiceImpl method contractPreCreateTx.
/**
* 预创建生成智能合约的交易
* 用于测试合约是否能正确创建
*
* @param sender 交易创建者
* @param gasLimit 最大gas消耗
* @param price 执行合约单价
* @param contractCode 合约代码
* @param args 参数列表
* @param password 账户密码
* @param remark 备注
* @return
*/
@Override
public Result contractPreCreateTx(String sender, Long gasLimit, Long price, byte[] contractCode, String[][] args, String password, String remark) {
try {
AssertUtil.canNotEmpty(sender, "the sender address can not be empty");
AssertUtil.canNotEmpty(contractCode, "the contractCode can not be empty");
Na value = Na.ZERO;
Result<Account> accountResult = accountService.getAccount(sender);
if (accountResult.isFailed()) {
return accountResult;
}
// 生成一个地址作为智能合约地址
Address contractAddress = AccountTool.createContractAddress();
byte[] contractAddressBytes = contractAddress.getAddressBytes();
byte[] senderBytes = AddressTool.getAddress(sender);
CreateContractTransaction tx = new CreateContractTransaction();
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());
// 计算CoinData
/*
* 智能合约计算手续费以消耗的Gas*Price为根据,然而创建交易时并不执行智能合约,
* 所以此时交易的CoinData是不固定的,比实际要多,
* 打包时执行智能合约,真实的手续费已算出,然而tx的手续费已扣除,
* 多扣除的费用会以CoinBase交易还给Sender
*/
CoinData coinData = new CoinData();
// 向智能合约账户转账
if (!Na.ZERO.equals(value)) {
Coin toCoin = new Coin(contractAddressBytes, value);
coinData.getTo().add(toCoin);
}
BlockHeader blockHeader = NulsContext.getInstance().getBestBlock().getHeader();
// 当前区块高度
long blockHeight = blockHeader.getHeight();
// 当前区块状态根
byte[] prevStateRoot = ContractUtil.getStateRoot(blockHeader);
AssertUtil.canNotEmpty(prevStateRoot, "All features of the smart contract are locked.");
// 执行VM验证合法性
ProgramCreate programCreate = new ProgramCreate();
programCreate.setContractAddress(contractAddressBytes);
programCreate.setSender(senderBytes);
programCreate.setValue(BigInteger.valueOf(value.getValue()));
programCreate.setPrice(price.longValue());
programCreate.setGasLimit(gasLimit.longValue());
programCreate.setNumber(blockHeight);
programCreate.setContractCode(contractCode);
if (args != null) {
programCreate.setArgs(args);
}
ProgramExecutor track = programExecutor.begin(prevStateRoot);
// 验证合约时跳过Gas验证
long realGasLimit = programCreate.getGasLimit();
programCreate.setGasLimit(MAX_GASLIMIT);
ProgramResult programResult = track.create(programCreate);
// 执行结果失败时,交易直接返回错误,不上链,不消耗Gas,
if (!programResult.isSuccess()) {
Log.error(programResult.getStackTrace());
Result result = Result.getFailed(ContractErrorCode.DATA_ERROR);
result.setMsg(ContractUtil.simplifyErrorMsg(programResult.getErrorMessage()));
result = checkVmResultAndReturn(programResult.getErrorMessage(), result);
return result;
} else {
// 其他合法性都通过后,再验证Gas
track = programExecutor.begin(prevStateRoot);
programCreate.setGasLimit(realGasLimit);
programResult = track.create(programCreate);
if (!programResult.isSuccess()) {
Log.error(programResult.getStackTrace());
Result result = Result.getFailed(ContractErrorCode.DATA_ERROR);
result.setMsg(ContractUtil.simplifyErrorMsg(programResult.getErrorMessage()));
return result;
}
}
long gasUsed = gasLimit.longValue();
Na imputedNa = Na.valueOf(LongUtils.mul(gasUsed, price));
// 总花费
Na totalNa = imputedNa.add(value);
// 组装txData
CreateContractData createContractData = new CreateContractData();
createContractData.setSender(senderBytes);
createContractData.setContractAddress(contractAddressBytes);
createContractData.setValue(value.getValue());
createContractData.setGasLimit(gasLimit);
createContractData.setPrice(price);
createContractData.setCodeLen(contractCode.length);
createContractData.setCode(contractCode);
if (args != null) {
createContractData.setArgsCount((byte) args.length);
if (args.length > 0) {
createContractData.setArgs(args);
}
}
tx.setTxData(createContractData);
CoinDataResult coinDataResult = accountLedgerService.getCoinData(senderBytes, totalNa, tx.size(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES);
if (!coinDataResult.isEnough()) {
return Result.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE);
}
return Result.getSuccess();
} catch (NulsException e) {
Log.error(e);
return Result.getFailed(e.getErrorCode());
} catch (Exception e) {
Log.error(e);
Result result = Result.getFailed(ContractErrorCode.CONTRACT_TX_CREATE_ERROR);
result.setMsg(e.getMessage());
return result;
}
}
use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.
the class AliasService method getMultiAliasFee.
/**
* 获取设置别名交易手续费
* Gets to set the alias transaction fee
*
* @param address
* @param aliasName
* @return
*/
public Result<Na> getMultiAliasFee(String address, String aliasName) {
if (!AddressTool.validAddress(address)) {
Result.getFailed(AccountErrorCode.ADDRESS_ERROR);
}
byte[] addressBytes = AddressTool.getAddress(address);
try {
// 创建一笔设置别名的交易
AliasTransaction tx = new AliasTransaction();
tx.setTime(TimeService.currentTimeMillis());
Alias alias = new Alias(addressBytes, aliasName);
tx.setTxData(alias);
CoinDataResult coinDataResult = accountLedgerService.getMutilCoinData(addressBytes, AccountConstant.ALIAS_NA, tx.size(), TransactionFeeCalculator.OTHER_PRICE_PRE_1024_BYTES);
if (!coinDataResult.isEnough()) {
return Result.getFailed(AccountErrorCode.INSUFFICIENT_BALANCE);
}
CoinData coinData = new CoinData();
coinData.setFrom(coinDataResult.getCoinList());
Coin change = coinDataResult.getChange();
if (null != change) {
// 创建toList
List<Coin> toList = new ArrayList<>();
toList.add(change);
coinData.setTo(toList);
}
Coin coin = new Coin(NulsConstant.BLACK_HOLE_ADDRESS, Na.parseNuls(1), 0);
coinData.addTo(coin);
tx.setCoinData(coinData);
Na fee = TransactionFeeCalculator.getMaxFee(tx.size());
return Result.getSuccess().setData(fee);
} catch (Exception e) {
Log.error(e);
return Result.getFailed(KernelErrorCode.SYS_UNKOWN_EXCEPTION);
}
}
use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.
the class AliasService method setMutilAlias.
/**
* 多签账户设置别名
* Initiate a transaction to set alias.
*
* @param addr Address of account
* @param password password of account
* @param aliasName the alias to set
* @return txhash
*/
public Result<String> setMutilAlias(String addr, String signAddr, String aliasName, String password, List<String> pubKeys, int m, String txdata) {
// 签名账户
Account account = accountService.getAccount(signAddr).getData();
if (null == account) {
return Result.getFailed(AccountErrorCode.ACCOUNT_NOT_EXIST);
}
if (account.isEncrypted() && account.isLocked()) {
if (!account.validatePassword(password)) {
return Result.getFailed(AccountErrorCode.PASSWORD_IS_WRONG);
}
}
try {
AliasTransaction tx = new AliasTransaction();
TransactionSignature transactionSignature = new TransactionSignature();
List<P2PHKSignature> p2PHKSignatures = new ArrayList<>();
List<Script> scripts = new ArrayList<>();
byte[] addressBytes = AddressTool.getAddress(addr);
// 如果txdata为空则表示当前请求为多签发起者调用,需要创建交易
if (txdata == null || txdata.trim().length() == 0) {
if (!StringUtils.validAlias(aliasName)) {
return Result.getFailed(AccountErrorCode.ALIAS_FORMAT_WRONG);
}
if (!isAliasUsable(aliasName)) {
return Result.getFailed(AccountErrorCode.ALIAS_EXIST);
}
// 创建一笔设置别名的交易
tx = new AliasTransaction();
Script redeemScript = ScriptBuilder.createNulsRedeemScript(m, pubKeys);
tx.setTime(TimeService.currentTimeMillis());
Alias alias = new Alias(addressBytes, aliasName);
tx.setTxData(alias);
// 交易签名的长度为m*单个签名长度+赎回脚本长度
int scriptSignLenth = redeemScript.getProgram().length + m * 72;
CoinDataResult coinDataResult = accountLedgerService.getMutilCoinData(addressBytes, AccountConstant.ALIAS_NA, tx.size() + scriptSignLenth, TransactionFeeCalculator.OTHER_PRICE_PRE_1024_BYTES);
if (!coinDataResult.isEnough()) {
return Result.getFailed(AccountErrorCode.INSUFFICIENT_BALANCE);
}
CoinData coinData = new CoinData();
coinData.setFrom(coinDataResult.getCoinList());
Coin change = coinDataResult.getChange();
if (null != change) {
// 创建toList
List<Coin> toList = new ArrayList<>();
toList.add(change);
coinData.setTo(toList);
}
Coin coin = new Coin(NulsConstant.BLACK_HOLE_ADDRESS, Na.parseNuls(1), 0);
coinData.addTo(coin);
tx.setCoinData(coinData);
tx.setHash(NulsDigestData.calcDigestData(tx.serializeForHash()));
// 将赎回脚本先存储在签名脚本中
scripts.add(redeemScript);
transactionSignature.setScripts(scripts);
} else // 如果txdata不为空表示多签交易已经创建好了,将交易反序列化出来
{
byte[] txByte = Hex.decode(txdata);
tx.parse(new NulsByteBuffer(txByte));
transactionSignature.parse(new NulsByteBuffer(tx.getTransactionSignature()));
p2PHKSignatures = transactionSignature.getP2PHKSignatures();
scripts = transactionSignature.getScripts();
}
// 使用签名账户对交易进行签名
P2PHKSignature p2PHKSignature = new P2PHKSignature();
ECKey eckey = account.getEcKey(password);
p2PHKSignature.setPublicKey(eckey.getPubKey());
// 用当前交易的hash和账户的私钥账户
p2PHKSignature.setSignData(accountService.signDigest(tx.getHash().getDigestBytes(), eckey));
p2PHKSignatures.add(p2PHKSignature);
Result result = txMutilProcessing(tx, p2PHKSignatures, scripts, transactionSignature, addressBytes);
return result;
} catch (Exception e) {
Log.error(e);
return Result.getFailed(KernelErrorCode.SYS_UNKOWN_EXCEPTION);
}
}
use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.
the class AliasService method setAlias.
/**
* 设置别名
* Initiate a transaction to set alias.
*
* @param addr Address of account
* @param password password of account
* @param aliasName the alias to set
* @return txhash
*/
public Result<String> setAlias(String addr, String aliasName, String password) {
if (!AddressTool.validAddress(addr)) {
return Result.getFailed(AccountErrorCode.ADDRESS_ERROR);
}
Account account = accountService.getAccount(addr).getData();
if (null == account) {
return Result.getFailed(AccountErrorCode.ACCOUNT_NOT_EXIST);
}
if (account.isEncrypted() && account.isLocked()) {
if (!account.validatePassword(password)) {
return Result.getFailed(AccountErrorCode.PASSWORD_IS_WRONG);
}
}
if (!account.isOk()) {
return Result.getFailed(AccountErrorCode.IMPORTING_ACCOUNT);
}
if (StringUtils.isNotBlank(account.getAlias())) {
return Result.getFailed(AccountErrorCode.ACCOUNT_ALREADY_SET_ALIAS);
}
if (!StringUtils.validAlias(aliasName)) {
return Result.getFailed(AccountErrorCode.ALIAS_FORMAT_WRONG);
}
if (!isAliasUsable(aliasName)) {
return Result.getFailed(AccountErrorCode.ALIAS_EXIST);
}
byte[] addressBytes = account.getAddress().getAddressBytes();
try {
// 创建一笔设置别名的交易
AliasTransaction tx = new AliasTransaction();
tx.setTime(TimeService.currentTimeMillis());
Alias alias = new Alias(addressBytes, aliasName);
tx.setTxData(alias);
CoinDataResult coinDataResult = accountLedgerService.getCoinData(addressBytes, AccountConstant.ALIAS_NA, tx.size(), TransactionFeeCalculator.OTHER_PRICE_PRE_1024_BYTES);
if (!coinDataResult.isEnough()) {
return Result.getFailed(AccountErrorCode.INSUFFICIENT_BALANCE);
}
CoinData coinData = new CoinData();
coinData.setFrom(coinDataResult.getCoinList());
Coin change = coinDataResult.getChange();
if (null != change) {
// 创建toList
List<Coin> toList = new ArrayList<>();
toList.add(change);
coinData.setTo(toList);
}
Coin coin = new Coin(NulsConstant.BLACK_HOLE_ADDRESS, AccountConstant.ALIAS_NA, 0);
coinData.addTo(coin);
tx.setCoinData(coinData);
tx.setHash(NulsDigestData.calcDigestData(tx.serializeForHash()));
// 生成签名
List<ECKey> signEckeys = new ArrayList<>();
List<ECKey> scriptEckeys = new ArrayList<>();
;
ECKey eckey = account.getEcKey(password);
// 如果最后一位为1则表示该交易包含普通签名
if ((coinDataResult.getSignType() & 0x01) == 0x01) {
signEckeys.add(eckey);
}
// 如果倒数第二位位为1则表示该交易包含脚本签名
if ((coinDataResult.getSignType() & 0x02) == 0x02) {
scriptEckeys.add(eckey);
}
SignatureUtil.createTransactionSignture(tx, scriptEckeys, signEckeys);
Result saveResult = accountLedgerService.verifyAndSaveUnconfirmedTransaction(tx);
if (saveResult.isFailed()) {
if (KernelErrorCode.DATA_SIZE_ERROR.getCode().equals(saveResult.getErrorCode().getCode())) {
// 重新算一次交易(不超出最大交易数据大小下)的最大金额
Result rs = accountLedgerService.getMaxAmountOfOnce(account.getAddress().getAddressBytes(), tx, TransactionFeeCalculator.OTHER_PRICE_PRE_1024_BYTES);
if (rs.isSuccess()) {
Na maxAmount = (Na) rs.getData();
rs = Result.getFailed(KernelErrorCode.DATA_SIZE_ERROR_EXTEND);
rs.setMsg(rs.getMsg() + maxAmount.toDouble());
}
return rs;
}
return saveResult;
}
this.transactionService.newTx(tx);
Result sendResult = this.transactionService.broadcastTx(tx);
if (sendResult.isFailed()) {
accountLedgerService.deleteTransaction(tx);
return sendResult;
}
String hash = tx.getHash().getDigestHex();
return Result.getSuccess().setData(hash);
} catch (Exception e) {
Log.error(e);
return Result.getFailed(KernelErrorCode.SYS_UNKOWN_EXCEPTION);
}
}
use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.
the class AliasService method getAliasFee.
/**
* 获取设置别名交易手续费
* Gets to set the alias transaction fee
*
* @param address
* @param aliasName
* @return
*/
public Result<Na> getAliasFee(String address, String aliasName) {
if (!AddressTool.validAddress(address)) {
Result.getFailed(AccountErrorCode.ADDRESS_ERROR);
}
Account account = accountService.getAccount(address).getData();
if (null == account) {
return Result.getFailed(AccountErrorCode.ACCOUNT_NOT_EXIST);
}
if (!account.isOk()) {
return Result.getFailed(AccountErrorCode.IMPORTING_ACCOUNT);
}
byte[] addressBytes = account.getAddress().getAddressBytes();
try {
// 创建一笔设置别名的交易
AliasTransaction tx = new AliasTransaction();
tx.setTime(TimeService.currentTimeMillis());
Alias alias = new Alias(addressBytes, aliasName);
tx.setTxData(alias);
CoinDataResult coinDataResult = accountLedgerService.getCoinData(addressBytes, AccountConstant.ALIAS_NA, tx.size(), TransactionFeeCalculator.OTHER_PRICE_PRE_1024_BYTES);
if (!coinDataResult.isEnough()) {
return Result.getFailed(AccountErrorCode.INSUFFICIENT_BALANCE);
}
CoinData coinData = new CoinData();
coinData.setFrom(coinDataResult.getCoinList());
Coin change = coinDataResult.getChange();
if (null != change) {
// 创建toList
List<Coin> toList = new ArrayList<>();
toList.add(change);
coinData.setTo(toList);
}
Coin coin = new Coin(NulsConstant.BLACK_HOLE_ADDRESS, Na.parseNuls(1), 0);
coinData.addTo(coin);
tx.setCoinData(coinData);
Na fee = TransactionFeeCalculator.getMaxFee(tx.size());
return Result.getSuccess().setData(fee);
} catch (Exception e) {
Log.error(e);
return Result.getFailed(KernelErrorCode.SYS_UNKOWN_EXCEPTION);
}
}
Aggregations