use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.
the class PocConsensusResource method txProcessing.
public RpcClientResult txProcessing(Transaction tx, CoinDataResult result, Account account, String password) {
if (null != result) {
if (result.isEnough()) {
tx.getCoinData().setFrom(result.getCoinList());
if (null != result.getChange()) {
tx.getCoinData().getTo().add(result.getChange());
}
} else {
return Result.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE).toRpcClientResult();
}
}
try {
tx.setHash(NulsDigestData.calcDigestData(tx.serializeForHash()));
// 生成签名
List<ECKey> signEckeys = new ArrayList<>();
ECKey eckey = account.getEcKey(password);
signEckeys.add(eckey);
SignatureUtil.createTransactionSignture(tx, null, signEckeys);
} catch (Exception e) {
Log.error(e);
return Result.getFailed(KernelErrorCode.SYS_UNKOWN_EXCEPTION).toRpcClientResult();
}
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.toRpcClientResult();
}
return saveResult.toRpcClientResult();
}
transactionService.newTx(tx);
Result sendResult = this.transactionService.broadcastTx(tx);
if (sendResult.isFailed()) {
accountLedgerService.deleteTransaction(tx);
return sendResult.toRpcClientResult();
}
return Result.getSuccess().toRpcClientResult();
}
use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.
the class PocConsensusResource method createMutilDeposit.
@POST
@Path("/multiAccount/createMultiDeposit")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "deposit nuls to a bank! 多签账户申请参与共识 ", notes = "返回申请成功交易hash")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success", response = String.class) })
public RpcClientResult createMutilDeposit(@ApiParam(name = "form", value = "多签账户申请参与共识表单数据", required = true) CreateMultiDepositForm form) throws Exception {
if (NulsContext.MAIN_NET_VERSION <= 1) {
return Result.getFailed(KernelErrorCode.VERSION_TOO_LOW).toRpcClientResult();
}
AssertUtil.canNotEmpty(form);
AssertUtil.canNotEmpty(form.getDeposit());
AssertUtil.canNotEmpty(form.getAgentHash());
AssertUtil.canNotEmpty(form.getAddress());
AssertUtil.canNotEmpty(form.getSignAddress());
if (form == null) {
return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
}
if (!NulsDigestData.validHash(form.getAgentHash())) {
return Result.getFailed(PocConsensusErrorCode.AGENT_NOT_EXIST).toRpcClientResult();
}
if (!AddressTool.validAddress(form.getSignAddress()) || !AddressTool.validAddress(form.getAddress())) {
return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
}
Account account = accountService.getAccount(form.getSignAddress()).getData();
if (null == account) {
return Result.getFailed(AccountErrorCode.ACCOUNT_NOT_EXIST).toRpcClientResult();
}
if (account.isEncrypted() && account.isLocked()) {
AssertUtil.canNotEmpty(form.getPassword(), "password is wrong");
if (!account.validatePassword(form.getPassword())) {
return Result.getFailed(AccountErrorCode.PASSWORD_IS_WRONG).toRpcClientResult();
}
}
Result<MultiSigAccount> sigAccountResult = accountService.getMultiSigAccount(form.getAddress());
MultiSigAccount multiSigAccount = sigAccountResult.getData();
// 验证签名账户是否属于多签账户,如果不是多签账户下的地址则提示错误
if (!AddressTool.validSignAddress(multiSigAccount.getPubKeyList(), account.getPubKey())) {
return Result.getFailed(AccountErrorCode.SIGN_ADDRESS_NOT_MATCH).toRpcClientResult();
}
Script redeemScript = accountLedgerService.getRedeemScript(multiSigAccount);
if (redeemScript == null) {
return Result.getFailed(AccountErrorCode.ACCOUNT_NOT_EXIST).toRpcClientResult();
}
DepositTransaction tx = new DepositTransaction();
TransactionSignature transactionSignature = new TransactionSignature();
List<Script> scripts = new ArrayList<>();
Deposit deposit = new Deposit();
deposit.setAddress(AddressTool.getAddress(form.getAddress()));
deposit.setAgentHash(NulsDigestData.fromDigestHex(form.getAgentHash()));
deposit.setDeposit(Na.valueOf(form.getDeposit()));
tx.setTxData(deposit);
CoinData coinData = new CoinData();
List<Coin> toList = new ArrayList<>();
// AddressTool.getAddress(addr)
if (deposit.getAddress()[2] == NulsContext.P2SH_ADDRESS_TYPE) {
Script scriptPubkey = SignatureUtil.createOutputScript(deposit.getAddress());
toList.add(new Coin(scriptPubkey.getProgram(), deposit.getDeposit(), PocConsensusConstant.CONSENSUS_LOCK_TIME));
} else {
toList.add(new Coin(deposit.getAddress(), deposit.getDeposit(), PocConsensusConstant.CONSENSUS_LOCK_TIME));
}
coinData.setTo(toList);
tx.setCoinData(coinData);
// 交易签名的长度为m*单个签名长度+赎回脚本长度
int scriptSignLenth = redeemScript.getProgram().length + ((int) multiSigAccount.getM()) * 72;
CoinDataResult result = accountLedgerService.getMutilCoinData(deposit.getAddress(), deposit.getDeposit(), tx.size() + scriptSignLenth, TransactionFeeCalculator.OTHER_PRICE_PRE_1024_BYTES);
if (null != result) {
if (result.isEnough()) {
tx.getCoinData().setFrom(result.getCoinList());
if (null != result.getChange()) {
tx.getCoinData().getTo().add(result.getChange());
}
} else {
return Result.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE).toRpcClientResult();
}
}
tx.setHash(NulsDigestData.calcDigestData(tx.serializeForHash()));
// 将赎回脚本先存储在签名脚本中
scripts.add(redeemScript);
transactionSignature.setScripts(scripts);
Result resultData = accountLedgerService.txMultiProcess(tx, transactionSignature, account, form.getPassword());
if (resultData.isSuccess()) {
Map<String, String> valueMap = new HashMap<>();
valueMap.put("txData", (String) resultData.getData());
return Result.getSuccess().setData(valueMap).toRpcClientResult();
}
return resultData.toRpcClientResult();
}
use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.
the class AccountLedgerServiceImpl method transferP2SH.
/**
* A transfers NULS to B 多签交易
*
* @param fromAddr address of A
* @param signAddr address of B
* @param values NULS amount
* @param password password of A
* @param remark remarks of transaction
* @param price Unit price of fee
* @param pubkeys 公钥列表
* @param m 至少需要签名验证通过
* @return Result
*/
@Override
public Result transferP2SH(byte[] fromAddr, byte[] signAddr, List<MultipleAddressTransferModel> outputs, Na values, String password, String remark, Na price, List<String> pubkeys, int m, String txdata) {
try {
Result<Account> accountResult = accountService.getAccount(signAddr);
if (accountResult.isFailed()) {
return accountResult;
}
Account account = accountResult.getData();
if (account.isEncrypted() && account.isLocked()) {
AssertUtil.canNotEmpty(password, "the password can not be empty");
if (!account.validatePassword(password)) {
return Result.getFailed(AccountErrorCode.PASSWORD_IS_WRONG);
}
}
if (!account.isOk()) {
return Result.getFailed(AccountErrorCode.IMPORTING_ACCOUNT);
}
TransferTransaction tx = new TransferTransaction();
TransactionSignature transactionSignature = new TransactionSignature();
List<P2PHKSignature> p2PHKSignatures = new ArrayList<>();
List<Script> scripts = new ArrayList<>();
// 如果txdata为空则表示当前请求为多签发起者调用,需要创建交易
if (txdata == null || txdata.trim().length() == 0) {
if (StringUtils.isNotBlank(remark)) {
try {
tx.setRemark(remark.getBytes(NulsConfig.DEFAULT_ENCODING));
} catch (UnsupportedEncodingException e) {
Log.error(e);
}
}
Script redeemScript = ScriptBuilder.createNulsRedeemScript(m, pubkeys);
tx.setTime(TimeService.currentTimeMillis());
CoinData coinData = new CoinData();
for (MultipleAddressTransferModel to : outputs) {
// 如果为多签地址
Coin toCoin = null;
if (to.getAddress()[2] == NulsContext.P2SH_ADDRESS_TYPE) {
Script scriptPubkey = SignatureUtil.createOutputScript(to.getAddress());
toCoin = new Coin(scriptPubkey.getProgram(), Na.valueOf(to.getAmount()));
} else {
toCoin = new Coin(to.getAddress(), Na.valueOf(to.getAmount()));
}
coinData.getTo().add(toCoin);
}
if (price == null) {
price = TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES;
}
// 交易签名的长度为m*单个签名长度+赎回脚本长度
int scriptSignLenth = redeemScript.getProgram().length + m * 72;
CoinDataResult coinDataResult = getMutilCoinData(fromAddr, values, tx.size() + coinData.size() + scriptSignLenth, price);
if (!coinDataResult.isEnough()) {
return Result.getFailed(AccountLedgerErrorCode.INSUFFICIENT_BALANCE);
}
coinData.setFrom(coinDataResult.getCoinList());
if (coinDataResult.getChange() != null) {
coinData.getTo().add(coinDataResult.getChange());
}
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);
// 当已签名数等于M则自动广播该交易
if (p2PHKSignatures.size() == SignatureUtil.getM(scripts.get(0))) {
// 将交易中的签名数据P2PHKSignatures按规则排序
Collections.sort(p2PHKSignatures, P2PHKSignature.PUBKEY_COMPARATOR);
// 将排序后的P2PHKSignatures的签名数据取出和赎回脚本结合生成解锁脚本
List<byte[]> signatures = new ArrayList<>();
for (P2PHKSignature p2PHKSignatureTemp : p2PHKSignatures) {
signatures.add(p2PHKSignatureTemp.getSignData().getSignBytes());
}
transactionSignature.setP2PHKSignatures(null);
Script scriptSign = ScriptBuilder.createNulsP2SHMultiSigInputScript(signatures, scripts.get(0));
transactionSignature.getScripts().clear();
transactionSignature.getScripts().add(scriptSign);
tx.setTransactionSignature(transactionSignature.serialize());
// 保存未确认交易到本地账户
Result saveResult = verifyAndSaveUnconfirmedTransaction(tx);
if (saveResult.isFailed()) {
if (KernelErrorCode.DATA_SIZE_ERROR.getCode().equals(saveResult.getErrorCode().getCode())) {
// 重新算一次交易(不超出最大交易数据大小下)的最大金额
Result rs = getMaxAmountOfOnce(fromAddr, tx, price);
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;
}
Result sendResult = transactionService.broadcastTx(tx);
if (sendResult.isFailed()) {
this.deleteTransaction(tx);
return sendResult;
}
return Result.getSuccess().setData(tx.getHash().getDigestHex());
} else // 如果签名数还没达到,则返回交易
{
transactionSignature.setP2PHKSignatures(p2PHKSignatures);
tx.setTransactionSignature(transactionSignature.serialize());
return Result.getSuccess().setData(Hex.encode(tx.serialize()));
}
} catch (IOException e) {
Log.error(e);
return Result.getFailed(KernelErrorCode.IO_ERROR);
} catch (NulsException e) {
Log.error(e);
return Result.getFailed(e.getErrorCode());
}
}
use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.
the class AccountLedgerServiceImpl method createP2shTransfer.
/**
* A transfers NULS to B 多签交易
*
* @param fromAddr 输入地址
* @param signAddr 签名地址
* @param outputs 输出地址
* @param password password of A
* @param remark remarks of transaction
* @return Result
*/
@Override
public Result createP2shTransfer(String fromAddr, String signAddr, List<MultipleAddressTransferModel> outputs, String password, String remark) {
try {
Result<Account> accountResult = accountService.getAccount(signAddr);
if (accountResult.isFailed()) {
return accountResult;
}
Account account = accountResult.getData();
if (account.isEncrypted() && account.isLocked()) {
AssertUtil.canNotEmpty(password, "the password can not be empty");
if (!account.validatePassword(password)) {
return Result.getFailed(AccountErrorCode.PASSWORD_IS_WRONG);
}
}
TransferTransaction tx = new TransferTransaction();
TransactionSignature transactionSignature = new TransactionSignature();
List<Script> scripts = new ArrayList<>();
Result<MultiSigAccount> result = accountService.getMultiSigAccount(fromAddr);
MultiSigAccount multiSigAccount = result.getData();
// 验证签名账户是否属于多签账户,如果不是多签账户下的地址则提示错误
if (!AddressTool.validSignAddress(multiSigAccount.getPubKeyList(), account.getPubKey())) {
return Result.getFailed(AccountErrorCode.SIGN_ADDRESS_NOT_MATCH);
}
Script redeemScript = getRedeemScript(multiSigAccount);
if (redeemScript == null) {
return Result.getFailed(AccountErrorCode.ACCOUNT_NOT_EXIST);
}
tx.setTime(TimeService.currentTimeMillis());
if (StringUtils.isNotBlank(remark)) {
try {
tx.setRemark(remark.getBytes(NulsConfig.DEFAULT_ENCODING));
} catch (UnsupportedEncodingException e) {
Log.error(e);
}
}
CoinData coinData = new CoinData();
Na values = Na.ZERO;
for (MultipleAddressTransferModel to : outputs) {
// 如果为多签地址
Coin toCoin = null;
values = values.add(Na.valueOf(to.getAmount()));
if (to.getAddress()[2] == NulsContext.P2SH_ADDRESS_TYPE) {
Script scriptPubkey = SignatureUtil.createOutputScript(to.getAddress());
toCoin = new Coin(scriptPubkey.getProgram(), Na.valueOf(to.getAmount()));
} else {
toCoin = new Coin(to.getAddress(), Na.valueOf(to.getAmount()));
}
coinData.getTo().add(toCoin);
}
// 交易签名的长度为m*单个签名长度+赎回脚本长度
int scriptSignLenth = redeemScript.getProgram().length + ((int) multiSigAccount.getM()) * 72;
CoinDataResult coinDataResult = getMutilCoinData(AddressTool.getAddress(fromAddr), values, tx.size() + coinData.size() + scriptSignLenth, TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES);
if (!coinDataResult.isEnough()) {
return Result.getFailed(AccountLedgerErrorCode.INSUFFICIENT_BALANCE);
}
coinData.setFrom(coinDataResult.getCoinList());
if (coinDataResult.getChange() != null) {
coinData.getTo().add(coinDataResult.getChange());
}
tx.setCoinData(coinData);
tx.setHash(NulsDigestData.calcDigestData(tx.serializeForHash()));
// 将赎回脚本先存储在签名脚本中
scripts.add(redeemScript);
transactionSignature.setScripts(scripts);
return txMultiProcess(tx, transactionSignature, account, password);
} catch (IOException e) {
Log.error(e);
return Result.getFailed(KernelErrorCode.IO_ERROR);
} catch (NulsException e) {
Log.error(e);
return Result.getFailed(e.getErrorCode());
} catch (Exception e) {
Log.error(e);
return Result.getFailed(AccountErrorCode.ACCOUNT_NOT_EXIST);
}
}
use of io.nuls.account.ledger.model.CoinDataResult in project nuls by nuls-io.
the class AccountLedgerServiceImpl method getCoinData.
@Override
public CoinDataResult getCoinData(byte[] address, Na amount, int size, Na price) {
if (null == price) {
throw new NulsRuntimeException(KernelErrorCode.PARAMETER_ERROR);
}
lock.lock();
try {
List<Coin> coinList = balanceManager.getCoinListByAddress(address);
coinList = coinList.stream().filter(coin1 -> coin1.usable() && !Na.ZERO.equals(coin1.getNa())).sorted(CoinComparator.getInstance()).collect(Collectors.toList());
CoinDataResult coinDataResult = CoinDataTool.getCoinData(address, amount, size, price, coinList);
return coinDataResult;
} finally {
lock.unlock();
}
}
Aggregations