use of io.nuls.core.tools.crypto.ECKey in project nuls by nuls-io.
the class AccountLedgerServiceImpl method getChangeWholeTxInfoList.
private TransferTransaction getChangeWholeTxInfoList(byte[] address, Account account, String password, Na price) {
// 这里要重新获取可用余额
List<Coin> coinList = balanceManager.getCoinListByAddress(address);
TransferTransaction tx = new TransferTransaction();
changeWholeLock.lock();
try {
tx.setTime(TimeService.currentTimeMillis());
// 默认coindata中to暂定38字节(一条tocoin)
int size = tx.size() + 38;
// 计算目标size,coindata中from的总大小
int targetSize = TxMaxSizeValidator.MAX_TX_SIZE - size;
if (coinList.isEmpty()) {
return null;
}
// 从大到小
Collections.sort(coinList, CoinComparatorDesc.getInstance());
Na max = Na.ZERO;
List<Coin> coins = new ArrayList<>();
byte signType = 0;
for (int i = 0; i < coinList.size(); i++) {
Coin coin = coinList.get(i);
if (!coin.usable()) {
continue;
}
if (coin.getNa().equals(Na.ZERO)) {
continue;
}
size += coin.size();
if (i == 127) {
size += 1;
}
if (size > targetSize) {
break;
}
coins.add(coin);
/**
* 判断是否是脚本验证UTXO
*/
if (signType != 3) {
if ((signType & 0x01) == 0 && coin.getTempOwner().length == 23) {
signType = (byte) (signType | 0x01);
size += P2PHKSignature.SERIALIZE_LENGTH;
} else if ((signType & 0x02) == 0 && coin.getTempOwner().length != 23) {
signType = (byte) (signType | 0x02);
size += P2PHKSignature.SERIALIZE_LENGTH;
}
}
max = max.add(coin.getNa());
}
Na fee = TransactionFeeCalculator.getFee(size, price);
max = max.subtract(fee);
CoinData coinData = new CoinData();
Coin toCoin = new Coin(address, max);
coinData.getTo().add(toCoin);
coinData.setFrom(coins);
tx.setCoinData(coinData);
// 一定要交易组装完才能setHash
tx.setHash(NulsDigestData.calcDigestData(tx.serializeForHash()));
// 生成签名
List<ECKey> signEckeys = new ArrayList<>();
List<ECKey> scriptEckeys = new ArrayList<>();
ECKey eckey = account.getEcKey(password);
// 如果最后一位为1则表示该交易包含普通签名
if ((signType & 0x01) == 0x01) {
signEckeys.add(eckey);
}
// 如果倒数第二位位为1则表示该交易包含脚本签名
if ((signType & 0x02) == 0x02) {
scriptEckeys.add(eckey);
}
SignatureUtil.createTransactionSignture(tx, scriptEckeys, signEckeys);
return tx;
} catch (RuntimeException | IOException | NulsException e) {
Log.error(e);
return null;
} finally {
changeWholeLock.unlock();
}
}
use of io.nuls.core.tools.crypto.ECKey in project nuls by nuls-io.
the class AccountLedgerServiceImpl method dapp.
@Override
public Result dapp(byte[] from, String password, byte[] data, byte[] remark) {
Result<Account> accountResult = accountService.getAccount(from);
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);
}
}
DataTransaction tx = new DataTransaction();
tx.setRemark(remark);
tx.setTime(TimeService.currentTimeMillis());
LogicData logicData = new LogicData(data);
tx.setTxData(logicData);
CoinData coinData = new CoinData();
try {
CoinDataResult coinDataResult = getCoinData(from, Na.ZERO, tx.size() + coinData.size(), 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()));
// 生成签名
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 = verifyAndSaveUnconfirmedTransaction(tx);
if (saveResult.isFailed()) {
if (KernelErrorCode.DATA_SIZE_ERROR.getCode().equals(saveResult.getErrorCode().getCode())) {
// 重新算一次交易(不超出最大交易数据大小下)的最大金额
Result rs = getMaxAmountOfOnce(from, tx, TransactionFeeCalculator.MIN_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;
}
Result sendResult = transactionService.broadcastTx(tx);
if (sendResult.isFailed()) {
this.deleteTransaction(tx);
return sendResult;
}
return Result.getSuccess().setData(tx.getHash().getDigestHex());
} catch (NulsException e) {
Log.error(e);
return Result.getFailed(e.getErrorCode());
} catch (IOException e) {
Log.error(e);
return Result.getFailed(KernelErrorCode.IO_ERROR);
}
}
use of io.nuls.core.tools.crypto.ECKey in project nuls by nuls-io.
the class AccountLedgerServiceImpl method transfer.
@Override
public Result transfer(byte[] from, byte[] to, Na values, String password, byte[] remark, Na price) {
try {
if (NulsContext.WALLET_STATUS == NulsConstant.SYNCHING) {
return Result.getFailed(KernelErrorCode.WALLET_STATUS_SYNCHING);
} else if (NulsContext.WALLET_STATUS == NulsConstant.ROLLBACK) {
return Result.getFailed(KernelErrorCode.WALLET_STATUS_ROLLBACK);
}
Result<Account> accountResult = accountService.getAccount(from);
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);
}
// 检查to是否为合约地址,如果是合约地址,则返回错误
if (contractService.isContractAddress(to)) {
return Result.getFailed(ContractErrorCode.NON_CONTRACTUAL_TRANSACTION_NO_TRANSFER);
}
TransferTransaction tx = new TransferTransaction();
tx.setRemark(remark);
tx.setTime(TimeService.currentTimeMillis());
CoinData coinData = new CoinData();
// 如果为多签地址则以脚本方式存储
Coin toCoin;
if (to[2] == NulsContext.P2SH_ADDRESS_TYPE) {
Script scriptPubkey = SignatureUtil.createOutputScript(to);
toCoin = new Coin(scriptPubkey.getProgram(), values);
} else {
toCoin = new Coin(to, values);
}
coinData.getTo().add(toCoin);
if (price == null) {
price = TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES;
}
CoinDataResult coinDataResult = getCoinData(from, values, tx.size() + coinData.size(), 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()));
// 生成签名
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 = verifyAndSaveUnconfirmedTransaction(tx);
if (saveResult.isFailed()) {
if (KernelErrorCode.DATA_SIZE_ERROR.getCode().equals(saveResult.getErrorCode().getCode())) {
// 重新算一次交易(不超出最大交易数据大小下)的最大金额
Result rs = getMaxAmountOfOnce(from, 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;
}
// transactionService.newTx(tx);
Result sendResult = transactionService.broadcastTx(tx);
if (sendResult.isFailed()) {
this.deleteTransaction(tx);
return sendResult;
}
return Result.getSuccess().setData(tx.getHash().getDigestHex());
} 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.core.tools.crypto.ECKey in project nuls by nuls-io.
the class AccountLedgerResource method signTransaction.
@POST
@Path("/transaction/sign")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "交易签名", notes = "result.data: resultJson 返回交易对象")
@ApiResponses(value = { @ApiResponse(code = 200, message = "success") })
public RpcClientResult signTransaction(@ApiParam(name = "form", value = "交易信息", required = true) TransactionHexForm form) {
if (StringUtils.isBlank(form.getPriKey())) {
return Result.getFailed(AccountErrorCode.PARAMETER_ERROR).toRpcClientResult();
}
if (StringUtils.isBlank(form.getTxHex())) {
return Result.getFailed(AccountErrorCode.PARAMETER_ERROR).toRpcClientResult();
}
if (!AddressTool.validAddress(form.getAddress())) {
return Result.getFailed(AccountErrorCode.PARAMETER_ERROR).toRpcClientResult();
}
String priKey = form.getPriKey();
if (StringUtils.isNotBlank(form.getPassword())) {
if (StringUtils.validPassword(form.getPassword())) {
// decrypt
byte[] privateKeyBytes = null;
try {
privateKeyBytes = AESEncrypt.decrypt(Hex.decode(priKey), form.getPassword());
} catch (CryptoException e) {
return Result.getFailed(AccountLedgerErrorCode.PARAMETER_ERROR).toRpcClientResult();
}
priKey = Hex.encode(privateKeyBytes);
} else {
return Result.getFailed(AccountLedgerErrorCode.PARAMETER_ERROR).toRpcClientResult();
}
}
if (!ECKey.isValidPrivteHex(priKey)) {
return Result.getFailed(AccountErrorCode.PARAMETER_ERROR).toRpcClientResult();
}
// is private key matches address
ECKey key = ECKey.fromPrivate(new BigInteger(1, Hex.decode(priKey)));
try {
String newAddress = AccountTool.newAddress(key).getBase58();
if (!newAddress.equals(form.getAddress())) {
return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
}
} catch (NulsException e) {
return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
}
try {
byte[] data = Hex.decode(form.getTxHex());
Transaction tx = TransactionManager.getInstance(new NulsByteBuffer(data));
tx = accountLedgerService.signTransaction(tx, key);
// Result validateResult = tx.verify();
// if (validateResult.isFailed()) {
// return Result.getFailed(validateResult.getErrorCode()).toRpcClientResult();
// }
// for (Coin coin : tx.getCoinData().getFrom()) {
// Coin utxo = ledgerService.getUtxo(coin.());
// if (utxo == null) {
// return Result.getFailed(LedgerErrorCode.UTXO_NOT_FOUND).toRpcClientResult();
// }
//
// if (!form.getAddress().equals(AddressTool.getStringAddressByBytes(utxo.()))) {
// return Result.getFailed(LedgerErrorCode.INVALID_INPUT).toRpcClientResult();
// }
//
// }
Map<String, String> map = new HashMap<>();
map.put("value", Hex.encode(tx.serialize()));
return Result.getSuccess().setData(map).toRpcClientResult();
} catch (Exception e) {
Log.error(e);
return Result.getFailed(LedgerErrorCode.DATA_PARSE_ERROR).toRpcClientResult();
}
}
use of io.nuls.core.tools.crypto.ECKey in project nuls by nuls-io.
the class Script method createMultiSigOutputScript.
/**
* Creates a program that requires at least N of the given keys to sign, using OP_CHECKMULTISIG.
* 将OutputScript/scriptPublicKry 转为字节数组 用于传输
*/
public static byte[] createMultiSigOutputScript(int threshold, List<ECKey> pubkeys) {
checkArgument(threshold > 0);
checkArgument(threshold <= pubkeys.size());
// That's the max we can represent with a single opcode.
checkArgument(pubkeys.size() <= 16);
if (pubkeys.size() > 3) {
log.warn("Creating a multi-signature output that is non-standard: {} pubkeys, should be <= 3", pubkeys.size());
}
try {
ByteArrayOutputStream bits = new ByteArrayOutputStream();
bits.write(encodeToOpN(threshold));
for (ECKey key : pubkeys) {
writeBytes(bits, key.getPubKey());
}
bits.write(encodeToOpN(pubkeys.size()));
bits.write(OP_CHECKMULTISIG);
return bits.toByteArray();
} catch (IOException e) {
// Cannot happen.
throw new RuntimeException(e);
}
}
Aggregations