Skip to content

Commit

Permalink
Merge branch 'develop' into mainnet
Browse files Browse the repository at this point in the history
  • Loading branch information
niels1286 committed May 29, 2019
2 parents 85c8bad + be79795 commit 08512c6
Show file tree
Hide file tree
Showing 78 changed files with 707 additions and 414 deletions.
8 changes: 4 additions & 4 deletions account-ledger-module/account-ledger/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,25 @@
<parent>
<artifactId>account-ledger-module</artifactId>
<groupId>io.nuls</groupId>
<version>1.2.1</version>
<version>1.2.2</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<groupId>io.nuls.account-ledger-module</groupId>
<artifactId>account-ledger</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>

<dependencies>
<dependency>
<groupId>io.nuls.core-module</groupId>
<artifactId>kernel</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>io.nuls.account-module</groupId>
<artifactId>account</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>
</dependency>
</dependencies>
<build>
Expand Down
16 changes: 8 additions & 8 deletions account-ledger-module/base/account-ledger-base/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,46 @@
<parent>
<artifactId>account-ledger-module</artifactId>
<groupId>io.nuls</groupId>
<version>1.2.1</version>
<version>1.2.2</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<groupId>io.nuls.account-ledger-module</groupId>
<artifactId>account-ledger-base</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>


<dependencies>
<dependency>
<groupId>io.nuls.account-ledger-module</groupId>
<artifactId>account-ledger</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>io.nuls.account-ledger-module</groupId>
<artifactId>account-ledger-storage</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>io.nuls.protocol-module</groupId>
<artifactId>protocol</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>io.nuls.consensus-module</groupId>
<artifactId>consensus</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>io.nuls.contract-module</groupId>
<artifactId>contract</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>io.nuls.utxo-accounts-module</groupId>
<artifactId>utxo-accounts</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
Expand Down
10 changes: 5 additions & 5 deletions account-ledger-module/base/account-ledger-rpc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
<parent>
<artifactId>account-ledger-module</artifactId>
<groupId>io.nuls</groupId>
<version>1.2.1</version>
<version>1.2.2</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<groupId>io.nuls.account-ledger-module</groupId>
<artifactId>account-ledger-rpc</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>


<dependencies>
Expand All @@ -39,17 +39,17 @@
<dependency>
<groupId>io.nuls.account-ledger-module</groupId>
<artifactId>account-ledger</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>io.nuls.account-ledger-module</groupId>
<artifactId>account-ledger-base</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>io.nuls.ledger-module</groupId>
<artifactId>ledger</artifactId>
<version>1.2.1</version>
<version>1.2.2</version>
</dependency>
</dependencies>
<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,24 @@
import io.nuls.kernel.lite.annotation.Autowired;
import io.nuls.kernel.lite.annotation.Component;
import io.nuls.kernel.model.*;
import io.nuls.kernel.script.P2PHKSignature;
import io.nuls.kernel.script.Script;
import io.nuls.kernel.script.SignatureUtil;
import io.nuls.kernel.script.TransactionSignature;
import io.nuls.kernel.utils.*;
import io.nuls.kernel.validate.ValidateResult;
import io.nuls.ledger.constant.LedgerErrorCode;
import io.nuls.ledger.service.LedgerService;
import io.nuls.protocol.constant.ProtocolConstant;
import io.nuls.protocol.model.tx.TransferTransaction;
import io.nuls.protocol.model.validator.TxMaxSizeValidator;
import io.protostuff.Output;
import io.swagger.annotations.*;
import org.spongycastle.util.Arrays;

