use of io.nuls.contract.ledger.module.ContractBalance in project nuls by nuls-io.
the class ContractTxServiceImpl method contractDeleteTx.
/**
* 创建删除智能合约的交易
*
* @param sender 交易创建者
* @param contractAddress 合约地址
* @param password 账户密码
* @param remark 备注
* @return
*/
@Override
public Result contractDeleteTx(String sender, String contractAddress, String password, String remark) {
try {
AssertUtil.canNotEmpty(sender, "the sender address can not be empty");
AssertUtil.canNotEmpty(contractAddress, "the contractAddress can not be empty");
byte[] contractAddressBytes = AddressTool.getAddress(contractAddress);
Result<ContractAddressInfoPo> contractAddressInfoPoResult = contractAddressStorageService.getContractAddressInfo(contractAddressBytes);
if (contractAddressInfoPoResult.isFailed()) {
return contractAddressInfoPoResult;
}
ContractAddressInfoPo contractAddressInfoPo = contractAddressInfoPoResult.getData();
if (contractAddressInfoPo == null) {
return Result.getFailed(ContractErrorCode.CONTRACT_ADDRESS_NOT_EXIST);
}
BlockHeader blockHeader = NulsContext.getInstance().getBestBlock().getHeader();
// 当前区块状态根
byte[] stateRoot = ContractUtil.getStateRoot(blockHeader);
// 获取合约当前状态
ProgramStatus status = vmHelper.getContractStatus(stateRoot, contractAddressBytes);
boolean isTerminatedContract = ContractUtil.isTerminatedContract(status.ordinal());
if (isTerminatedContract) {
return Result.getFailed(ContractErrorCode.CONTRACT_DELETED);
}
byte[] senderBytes = AddressTool.getAddress(sender);
if (!ArraysTool.arrayEquals(senderBytes, contractAddressInfoPo.getSender())) {
return Result.getFailed(ContractErrorCode.CONTRACT_DELETE_CREATER);
}
Result<ContractBalance> result = contractBalanceManager.getBalance(contractAddressBytes);
ContractBalance balance = (ContractBalance) result.getData();
if (balance == null) {
return result;
}
Na totalBalance = balance.getBalance();
if (totalBalance.compareTo(Na.ZERO) != 0) {
return Result.getFailed(ContractErrorCode.CONTRACT_DELETE_BALANCE);
}
Result<Account> accountResult = accountService.getAccount(sender);
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);
}
DeleteContractTransaction tx = new DeleteContractTransaction();
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());
// 组装txData
DeleteContractData deleteContractData = new DeleteContractData();
deleteContractData.setContractAddress(contractAddressBytes);
deleteContractData.setSender(senderBytes);
tx.setTxData(deleteContractData);
// 计算CoinData
/*
* 没有Gas消耗,在终止智能合约里
*/
CoinData coinData = new CoinData();
// 总花费 终止智能合约的交易手续费按普通交易计算手续费
CoinDataResult coinDataResult = accountLedgerService.getCoinData(senderBytes, Na.ZERO, tx.size() + coinData.size(), TransactionFeeCalculator.MIN_PRICE_PRE_1024_BYTES);
if (!coinDataResult.isEnough()) {
return Result.getFailed(TransactionErrorCode.INSUFFICIENT_BALANCE);
}
coinData.setFrom(coinDataResult.getCoinList());
// 找零的UTXO
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 = accountLedgerService.verifyAndSaveUnconfirmedTransaction(tx);
if (saveResult.isFailed()) {
if (KernelErrorCode.DATA_SIZE_ERROR.getCode().equals(saveResult.getErrorCode().getCode())) {
// 重新算一次交易(不超出最大交易数据大小下)的最大金额
Result rs = accountLedgerService.getMaxAmountOfOnce(senderBytes, 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()) {
// 失败则回滚
accountLedgerService.deleteTransaction(tx);
return sendResult;
}
return Result.getSuccess().setData(tx.getHash().getDigestHex());
} catch (IOException e) {
Log.error(e);
Result result = Result.getFailed(ContractErrorCode.CONTRACT_TX_CREATE_ERROR);
result.setMsg(e.getMessage());
return result;
} 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.contract.ledger.module.ContractBalance in project nuls by nuls-io.
the class ContractBalanceManager method getBalance.
/**
* 获取账户余额
*
* @param address
* @param bestHeight
* @return
*/
public Result<ContractBalance> getBalance(byte[] address, Long blockHeight) {
lock.lock();
try {
if (address == null || address.length != Address.ADDRESS_LENGTH) {
return Result.getFailed(ContractErrorCode.PARAMETER_ERROR);
}
String addressKey = asString(address);
ContractBalance balance;
// 打包或验证区块前创建一个临时余额区,实时更新余额,打包完或验证区块后移除
Map<String, ContractBalance> tempBalanceMap = tempBalanceMapManager.get();
if (tempBalanceMap != null) {
balance = tempBalanceMap.get(addressKey);
// 临时余额区没有余额,则从真实余额中取值
if (balance == null) {
balance = balanceMap.get(addressKey);
// 真实余额区也没有值时,初始化真实余额区和临时余额区
if (balance == null) {
balanceMap.put(addressKey, new ContractBalance());
balance = new ContractBalance();
tempBalanceMap.put(addressKey, balance);
} else {
// 真实余额区有值时,深度复制这个值到临时余额区,避免真实余额被临时余额所影响
// 刷新处理余额中的锁定余额
this.handleLockedBalances(balance, blockHeight);
balance = depthClone(balance);
tempBalanceMap.put(addressKey, balance);
}
}
} else {
balance = balanceMap.get(addressKey);
if (balance == null) {
balance = new ContractBalance();
balanceMap.put(addressKey, balance);
} else {
// 刷新处理余额中的锁定余额
this.handleLockedBalances(balance, blockHeight);
}
}
return Result.getSuccess().setData(balance);
} finally {
lock.unlock();
}
}
use of io.nuls.contract.ledger.module.ContractBalance in project nuls by nuls-io.
the class ContractBalanceManager method refreshBalance.
/**
* 刷新余额
*/
public void refreshBalance(List<Coin> addUtxoList, List<Coin> deleteUtxoList) {
lock.lock();
try {
ContractBalance balance;
String strAddress;
if (addUtxoList != null) {
for (Coin coin : addUtxoList) {
strAddress = asString(coin.getTempOwner());
balance = balanceMap.get(strAddress);
if (balance == null) {
balance = new ContractBalance();
balanceMap.put(strAddress, balance);
}
// 共识奖励的utxo
if (coin.getLockTime() != 0) {
balance.getConsensusRewardCoins().put(coin.getKey(), coin);
} else {
balance.addUsable(coin.getNa());
}
}
}
if (deleteUtxoList != null) {
for (Coin coin : deleteUtxoList) {
strAddress = asString(coin.getTempOwner());
balance = balanceMap.get(strAddress);
if (balance == null) {
balance = new ContractBalance();
balanceMap.put(strAddress, balance);
}
// 共识奖励的utxo
if (coin.getLockTime() != 0) {
balance.getConsensusRewardCoins().remove(coin.getKey());
} else {
balance.minusUsable(coin.getNa());
}
}
}
} finally {
lock.unlock();
}
}
use of io.nuls.contract.ledger.module.ContractBalance in project nuls by nuls-io.
the class ContractBalanceManager method depthClone.
private ContractBalance depthClone(ContractBalance contractBalance) {
if (contractBalance == null) {
return null;
}
LinkedHashMap<String, Coin> lockedCoins = contractBalance.getConsensusRewardCoins();
LinkedHashMap<String, Coin> lockedCoinsClone = MapUtil.createLinkedHashMap(lockedCoins.size());
Collection<Coin> values = lockedCoins.values();
for (Coin coin : values) {
lockedCoinsClone.put(coin.getKey(), coin);
}
ContractBalance result = new ContractBalance(Na.valueOf(contractBalance.getUsable().getValue()), Na.valueOf(contractBalance.getLocked().getValue()), Na.valueOf(contractBalance.getUsableConsensusReward().getValue()), lockedCoinsClone);
return result;
}
use of io.nuls.contract.ledger.module.ContractBalance in project nuls by nuls-io.
the class ContractBalanceManager method initContractBalance.
/**
* 初始化缓存本地所有合约账户的余额信息
*/
public void initContractBalance() {
balanceMap = new ConcurrentHashMap<>();
List<Entry<byte[], byte[]>> rawList = contractUtxoStorageService.loadAllCoinList();
Coin coin;
String strAddress;
ContractBalance balance;
for (Entry<byte[], byte[]> coinEntry : rawList) {
coin = new Coin();
try {
coin.parse(coinEntry.getValue(), 0);
// strAddress = asString(coin.getOwner());
coin.setKey(asString(coinEntry.getKey()));
strAddress = asString(coin.getAddress());
} catch (NulsException e) {
Log.error("parse contract coin error form db", e);
continue;
}
balance = balanceMap.get(strAddress);
if (balance == null) {
balance = new ContractBalance();
balanceMap.put(strAddress, balance);
}
// 共识奖励的utxo
if (coin.getLockTime() != 0) {
balance.getConsensusRewardCoins().put(coin.getKey(), coin);
} else {
balance.addUsable(coin.getNa());
}
}
}
Aggregations