use of io.nuls.kernel.utils.NulsByteBuffer 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.kernel.utils.NulsByteBuffer in project nuls by nuls-io.
the class AccountLedgerServiceImpl method signMultiTransaction.
/**
* A transfers NULS to B 多签交易
*
* @param signAddr 签名地址
* @param password password of A
* @param txdata 需要签名的数据
* @return Result
*/
@Override
public Result signMultiTransaction(String signAddr, String password, 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);
}
}
byte[] txByte = Hex.decode(txdata);
Transaction tx = TransactionManager.getInstance(new NulsByteBuffer(txByte));
TransactionSignature transactionSignature = new TransactionSignature();
transactionSignature.parse(new NulsByteBuffer(tx.getTransactionSignature()));
// 验证签名地址账户是否属于多签账户
List<byte[]> pubkeys = SignatureUtil.getPublicKeyList(transactionSignature.getScripts().get(0));
if (pubkeys == null || pubkeys.size() == 0 || !AddressTool.validSignAddress(pubkeys, account.getPubKey())) {
return Result.getFailed(AccountErrorCode.SIGN_ADDRESS_NOT_MATCH);
}
return txMultiProcess(tx, transactionSignature, account, password);
} 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.kernel.utils.NulsByteBuffer in project nuls by nuls-io.
the class CreateP2shTransactionForm method validAddress.
public static boolean validAddress(String address) {
if (StringUtils.isBlank(address)) {
return false;
}
byte[] bytes;
try {
bytes = Base58.decode(address);
if (bytes.length != Address.ADDRESS_LENGTH + 1) {
return false;
}
} catch (NulsException e) {
return false;
} catch (Exception e) {
return false;
}
NulsByteBuffer byteBuffer = new NulsByteBuffer(bytes);
short chainId;
byte type;
try {
chainId = byteBuffer.readShort();
type = byteBuffer.readByte();
} catch (NulsException e) {
Log.error(e);
return false;
}
if (NulsContext.getInstance().getDefaultChainId() != chainId) {
return false;
}
if (NulsContext.MAIN_NET_VERSION <= 1 || NulsContext.CONTRACT_ADDRESS_TYPE == type) {
return false;
}
if (NulsContext.DEFAULT_ADDRESS_TYPE != type && NulsContext.P2SH_ADDRESS_TYPE != type) {
return false;
}
try {
AddressTool.checkXOR(bytes);
} catch (Exception e) {
return false;
}
return true;
}
use of io.nuls.kernel.utils.NulsByteBuffer in project nuls by nuls-io.
the class BaseNulsData method parse.
@Override
public final void parse(byte[] bytes, int cursor) throws NulsException {
if (bytes == null || bytes.length == 0 || ((bytes.length == 4) && Arrays.equals(NulsConstant.PLACE_HOLDER, bytes))) {
return;
}
NulsByteBuffer byteBuffer = new NulsByteBuffer(bytes);
byteBuffer.setCursor(cursor);
this.parse(byteBuffer);
}
use of io.nuls.kernel.utils.NulsByteBuffer in project nuls by nuls-io.
the class ChainContainer method verifyRedPunish.
private boolean verifyRedPunish(RedPunishTransaction data) {
RedPunishData punishData = data.getTxData();
if (ConsensusConfig.getSeedNodeStringList().contains(AddressTool.getStringAddressByBytes(punishData.getAddress()))) {
Log.warn("The seed node can not be punished!");
return false;
}
HeaderSignValidator validator = NulsContext.getServiceBean(HeaderSignValidator.class);
LedgerService ledgerService = NulsContext.getServiceBean(LedgerService.class);
if (punishData.getReasonCode() == PunishReasonEnum.DOUBLE_SPEND.getCode()) {
if (NulsContext.MAIN_NET_VERSION <= 1) {
Log.warn("The red punish tx need higher version!");
return false;
}
SmallBlock smallBlock = new SmallBlock();
try {
smallBlock.parse(punishData.getEvidence(), 0);
} catch (NulsException e) {
Log.error(e);
return false;
}
BlockHeader header = smallBlock.getHeader();
if (header.getTime() != data.getTime()) {
return false;
}
ValidateResult result = validator.validate(header);
if (result.isFailed()) {
Log.warn(result.getMsg());
return false;
}
List<NulsDigestData> txHashList = smallBlock.getTxHashList();
if (!header.getMerkleHash().equals(NulsDigestData.calcMerkleDigestData(txHashList))) {
Log.warn(TransactionErrorCode.TX_DATA_VALIDATION_ERROR.getMsg());
return false;
}
List<Transaction> txList = smallBlock.getSubTxList();
if (null == txList || txList.size() < 2) {
Log.warn(TransactionErrorCode.TX_DATA_VALIDATION_ERROR.getMsg());
return false;
}
result = ledgerService.verifyDoubleSpend(txList);
if (result.isSuccess()) {
Log.warn(PocConsensusErrorCode.TRANSACTIONS_NEVER_DOUBLE_SPEND.getMsg());
return false;
}
} else if (punishData.getReasonCode() == PunishReasonEnum.BIFURCATION.getCode()) {
if (NulsContext.MAIN_NET_VERSION <= 1) {
Log.warn("The red punish tx need higher version!");
return false;
}
NulsByteBuffer byteBuffer = new NulsByteBuffer(punishData.getEvidence());
// 轮次
long[] roundIndex = new long[NulsContext.REDPUNISH_BIFURCATION];
for (int i = 0; i < NulsContext.REDPUNISH_BIFURCATION && !byteBuffer.isFinished(); i++) {
BlockHeader header1 = null;
BlockHeader header2 = null;
try {
header1 = byteBuffer.readNulsData(new BlockHeader());
header2 = byteBuffer.readNulsData(new BlockHeader());
} catch (NulsException e) {
Log.error(e);
}
if (null == header1 || null == header2) {
Log.warn(KernelErrorCode.DATA_NOT_FOUND.getMsg());
return false;
}
if (header1.getHeight() != header2.getHeight()) {
Log.warn(TransactionErrorCode.TX_DATA_VALIDATION_ERROR.getMsg());
return false;
}
if (i == NulsContext.REDPUNISH_BIFURCATION - 1 && (header1.getTime() + header2.getTime()) / 2 != data.getTime()) {
return false;
}
ValidateResult result = validator.validate(header1);
if (result.isFailed()) {
Log.warn(TransactionErrorCode.TX_DATA_VALIDATION_ERROR.getMsg());
return false;
}
result = validator.validate(header2);
if (result.isFailed()) {
Log.warn(TransactionErrorCode.TX_DATA_VALIDATION_ERROR.getMsg());
return false;
}
if (!Arrays.equals(header1.getBlockSignature().getPublicKey(), header2.getBlockSignature().getPublicKey())) {
Log.warn(TransactionErrorCode.SIGNATURE_ERROR.getMsg());
return false;
}
BlockExtendsData blockExtendsData = new BlockExtendsData(header1.getExtend());
roundIndex[i] = blockExtendsData.getRoundIndex();
}
// 验证轮次是否连续
boolean rs = true;
for (int i = 0; i < roundIndex.length; i++) {
if (i < roundIndex.length - 2 && roundIndex[i + 1] - roundIndex[i] != 1) {
rs = false;
break;
}
}
if (!rs) {
Log.warn(PocConsensusErrorCode.RED_CARD_VERIFICATION_FAILED.getMsg());
return false;
}
} else if (punishData.getReasonCode() != PunishReasonEnum.TOO_MUCH_YELLOW_PUNISH.getCode()) {
Log.warn(PocConsensusErrorCode.RED_CARD_VERIFICATION_FAILED.getMsg());
return false;
}
try {
return verifyCoinData(data);
} catch (IOException e) {
Log.error(e);
return false;
}
}
Aggregations