import javax.ws.rs.*;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.*;
Expand Down Expand Up @@ -328,6 +332,60 @@ public RpcClientResult multipleAddressTransfer(@ApiParam(name = "form", value =
return result.toRpcClientResult();
}

@POST
@Path("/signMultipleTx")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "签名多地址转账交易", notes = "result.data: resultJson 返回签名后的txHex")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "success")
})
public RpcClientResult signMultipleTx(@ApiParam(name = "form", value = "签名多地址转账交易", required = true)
MulitpleTxForm form) {
String txHex = form.getTxHex();
List<String> priKeys = form.getPriKeys();
String password = form.getPassword();
if (StringUtils.isBlank(txHex) || priKeys.isEmpty()) {
return Result.getFailed(AccountErrorCode.PARAMETER_ERROR).toRpcClientResult();
}

List<String> signKeys = new ArrayList<>(priKeys.size());
for (int i = 0; i < priKeys.size(); i++) {
String encryptPrivKey = priKeys.get(i);
if (StringUtils.isBlank(password)) {
signKeys.add(encryptPrivKey);
continue;
}
byte[] privateKeyBytes = null;
try {
privateKeyBytes = AESEncrypt.decrypt(Hex.decode(encryptPrivKey), password);
} catch (Exception e) {
return Result.getFailed(AccountErrorCode.DECRYPT_ACCOUNT_ERROR).toRpcClientResult();
}
signKeys.add(Hex.encode(privateKeyBytes));
}

// conversion private key string to ECKey
List<ECKey> keys = signKeys.stream()
.map(p -> ECKey.fromPrivate(new BigInteger(Hex.decode(p))))
.collect(Collectors.toList());

try {
byte[] data = Hex.decode(txHex);
Transaction tx = TransactionManager.getInstance(new NulsByteBuffer(data));
List<P2PHKSignature> p2PHKSignatures = SignatureUtil.createSignaturesByEckey(tx, keys);
TransactionSignature transactionSignature = new TransactionSignature();
transactionSignature.setP2PHKSignatures(p2PHKSignatures);
tx.setTransactionSignature(transactionSignature.serialize());
txHex = Hex.encode(tx.serialize());
Map<String, String> map = new HashMap<>();
map.put("value", txHex);
return Result.getSuccess().setData(map).toRpcClientResult();
} catch (Exception e) {
Log.error(e);
return Result.getFailed(AccountErrorCode.DATA_PARSE_ERROR).toRpcClientResult();
}
}

// @POST
// @Path("/sendFrom")
// @Produces(MediaType.APPLICATION_JSON)
Expand Down Expand Up @@ -644,6 +702,121 @@ public RpcClientResult createTransaction(@ApiParam(name = "form", value = "导
return result.toRpcClientResult();
}

@POST
@Path("/createMultipleTx")
@Produces(MediaType.APPLICATION_JSON)
@ApiOperation(value = "创建多账户转账交易", notes = "result.data: resultJson 返回交易Hex")
@ApiResponses(value = {
@ApiResponse(code = 200, message = "success")
})
public RpcClientResult createMultipleTx(@ApiParam(name = "form", value = "交易输入输出", required = true)
TransactionForm form) {
if (form.getInputs() == null || form.getInputs().isEmpty()) {
return RpcClientResult.getFailed("inputs error");
}
if (form.getOutputs() == null || form.getOutputs().isEmpty()) {
return RpcClientResult.getFailed("outputs error");
}

byte[] remark = null;
if (!StringUtils.isBlank(form.getRemark())) {
try {
remark = form.getRemark().getBytes(NulsConfig.DEFAULT_ENCODING);
} catch (UnsupportedEncodingException e) {
return RpcClientResult.getFailed("remark error");
}
}

List<Coin> outputList = new ArrayList<>();
for (int i = 0; i < form.getOutputs().size(); i++) {
OutputDto outputDto = form.getOutputs().get(i);
Coin to = new Coin();
try {
if (!AddressTool.validAddress(outputDto.getAddress())) {
return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
}
byte[] owner = AddressTool.getAddress(outputDto.getAddress());
if (owner[2] == 3) {
Script scriptPubkey = SignatureUtil.createOutputScript(to.getAddress());
to.setOwner(scriptPubkey.getProgram());
} else {
to.setOwner(AddressTool.getAddress(outputDto.getAddress()));

}
} catch (Exception e) {
return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
}
try {
to.setNa(Na.valueOf(outputDto.getValue()));
} catch (Exception e) {
return Result.getFailed(AccountErrorCode.DATA_PARSE_ERROR).toRpcClientResult();
}
if (outputDto.getLockTime() < 0) {
return RpcClientResult.getFailed("lockTime error");
}

to.setLockTime(outputDto.getLockTime());
outputList.add(to);
}

List<Coin> inputsList = new ArrayList<>();
Set<String> addressSet = new HashSet<>();
for (int i = 0; i < form.getInputs().size(); i++) {
InputDto inputDto = form.getInputs().get(i);
if (inputDto.getAddress() == null) {
return Result.getFailed(AccountErrorCode.ADDRESS_ERROR).toRpcClientResult();
}
addressSet.add(inputDto.getAddress());
byte[] key = Arrays.concatenate(Hex.decode(inputDto.getFromHash()), new VarInt(inputDto.getFromIndex()).encode());
Coin coin = new Coin();
coin.setOwner(key);
coin.setNa(Na.valueOf(inputDto.getValue()));
coin.setLockTime(inputDto.getLockTime());
inputsList.add(coin);
}

TransferTransaction tx = new TransferTransaction();
CoinData coinData = new CoinData();
coinData.setFrom(inputsList);
coinData.setTo(outputList);
tx.setCoinData(coinData);
tx.setTime(TimeService.currentTimeMillis());
tx.setRemark(remark);
// 兜底,防止手续费不足
// 暂不支持 output 包含脚本交易

if (!isFeeEnough(tx, P2PHKSignature.SERIALIZE_LENGTH * addressSet.size())) {
return Result.getFailed(TransactionErrorCode.FEE_NOT_RIGHT).toRpcClientResult();
}

try {
String txHex = Hex.encode(tx.serialize());
Map<String, String> map = new HashMap<>();
map.put("value", txHex);
return Result.getSuccess().setData(map).toRpcClientResult();
} catch (IOException e) {
Log.error(e);
return RpcClientResult.getFailed(e.getMessage());
}
}

public static boolean isFeeEnough(Transaction tx, int signatureSize) {
int size = tx.size() + signatureSize;
Na minFee = TransactionFeeCalculator.getTransferFee(size);
//计算inputs和outputs的差额 ,求手续费
Na fee = Na.ZERO;
for (Coin coin : tx.getCoinData().getFrom()) {
fee = fee.add(coin.getNa());
}
for (Coin coin : tx.getCoinData().getTo()) {
fee = fee.subtract(coin.getNa());
}
if (fee.isLessThan(minFee)) {
return false;
}
return true;
}

@POST
@Path("/transaction/sign")
@Produces(MediaType.APPLICATION_JSON)
Expand Down Expand Up @@ -1097,6 +1270,16 @@ private Result getUnconfirmedTx(String hash) {
} else {
Transaction tx = txResult.getData();
tx.setStatus(TxStatusEnum.UNCONFIRM);
String fromAddress = null;
if (tx.getTransactionSignature() != null) {
TransactionSignature signature = new TransactionSignature();
signature.parse(new NulsByteBuffer(tx.getTransactionSignature()));
if (signature.getP2PHKSignatures() != null && signature.getP2PHKSignatures().size() == 1) {
byte[] addressBytes = AddressTool.getAddress(signature.getP2PHKSignatures().get(0).getPublicKey());
fromAddress = AddressTool.getStringAddressByBytes(addressBytes);
}
}

TransactionDto txDto = null;
CoinData coinData = tx.getCoinData();
if (coinData != null) {
Expand All @@ -1109,20 +1292,24 @@ private Result getUnconfirmedTx(String hash) {
Transaction fromTx;
Coin fromUtxo;
for (Coin from : froms) {
owner = from.getOwner();
// owner拆分出txHash和index
fromHash = AccountLegerUtils.getTxHashBytes(owner);
fromIndex = AccountLegerUtils.getIndex(owner);
// 查询from UTXO
fromHashObj = new NulsDigestData();
fromHashObj.parse(fromHash, 0);
//获取上一笔的to,先查未确认,如果没有再查已确认
fromTx = accountLedgerService.getUnconfirmedTransaction(fromHashObj).getData();
if (null == fromTx) {
fromTx = ledgerService.getTx(fromHashObj);
if (fromAddress != null) {
from.setFromAddress(fromAddress);
} else {
owner = from.getOwner();
// owner拆分出txHash和index
fromHash = AccountLegerUtils.getTxHashBytes(owner);
fromIndex = AccountLegerUtils.getIndex(owner);
// 查询from UTXO
fromHashObj = new NulsDigestData();
fromHashObj.parse(fromHash, 0);
//获取上一笔的to,先查未确认,如果没有再查已确认
fromTx = accountLedgerService.getUnconfirmedTransaction(fromHashObj).getData();
if (null == fromTx) {
fromTx = ledgerService.getTx(fromHashObj);
}
fromUtxo = fromTx.getCoinData().getTo().get(fromIndex);
from.setFrom(fromUtxo);
}
fromUtxo = fromTx.getCoinData().getTo().get(fromIndex);
from.setFrom(fromUtxo);
}
}
txDto = new TransactionDto(tx);
Expand Down
Loading

0 comments on commit 08512c6

Please sign in to comment.