diff --git a/README.md b/README.md index 5ef308288..729545eef 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,24 @@ -# NULS 2.0 -## Welcome to NULS! ## +# NULS2.0 Node Wallet Implemented in Java +NULS v2 is the main running program of NULS 2.0 nodes. It contains 3 microservice modules: +- nuls-cores +- nuls-cmd-client +- nuls-api +nuls-cores consists of 11 sub-modules: +https://github.com/nuls-io/nuls-v2/tree/master/module/nuls-cores/src/main/java/io/nuls -## Introduction -NULS is a blockchain infrastructure -that provides customizable services -and is also a global open-source -community blockchain project. NULS -adopts micro-services to achieve a -highly modular underlying -architecture, using smart contracts -and cross-chain technologies, -combined with the ability of Chain -Factory to quickly build chains, reduce -development costs, and accelerate -blockchain business application -landing. ## Getting Started -test +Start a NULS node according to this boot. ### Download Release Download URL: [RELEASES](https://github.com/nuls-io/nuls-v2/releases) -## Running NULS 2.0 +## Running NULS2.0 ### Bootstrap @@ -58,13 +49,11 @@ Note: The command will automatically end when all modules are started. ## Docker Quick Start -Stay tuned - -## Explorer and Web Wallet +Stay tuned. Join Discord to find out. -Explorer URL: [http://beta.nulscan.io/](http://beta.nulscan.io/) +## Explorer -Web Wallet: [http://beta.wallet.nuls.io/](http://beta.wallet.nuls.io/) +Explorer URL: [https://nulscan.io/](https://nulscan.io/) ## ChainBox Tutorial @@ -72,44 +61,57 @@ Please check the following documents: [https://docs.nuls.io/NULS2.0/chainBoxGuide.html](https://docs.nuls.io/NULS2.0/chainBoxGuide.html) -## Debug +## Modules Description -Stay tuned +Please check the following documents: -## Configuration +[https://docs.nuls.io/Docs/c_module.html](https://docs.nuls.io/Docs/c_module.html) -Stay tuned +Note: Some documents are in the process of being updated, so please understand if there are some inconsistencies. -## Interfaces +## Contribute to NULS2.0 +Click Star and Fork to start contributing improvements to NULS v2. +Hope more contributors can submit improvement suggestions and bug reports here. +Issues: https://github.com/nuls-io/nuls-v2/issues -Stay tuned -## Modules Description -Please check the following documents: +# Welcome to NULS! # -[https://docs.nuls.io/Docs/c_module.html](https://docs.nuls.io/Docs/c_module.html) +NULS — Making It Easier To Innovate -Note: Some documents are in the process of being updated, so please understand if there are some inconsistencies. +## Introduction + +NULS is a blockchain infrastructure that provides customizable services and is also a global open-source community blockchain project. NULS adopts micro-services to achieve a highly modular underlying architecture, using smart contracts and cross-chain technologies, combined with the ability of ChainBox to quickly build chains, reduce development costs, and accelerate blockchain business application landing. + +## Contribute to NULS +We are committed to making blockchain technology simpler and our slogan is "NULS Making It Easier to Innovate". + +Get to know NULS developers +https://nuls.io/developer + +You are welcome to contribute to NULS! We sincerely invite developers with rich experience in the blockchain field to join the NULS technology community. +https://nuls.io/community + +Documentation:https://docs.nuls.io + +NULS Brand Assets: https://nuls.io/brand-assets -## Contribution -Contributions to NULS are welcomed! We sincerely invite developers who are experienced in the blockchain field to join the NULS technology community. Details: https://nuls.community/d/9-invitation-of-community-developers. To be a great community, Nuls needs to welcome developers from all walks of life, with different backgrounds, and with a wide range of experience. ## License -Nuls is released under the [MIT](http://opensource.org/licenses/MIT) license. -Modules added in the future may be released under a different license specified in their module library path. +NULS is released under the [MIT](http://opensource.org/licenses/MIT) license. +Modules added in the future may be release under different license, will specified in the module library path. ## Community -- [nuls.io](https://nuls.io/) -- [@Twitter](https://twitter.com/nulsservice) -- [Facebook](https://www.facebook.com/nulscommunity/) -- [YouTube channel](https://www.youtube.com/channel/UC8FkLeF4QW6Undm4B3InN1Q?view_as=subscriber) -- Telegram [NULS Community](https://t.me/Nulsio) -- Telegram [NULS Chinese community](https://t.me/Nulscn) - -#### +- Website: https://nuls.io +- Twitter: https://twitter.com/nuls +- Discord:https://discord.gg/aRCwbj47WN +- Telegram: https://t.me/Nulsio +- Medium: https://nuls.medium.com +- Forum: https://forum.nuls.io +- GitHub: https://github.com/nuls-io -test +#### diff --git a/build/nulstar/start.sh b/build/nulstar/start.sh index ce48f51c7..98788c687 100755 --- a/build/nulstar/start.sh +++ b/build/nulstar/start.sh @@ -9,7 +9,7 @@ if [ ! -f "${CONFIG}" ] ; then exit 0 fi availableMem=`free | awk '/Mem/ {print $7}'` -xmsMem=6000000 +xmsMem=4000000 if [ "$availableMem" -lt $xmsMem ] then echo "available mem must be equal or greater than ${xmsMem}KB"; diff --git a/common/nuls-base-api-provider/src/main/java/io/nuls/base/api/provider/block/BlockService.java b/common/nuls-base-api-provider/src/main/java/io/nuls/base/api/provider/block/BlockService.java index 3a9d37fd4..e81b5a7f0 100644 --- a/common/nuls-base-api-provider/src/main/java/io/nuls/base/api/provider/block/BlockService.java +++ b/common/nuls-base-api-provider/src/main/java/io/nuls/base/api/provider/block/BlockService.java @@ -20,5 +20,5 @@ public interface BlockService { Result getBlockHeaderByLastHeight(GetBlockHeaderByLastHeightReq req); - Result rollback(GetBlockHeaderByHeightReq getBlockHeaderByHeightReq); + Result rollback(GetBlockHeaderByHeightReq getBlockHeaderByHeightReq); } diff --git a/common/nuls-base-api-provider/src/main/java/io/nuls/base/api/provider/block/BlockServiceForRpc.java b/common/nuls-base-api-provider/src/main/java/io/nuls/base/api/provider/block/BlockServiceForRpc.java index 9c58c826c..1468a7a10 100644 --- a/common/nuls-base-api-provider/src/main/java/io/nuls/base/api/provider/block/BlockServiceForRpc.java +++ b/common/nuls-base-api-provider/src/main/java/io/nuls/base/api/provider/block/BlockServiceForRpc.java @@ -49,8 +49,8 @@ public Result getBlockHeaderByLastHeight(GetBlockHeaderByLastHe } @Override - public Result rollback(GetBlockHeaderByHeightReq req) { - return _call("roll_back", req, this::tranderBlockHeader); + public Result rollback(GetBlockHeaderByHeightReq req) { + return _call("roll_back", req, this::tranderString); } @Override @@ -62,6 +62,14 @@ private Result _call(String method, Object req, Function tranderString(Map result) { + String hexString = (String) result.get("value"); + if (StringUtils.isBlank(hexString)) { + return success(null); + } + return success(hexString); + } + private Result tranderBlockHeader(Map result) { try { String hexString = (String) result.get("value"); diff --git a/common/nuls-base-protocol-update/src/main/java/io/nuls/base/protocol/cmd/MessageDispatcher.java b/common/nuls-base-protocol-update/src/main/java/io/nuls/base/protocol/cmd/MessageDispatcher.java index 3abdee21a..c81aa71f9 100644 --- a/common/nuls-base-protocol-update/src/main/java/io/nuls/base/protocol/cmd/MessageDispatcher.java +++ b/common/nuls-base-protocol-update/src/main/java/io/nuls/base/protocol/cmd/MessageDispatcher.java @@ -62,7 +62,11 @@ public Response msgProcess(Map params) { String msgStr = (String) params.get("messageBody"); for (MessageProcessor processor : processors) { if (cmd.equals(processor.getCmd())) { - processor.process(chainId, nodeId, msgStr); + try { + processor.process(chainId, nodeId, msgStr); + } catch (Exception e) { + Log.error("", e); + } } } return success(); diff --git a/common/nuls-base/src/main/java/io/nuls/base/basic/TransactionFeeCalculator.java b/common/nuls-base/src/main/java/io/nuls/base/basic/TransactionFeeCalculator.java index d7f6ae67e..b08923b98 100644 --- a/common/nuls-base/src/main/java/io/nuls/base/basic/TransactionFeeCalculator.java +++ b/common/nuls-base/src/main/java/io/nuls/base/basic/TransactionFeeCalculator.java @@ -29,6 +29,7 @@ import io.nuls.base.signture.P2PHKSignature; import io.nuls.core.exception.NulsRuntimeException; +import java.math.BigDecimal; import java.math.BigInteger; @@ -38,7 +39,6 @@ */ public class TransactionFeeCalculator { - public static final BigInteger NORMAL_PRICE_PRE_1024_BYTES = BigInteger.valueOf(100000); public static final BigInteger CROSSTX_PRICE_PRE_1024_BYTES = BigInteger.valueOf(1000000); public static final int KB = 1024; @@ -46,10 +46,12 @@ public class TransactionFeeCalculator { /** * Calculate the required transaction fees based on the size of the transaction * According to the transaction size calculate the handling fee. + * * @param size Transaction size/size of the transaction */ - public static final BigInteger getNormalTxFee(int size) { - BigInteger fee = NORMAL_PRICE_PRE_1024_BYTES.multiply(new BigInteger(String.valueOf(size/KB))); + public static final BigInteger getNormalTxFee(int size, long feeUnit) { + BigInteger NORMAL_PRICE_PRE_1024_BYTES = BigInteger.valueOf(feeUnit); + BigInteger fee = NORMAL_PRICE_PRE_1024_BYTES.multiply(new BigInteger(String.valueOf(size / KB))); if (size % KB > 0) { fee = fee.add(NORMAL_PRICE_PRE_1024_BYTES); } @@ -59,11 +61,12 @@ public static final BigInteger getNormalTxFee(int size) { /** * Calculate the required transaction fees based on the size of the transaction * According to the transaction size calculate the handling fee. + * * @param size Transaction size/size of the transaction */ - public static final BigInteger getConsensusTxFee(int size,long unit) { + public static final BigInteger getConsensusTxFee(int size, long unit) { BigInteger unitBigInteger = BigInteger.valueOf(unit); - BigInteger fee = unitBigInteger.multiply(new BigInteger(String.valueOf(size/KB))); + BigInteger fee = unitBigInteger.multiply(new BigInteger(String.valueOf(size / KB))); if (size % KB > 0) { fee = fee.add(unitBigInteger); } @@ -72,25 +75,32 @@ public static final BigInteger getConsensusTxFee(int size,long unit) { /** * Calculate the handling fee to be paid based on the size of unsigned transactions + * * @param size Unsigned transaction size/ size of the unsigned transaction * @return Transaction fees */ - public static final BigInteger getNormalUnsignedTxFee(int size) { + public static final BigInteger getNormalUnsignedTxFee(int size, long feeUnit, double feeCoefficient) { + BigInteger NORMAL_PRICE_PRE_1024_BYTES = BigInteger.valueOf(feeUnit); size += P2PHKSignature.SERIALIZE_LENGTH; - BigInteger fee = NORMAL_PRICE_PRE_1024_BYTES.multiply(new BigInteger(String.valueOf(size/KB))); + BigInteger fee = NORMAL_PRICE_PRE_1024_BYTES.multiply(new BigInteger(String.valueOf(size / KB))); if (size % KB > 0) { fee = fee.add(NORMAL_PRICE_PRE_1024_BYTES); } + if (1 != feeCoefficient) { + BigDecimal deci = BigDecimal.valueOf(feeCoefficient); + fee = deci.multiply(new BigDecimal(fee)).toBigInteger(); + } return fee; } /** * Calculate the required transaction fees based on the size of the transaction * According to the transaction size calculate the handling fee. + * * @param size Transaction size/size of the transaction */ public static final BigInteger getCrossTxFee(int size) { - BigInteger fee = CROSSTX_PRICE_PRE_1024_BYTES.multiply(new BigInteger(String.valueOf(size/KB))); + BigInteger fee = CROSSTX_PRICE_PRE_1024_BYTES.multiply(new BigInteger(String.valueOf(size / KB))); if (size % KB > 0) { fee = fee.add(CROSSTX_PRICE_PRE_1024_BYTES); } @@ -100,16 +110,18 @@ public static final BigInteger getCrossTxFee(int size) { /** * Calculate the required transaction fees based on the size of the transaction * According to the transaction size calculate the handling fee. + * * @param size Transaction size/size of the transaction */ - public static final BigInteger getFee(int size, BigInteger price) { - if(price.compareTo(NORMAL_PRICE_PRE_1024_BYTES)<0){ + public static final BigInteger getFee(int size, BigInteger price, long feeUnit) { + BigInteger NORMAL_PRICE_PRE_1024_BYTES = BigInteger.valueOf(feeUnit); + if (price.compareTo(NORMAL_PRICE_PRE_1024_BYTES) < 0) { throw new NulsRuntimeException(new Exception("entity is error")); } - if(price.compareTo(CROSSTX_PRICE_PRE_1024_BYTES)>0) { + if (price.compareTo(CROSSTX_PRICE_PRE_1024_BYTES) > 0) { throw new NulsRuntimeException(new Exception("entity is error")); } - BigInteger fee = price.multiply(new BigInteger(String.valueOf(size/KB))); + BigInteger fee = price.multiply(new BigInteger(String.valueOf(size / KB))); if (size % KB > 0) { fee = fee.add(price); } diff --git a/common/nuls-core-rpc/src/main/java/io/nuls/core/rpc/netty/processor/RequestMessageProcessor.java b/common/nuls-core-rpc/src/main/java/io/nuls/core/rpc/netty/processor/RequestMessageProcessor.java index 5f6493705..98860b764 100644 --- a/common/nuls-core-rpc/src/main/java/io/nuls/core/rpc/netty/processor/RequestMessageProcessor.java +++ b/common/nuls-core-rpc/src/main/java/io/nuls/core/rpc/netty/processor/RequestMessageProcessor.java @@ -517,11 +517,11 @@ private static Response invoke(String invokeClass, String invokeMethod, Map para return MessageUtil.newFailResponse("", CMD_NOT_FOUND); } long start = System.currentTimeMillis(); - Log.info("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"); - Log.info("-=-=-=-::{},{}",method.toString(),cmd.getClass().getName()); - Log.info("-=-=-=-::{}",JSONUtils.obj2json(params)); +// Log.info("-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"); +// Log.info("-=-=-=-::{},{}",method.toString(),cmd.getClass().getName()); +// Log.info("-=-=-=-::{}",JSONUtils.obj2json(params)); Object invoke = method.invoke(cmd, params); - Log.info("cmd: {}, invoke obj: {}", cmd.getClass().getName(), invoke.getClass().getName()); +// Log.info("cmd: {}, invoke obj: {}", cmd.getClass().getName(), invoke.getClass().getName()); Response response = (Response) invoke; // Response response = (Response) method.invoke(cmd, params); long use = System.currentTimeMillis() - start; diff --git a/common/nuls-core/pom.xml b/common/nuls-core/pom.xml index ebec42455..656b88064 100644 --- a/common/nuls-core/pom.xml +++ b/common/nuls-core/pom.xml @@ -166,13 +166,13 @@ com.google.guava guava - 31.0.1-jre + 33.2.1-jre compile commons-net commons-net - 3.6 + 3.9.0 commons-codec diff --git a/config/nuls.beta.ncf b/config/nuls.beta.ncf index 6083f19ce..72ce37f1c 100644 --- a/config/nuls.beta.ncf +++ b/config/nuls.beta.ncf @@ -32,10 +32,10 @@ port=18001 crossPort=18002 #Magic parameters packetMagic=20200120 -#Seed node -selfSeedIps=39.98.226.51:18001,47.244.186.65:18001,47.254.234.223:18001,47.74.86.85:18001,192.168.1.145:18001 -#Cross chain seed connection nodes of the main network -moonSeedIps=39.98.226.51:18002,47.244.186.65:18002,47.254.234.223:18002,47.74.86.85:18002 +#种子节点 +selfSeedIps=seedt1.nuls.io:18001,seedt2.nuls.io:18001,seedt3.nuls.io:18001 +#主网的跨链种子连接节点 +moonSeedIps=seedt1.nuls.io:18002,seedt2.nuls.io:18002,seedt3.nuls.io:18002 #Maximum number of network connections maxInCount=100 #Maximum number of outbound connections @@ -77,8 +77,6 @@ agentChainId=2 agentAssetId=1 #Consensus reward assetsID(Consensus rewards must be assets of the same chain) awardAssetId=1 -#Consensus transaction fee unit price -feeUnit=100000 #Total Inflation totalInflationAmount=11000000000000000 #Initial inflation amount500w/265*30 @@ -89,13 +87,16 @@ initTime=1594483200 deflationRatio=0.4 #Deflation interval time(unit:S),30day deflationTimeInterval=2592000 - +feeAssets=2-1,2-201,2-202 +feeUnit=100000,10000,100000000000000 [smart-contract] #The maximum consumption of contract view method callsGas maxViewGas=100000000 systemLogLevel=WARN crossTokenSystemContract=tNULSeBaMy9k29Nj4rd3U4tonVr93mrDLHMNNd +# 单位gasPrice小数点位移 +feeCoefficient=1,0.0001,10000000 [public-service] #public-serviceModule ExternalrpcPort number @@ -127,7 +128,7 @@ sendHeight=6 #Byzantine proportion of cross chain transactions byzantineRatio=66 #Main network cross chain seed node list -crossSeedIps=39.98.226.51:18002,47.244.186.65:18002,47.254.234.223:18002,47.74.86.85:18002,192.168.1.145:18002 +crossSeedIps=seedt1.nuls.io:18001,seedt2.nuls.io:18001,seedt3.nuls.io:18001 #List of main network validators verifiers=tNULSeBaMkrt4z9FYEkkR9D6choPVvQr94oYZp,tNULSeBaMmShSTVwbU4rHkZjpD98JgFgg6rmhF,tNULSeBaMoGr2RkLZPfJeS5dFzZeNj1oXmaYNe #Main network signature Byzantine comparison diff --git a/config/nuls.ncf b/config/nuls.ncf index 87a758c89..b1f558007 100644 --- a/config/nuls.ncf +++ b/config/nuls.ncf @@ -32,9 +32,9 @@ crossPort=8002 #Magic parameters packetMagic=20191222 #Seed node -selfSeedIps=seeda.nuls.io:8001,seedb.nuls.io:8001,seedc.nuls.io:8001,seedd.nuls.io:8001,seede.nuls.io:8001,seedf.nuls.io:8001 +selfSeedIps=seeda.nuls.io:8001,seedb.nuls.io:8001,seedc.nuls.io:8001,seedd.nuls.io:8001,seede.nuls.io:8001,seedf.nuls.io:8001,seedg.nuls.io:8001,seedh.nuls.io:8001 #Cross chain seed connection nodes of the main network -moonSeedIps=seeda.nuls.io:8002,seedb.nuls.io:8002,seedc.nuls.io:8002,seedd.nuls.io:8002,seede.nuls.io:8002,seedf.nuls.io:8002 +moonSeedIps=seeda.nuls.io:8002,seedb.nuls.io:8002,seedc.nuls.io:8002,seedd.nuls.io:8002,seede.nuls.io:8002,seedf.nuls.io:8002,seedg.nuls.io:8002,seedh.nuls.io:8002 #Maximum number of network connections maxInCount=300 #Maximum number of outbound connections @@ -77,8 +77,6 @@ agentChainId=1 agentAssetId=1 #Consensus reward assetsID(Consensus rewards must be assets of the same chain) awardAssetId=1 -#Consensus transaction fee unit price -feeUnit=100000 #Total Inflation totalInflationAmount=11000000000000000 #Initial inflation amount500w/365*30 @@ -89,11 +87,15 @@ initTime=1594483200 deflationRatio=0.4 #Deflation interval time(unit:S),30day deflationTimeInterval=2592000 +feeAssets=1-1,9-787,9-2 +feeUnit=100000,10000,100000000000000 [smart-contract] #The maximum consumption of contract view method callsGas maxViewGas=100000000 crossTokenSystemContract=NULSd6HgsyGNK1xTcx2GnC9y3Jr1DKd3qL2HS +# 单位gasPrice小数点位移 +feeCoefficient=1,0.0001,10000000 [public-service] #public-serviceModule ExternalrpcPort number @@ -127,7 +129,7 @@ sendHeight=6 #Byzantine proportion of cross chain transactions byzantineRatio=66 #Main network cross chain seed node list -crossSeedIps=seeda.nuls.io:8002,seedb.nuls.io:8002,seedc.nuls.io:8002,seedd.nuls.io:8002,seede.nuls.io:8002,seedf.nuls.io:8002 +crossSeedIps=seeda.nuls.io:8002,seedb.nuls.io:8002,seedc.nuls.io:8002,seedd.nuls.io:8002,seede.nuls.io:8002,seedf.nuls.io:8002,seedg.nuls.io:8002,seedh.nuls.io:8002 #List of main network validators verifiers=NULSd6Hge7xHDnvsSpnzbR2gWHd31zJ1How11,NULSd6Hgc5VNP4rF4wxdiXEQKpBKUE4w5RS22,NULSd6HgeQwXLdre69ArkqVZNDqMLU4CaAz33,NULSd6HgcjAKAgq8jjXgBCcNLEJUvJEYcoj44,NULSd6HgiDdTjcuvhqzm3bomyBFZmosV3ei55 #Main network signature Byzantine comparison diff --git a/genesis-block.json b/genesis-block.json index e4631cd59..3a1a90443 100644 --- a/genesis-block.json +++ b/genesis-block.json @@ -3,15 +3,3016 @@ "time": "1568131200", "txs": [ { - "address": "NULSd6HgX42PJ82mvg9qV6NiEiFLx8GA6vHmM", - "amount": 1314374313456741, + "address": "tNULSeBaMqsEvVjMYMhG1b7zPwgwC7E5ZMGHFJ", + "amount": 4332886598800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqpRQkHCs5ur3ck4LXEZB4qmmkPNo3", + "amount": 3687865664810469, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmTkgNtWA1jnyKBYKUC3vV4Sa57ovL", + "amount": 402524191370945, + "lockTime": 0 + }, + { + "address": "tNULSeBaMj5AkDSZeuXM5dHLJC34PuLVW7e3FH", + "amount": 195004013944801, + "lockTime": 0 + }, + { + "address": "tNULSeBaMspaJDzLdnDhgzS34K8i3Gs9MbcV2h", + "amount": 105070552877911, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqywZjfSrKNQKBfuQtVxAHBQ8rB2Zn", + "amount": 78999908314000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoVF1incqMLh3N48X123RrcjYc1uyP", + "amount": 65632918471416, + "lockTime": 0 + }, + { + "address": "tNULSeBaMx8TWnwjesj8mMm1M39RFrtjKfNMJy", + "amount": 61107327921041, + "lockTime": 0 + }, + { + "address": "tNULSeBaMp3wgK6qReYWpLHrNEHrLmRfJSsx15", + "amount": 60583218133268, + "lockTime": 0 + }, + { + "address": "tNULSeBaMotPhSFTjU9UxmzS8uToKezBSSYUxS", + "amount": 48959898119175, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhDQdoZJPjKPq1W8ehztifNGNPZ3EF", + "amount": 40780196885000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfHwuzJHxRre9U68f9Sog6QirDY5rm", + "amount": 38195067904649, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsPQUyeKhcMEGRmhJArmX5P6hqF67k", + "amount": 30764298564179, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfYYx6Pk652k5biNdACmzdSG6UU6N4", + "amount": 30555021413859, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhbRWvHgawzAUB7ZppTNvWGfShFhyC", + "amount": 30000300000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkz9cdFD2aCNacx6Hg7ArmRkg7t4Py", + "amount": 29727323742180, + "lockTime": 0 + }, + { + "address": "tNULSeBaMs7hgsVa64bLm9Q6cqGQyck8wcXi3S", + "amount": 27999091707675, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiAQSiqXHBUypfMGZzcroe12W4SFbi", + "amount": 26421039847100, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvjMmERz7DZgK85yjxwZkQUexVG4As", + "amount": 22998998370775, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoq3YhYDzwxsd8jGmCRoY8nGudcbr8", + "amount": 22798997782100, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgSVD53hrN7PaDw3vPSXZeB9GLHTTh", + "amount": 22707882567645, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuUcKTDkhAgCBdqSrYJgcpn32K9iE5", + "amount": 20497372975793, + "lockTime": 0 + }, + { + "address": "tNULSeBaMs65bgZmzzBZiHkzREz2cxtUp2bvGX", + "amount": 20020927877475, + "lockTime": 0 + }, + { + "address": "tNULSeBaMyZDUDjrsGhyxDvPG5PFy74aKarA2s", + "amount": 20015138581450, + "lockTime": 0 + }, + { + "address": "tNULSeBaN5xpQLvYBMJuybAzgzRkRXL4r3tqMx", + "amount": 20014645381031, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtTT2CXwgvs9dRk29r6M8gay6z7oyN", + "amount": 20000000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmESkMomLrvxg9Yj8nJsVyE2wW6mJF", + "amount": 19999896895525, + "lockTime": 0 + }, + { + "address": "tNULSeBaNBDfYEsjGeUnBmdcEaxbYassQegqW2", + "amount": 19999012154815, + "lockTime": 0 + }, + { + "address": "tNULSeBaMh1vGGeiiA7BaF91y28JYLZgQTWRgf", + "amount": 19998999103725, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrebYisUnwNMZdAdVtecytzZQff8i5", + "amount": 19779999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMn2UyQqP1vHM6Qmw7iFiczYfQjp3DX", + "amount": 15326498000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMr9KDm7dH99h4UJYPHNi4wo6Tf5giV", + "amount": 14136961867446, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpZ8NxS5vJVqr5xpBjycQn2Xud3ZD2", + "amount": 13561355703354, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoG1oaW1JZnh6Ly65Ttp6raeTFBfCG", + "amount": 11989898005700, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhAhsRiHDM4Ng93LEVcDknK5sPFhYU", + "amount": 11692620767972, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqtYBcBuPoYaxGDsASnrm6AwPL1kvZ", + "amount": 11111208965311, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnEysBLhWS8yMS5Cc6GLypiFAQMTpT", + "amount": 10618259989975, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqCqyLYqcgYZ3dyZowAyoLaS2HD8ma", + "amount": 9999899418375, + "lockTime": 0 + }, + { + "address": "tNULSeBaMozDhzJQ9vpP4i17QpfoysuiiPGUA4", + "amount": 8888799502400, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsvXgCBnaJ4u7rbQEKiWd23VWCudYm", + "amount": 8833553072716, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgUpGQRHxX5QgWtPLrMWJioLeiNKWD", + "amount": 8542015890741, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtkzQ1tH8JWBGZDCmRHCmySevE4frM", + "amount": 6961730529425, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkDXgwPXjczu479GjBxrDSRDdLLWq6", + "amount": 6904847361043, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrNP548LVMEvppNThEjaMd2izU6jL6", + "amount": 6431825179804, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnm4wKr3Uj82VVeZ7Uxhm7hvvKkYCb", + "amount": 6232427524648, + "lockTime": 0 + }, + { + "address": "tNULSeBaMu38g1vnJsSZUCwTDU9GsE5TVNUtpD", + "amount": 6003107334889, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrbMRiFAUeeAt6swb4xVBNyi81YL24", + "amount": 6001148403729, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfCD8hK8inyEKDBZpuuBUjLdiKgwnG", + "amount": 5969547053475, + "lockTime": 0 + }, + { + "address": "tNULSeBaMh4VafNqp5TJSmV5ogdZviq1nbXBSu", + "amount": 5967760560175, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtgmrSYu98QwP1Mv8G5FwaMDkWSkuy", + "amount": 5967748486250, + "lockTime": 0 + }, + { + "address": "tNULSeBaMj7QaB8mYBBvkhaT3jCrXEMCEcRfb1", + "amount": 5967746727700, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvQr8dVnk3f3DPvwCYX3ctTRtrTurD", + "amount": 5967593743575, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoixxbUovqmzPyJ2AwYFAX2evKbuy9", + "amount": 5965125820650, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvGmZSrFyQHptSL9yBCNSDfhWoxEHF", + "amount": 5964934449325, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvaRhahBAYkZKQFhiSqcC67UiRzoSA", + "amount": 5964927619825, + "lockTime": 0 + }, + { + "address": "tNULSeBaMobzkpUc1zYcT67wheRPLg7cmas5A6", + "amount": 5964919229650, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqjT3y9bGz4gBeJ7FJujmxBDTGdNp1", + "amount": 5964816737825, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpaiBiMHWfAeTzdXhnfJXPfwXwKikc", + "amount": 5964739028925, + "lockTime": 0 + }, + { + "address": "tNULSeBaMi5yGkDbDgKGGX8TGxYdDttZ4KhpMv", + "amount": 5964722973575, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuk5jx12ZXhaf5HLgcAr3WCwUhRGfT", + "amount": 5964722478275, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiKWTid5Gj3FoqBFP7WomUzgumVeKc", + "amount": 5964639781975, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjcximfy1JEGzjxodNMjrjydWuiffr", + "amount": 5964629618250, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmbiCH5soCFasXnG4TwqknyTzYBM3S", + "amount": 5964628195925, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqjttJV62GZ1iXVFDBudet3ey2aYSB", + "amount": 5964624558025, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrL5netZkTo9FZb86xGSk47kq6TRBR", + "amount": 5964543295050, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfXDQeT4MJZim1RusCJRPx5j9bMKQN", + "amount": 5964536134025, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjXxVzqB4T7zFoykRwfSZSD5ptAn4A", + "amount": 5964531159425, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsUBLVxwoaswjWvghJyoUJfbfB6dja", + "amount": 5964525370025, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgTcqskhNrE1ZSt3kZpdAv6B83npXE", + "amount": 5964520135200, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkzsRE6qc9RVoeY6gHq8k1xSMcdrc7", + "amount": 5964430789025, + "lockTime": 0 + }, + { + "address": "tNULSeBaMj8XfWDjyKHZ1ybC3ShR8qKGyVKRcb", + "amount": 5964420012900, + "lockTime": 0 + }, + { + "address": "tNULSeBaMk52mfhacRWkmB98PrwCVXuEzCdQuk", + "amount": 5964338710975, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhKaLzhQh1AhhecUqh15ZKw98peg29", + "amount": 5964332794000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMv8q3pWzS7bHpQWW8yypNGo8auRoPf", + "amount": 5964326585975, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfMk3RGzotV3Dw788NFTP52ep7SMnJ", + "amount": 5964324193925, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqwycXLTWtjexSHHfa4jDTrVq9FMWE", + "amount": 5964320129400, + "lockTime": 0 + }, + { + "address": "tNULSeBaMshNPEnuqiDhMdSA4iNs6LMgjY6tcL", + "amount": 5964220175225, + "lockTime": 0 + }, + { + "address": "tNULSeBaMp9wC9PcWEcfesY7YmWrPfeQzkN1xL", + "amount": 5893129655025, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG", + "amount": 5552108112377, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtK3FXr67yxTPWdRcjBYVZxHbWFEEV", + "amount": 5340406402515, + "lockTime": 0 + }, + { + "address": "tNULSeBaMud9PbxkfrWyBExWjLrbyFsrsrQZC6", + "amount": 5007225392710, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpZfSw6fSCc2wdcrUrXrys7K8b8KKq", + "amount": 5000000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmUZ2XFtazyZbJcAekufbbsbfJ3JG3", + "amount": 4998998354225, + "lockTime": 0 + }, + { + "address": "tNULSeBaMswWdvgYfR33ALR4mEp1jAahzpyeVH", + "amount": 4815809619488, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnTf4LrYZzXeQXAhX4JaCY24dcCBED", + "amount": 4782935168154, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnpqbWZgX76CPCacjQPNtYUhpBH9VW", + "amount": 4399497227769, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgC5kwDkiJKRRmNzGzDpJr3AgaA7ea", + "amount": 4180796388195, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiotxK9m7VBT1fDQrCpvQUpn2Z9kZN", + "amount": 4083015546214, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnz3MTqzcF2kbqSGgUUvw3PohUJXFF", + "amount": 4069206784051, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnrs6JKrCy6TQdzYJZkMZJDng7QAsD", + "amount": 3959598161628, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfySR2HrYGmryACfX6pdwVvWwaUQge", + "amount": 3827308013400, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkxVPipHkDpzTmsW1ANPeFG62uimVD", + "amount": 3590000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpXNTNgjjBTQG9gfzHWHrqbfnakHsa", + "amount": 3070197304125, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnXHhZUxtFvtgjKRd9oXU8KuzBzRqp", + "amount": 3009999516600, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjdg2vMBNG3RXeduADiiHbypgBtrfM", + "amount": 2999999502850, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnyciphhFrT52Lyc1aFtmieJgozjyU", + "amount": 2999471520675, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrge7NFuVUodnJVfyCfSweej8AZrwr", + "amount": 2997580915928, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiZciRL4MFDPc5Lg9t7N9gEFQ9vBib", + "amount": 2994986422725, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqSDRDdeD9wj47Zu252c7xvxwMKZw5", + "amount": 2988878035125, + "lockTime": 0 + }, + { + "address": "tNULSeBaNBjHnZu1nRdk2Rt4gQfPrvxV8XDQe3", + "amount": 2927990645065, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpECyE1oHY4QneHPDutR3Dyz6Ghv2M", + "amount": 2780099900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMraPGcjxNFfVrS9op6cPwtg1WCsCqJ", + "amount": 2775347540500, + "lockTime": 0 + }, + { + "address": "tNULSeBaN7NqbhEXcU7TgiyKjezCE9gAwn6nc5", + "amount": 2772815051761, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsQ75kkEyeqetdYBTLpekUHsiKR267", + "amount": 2731610975828, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvR7t3q5pxThzQBCNjd9prbjzd5tyd", + "amount": 2666569034845, + "lockTime": 0 + }, + { + "address": "tNULSeBaMh1cKVLomRNUaMmtZSV8AN67sTeQ4U", + "amount": 2555330206743, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfkVKA5opcmfEHW2oqW9X55FpyPhkX", + "amount": 2526201691750, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpjTH4Nsc32RbGec6JQvwyYGEt1jjH", + "amount": 2510955381132, + "lockTime": 0 + }, + { + "address": "tNULSeBaMq3vN5KGJx9r4wX2cqunxpokXjU4sL", + "amount": 2509997036050, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuDqkKST5mrsQDStQF1bodS2jUprfo", + "amount": 2256413711880, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkPHjgPqwooETMzttafPepJBPED6yd", + "amount": 2222222122222, + "lockTime": 0 + }, + { + "address": "tNULSeBaMokyuNzNJyL3RsZjbGgzvefGULJ2wX", + "amount": 2202899500000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgrTieVrYGAvUJWBGjPsSTUyXhg9EX", + "amount": 2201174340450, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrmywEP3oGJ37gme5zwtZ6sbQRqDXi", + "amount": 2100000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtCumY6ixakR76Yhrt5pk2Mu6aP8xV", + "amount": 2080000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMioVnTwyEvn7KNqQeGkK5XgbY3ykwX", + "amount": 2054385511968, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpPHAZ1if1a6csc1zau8SX2G3wEUfS", + "amount": 2048351046028, + "lockTime": 0 + }, + { + "address": "tNULSeBaMp31xDJLQ4sQPVP5GQBEiewUEaAwCz", + "amount": 2047488447331, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhTtbe1fo1F9hijPr3x2j3XzfmhTZC", + "amount": 2041463275119, + "lockTime": 0 + }, + { + "address": "tNULSeBaMruVHAFPsjrEGqYjT8rPNrrMNY6CnC", + "amount": 2010000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvUSPiNjNuLoNhBpgJxsVLRjG3wqkK", + "amount": 2009999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiShBYzc17JWZw9kg1pWubW84HGgNT", + "amount": 2009999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsJ2PRV2n9cGccUScr9bkLy1DMeD71", + "amount": 2004996165950, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtVBsUHAKTeFKTNYFLMkf2DUdm9qy2", + "amount": 2002899668781, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsNUEboyfNje7DjKVTHpe8DSZBJXPB", + "amount": 2001997352900, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmeJBW66dvE8afbBJZFFDskM2A8NCX", + "amount": 2001248231222, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfTzWhb6GyGDX6T9Upy9tpgvZpB8sh", + "amount": 2000999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgbsvbdvAAhjBpgGgxu3JBV5xMvt7A", + "amount": 2000999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkUMZF2YKb6HeZFiibW5aVrBVS8w3T", + "amount": 2000999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhCETTZ2QXTPSHSSmQqm2ubAGW31xM", + "amount": 2000999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkM7FGPuFUojjtoXHBfhSN9SPW1rWo", + "amount": 2000999499500, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpQaoMKRDFUCf2XgZFq22N1Swg4cho", + "amount": 2000599800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqRgkRswMqW6eVx3J7HvLgbgMAv1a9", + "amount": 2000500000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvJbNgG7mP3Bo6D1rTAbLLM2nQuQVD", + "amount": 2000199800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkTJ3QzVf1B8PDBW9Jjs54iU2aLoay", + "amount": 2000199800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMo4pu8f3bY7MrUuBy4f8r5NejbMjKi", + "amount": 2000099900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuRVk3xdSY8aE9LpecmhMDbkeGC8xC", + "amount": 2000099900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsnVD1YFaxfnY9XKNoKQyJS8Ljibgp", + "amount": 2000099800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhPs944jLUiUCQCK2g83NR2iLqCkL1", + "amount": 2000099800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMr55MEy1b5ErfYLZZqUhsLKVFq4CZi", + "amount": 2000099800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtU9ta3k4oq5gpjeR3oPTCgXM5K7H3", + "amount": 2000099800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMobmtKCzTox47r4jUW4xqCgt7LvT2m", + "amount": 2000099800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmkapqddfr2ttGwcscb9brwJM6fUNk", + "amount": 2000099800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmDsxQhavUbA2p7vqWvG8ZuiCXBGfq", + "amount": 2000099800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpGYFnDi9Dkfq2bX3yB3LzkcNUBtKg", + "amount": 2000099800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMftsAf77CyArjp51LABH4GyyjV7wpV", + "amount": 2000099800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMh8coYfzqHhWfK59E44A6qQBuScj5p", + "amount": 2000099800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgC3w9W7SVp5hFHmAWFmBFkzg1Vgw9", + "amount": 2000099800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfwmeDJp9pDS6EfjVVqVqayzGXJpfu", + "amount": 2000099700000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMu7mpCeNUUPsWX4RqZuVT7V7YTS7BJ", + "amount": 2000098600000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMn4uh1mTR43CX6oYNdUC1EDRZWNMAA", + "amount": 2000000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMikNrK5aPTr6kzRcNhJzrRMVHgQLVg", + "amount": 2000000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpRWgtdmv5X5qbDAihMsXModQJCuwk", + "amount": 2000000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMk69wKjbUvAsGXsrmKH24ZmReQ8Ttv", + "amount": 2000000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgtJfpvp6babwow3Gw7qZcTi97ox3G", + "amount": 1983277946192, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtgr7uompsnHtpVnP3MG8yDJJAip3L", + "amount": 1897986821950, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtyRv6wa4Pzg44DrhmLSEoLWgMXudn", + "amount": 1892308762261, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkHU3HYpX7xdf9mQWXciTz9xCStHuq", + "amount": 1804891384250, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhnKHAfV4pUaQb3tohwGtMuLN2gYAL", + "amount": 1745045970780, + "lockTime": 0 + }, + { + "address": "tNULSeBaMxgFoTyurwGNLqVeutDy64XrbQjm1A", + "amount": 1613123824319, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmK4LiYuWTSHGZhBag8r6Vo7CNnbsw", + "amount": 1579696998425, + "lockTime": 0 + }, + { + "address": "tNULSeBaMt2grPHgiTSUTrXFbfQ7i7Nf7rsZuu", + "amount": 1573680323525, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhmHrnX4XJHbZxR4ypRun52s1uYnJB", + "amount": 1534344228772, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpoX1tGJA1qaVbj9SaQx6MMhec3Rjz", + "amount": 1501601000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMyfDzgv1NoNq67KUpekRHePnPyn5Vw", + "amount": 1305762826389, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoodYW7AqyJrgYdWiJ6nfwfVHHHyXm", + "amount": 1277942984025, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmtHrFqE68VBFx11t7bunsJ7JAiEW3", + "amount": 1263693098075, + "lockTime": 0 + }, + { + "address": "tNULSeBaN8BPveRvyrbLSYjujhbfvw5Ace6arR", + "amount": 1212600000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN6yoGYh68qG2piYdid3A5DgUASYPTz", + "amount": 1210430000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgn4xFaRh9d21WbqekVst5Q4Rnu27L", + "amount": 1200400000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuTCTP1gtRyP9Y44YmFXteBdQLXCC6", + "amount": 1099999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvXFeu4ZsVuiG3bpboL9iCwk82jvws", + "amount": 999998740275, + "lockTime": 0 + }, + { + "address": "tNULSeBaMk48bGV4hvzPT1mqRkbJbtnndxNdbh", + "amount": 997094585141, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqMW6jn1hpuWaVJSzPwqfWQnRCqTkA", + "amount": 994278520075, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrGWJkAPzG7NmHz4YC2FGFhxDPH8Lk", + "amount": 932886854685, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnQzvihr16GZfzJBhwRTinvEz5EPzg", + "amount": 925942495989, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqEmpw7Z1nrgeNNdhaZHDu5NUae4rR", + "amount": 899999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMt5qvhNEZ9FaWVATF6XY9y4SHnGZZN", + "amount": 899990536800, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuPd3wtWTPr3tJa9zoWSwM3bSZWxbt", + "amount": 896331407533, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpwTaE6VbR7zd8m93NfEtoBgJxEttj", + "amount": 829999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuh5xiqbTEkUFH6acHHuWCbhs3c9nC", + "amount": 799999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfBqLbWRxvvueAzgJmcziBJSjAhCTZ", + "amount": 624118978765, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkdT9e3w9YF6ewSijXKXTPhLTy9N4h", + "amount": 598988990325, + "lockTime": 0 + }, + { + "address": "tNULSeBaMyTEe61hY6Lk7zaV97kBwP24bX31vS", + "amount": 588488574836, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgF9ZefH5kn7LrfXjkEwn6M8u2rMFE", + "amount": 533892437900, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjfjvW3hMpExr1Ws6FDHvpdcrReUsL", + "amount": 500784852120, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqsWgWMUnUqTue6KhDWXve2wiDvyGJ", + "amount": 488524140000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN6axbXuZG9hko5WPuTYz1r16YJBptQ", + "amount": 487998633989, + "lockTime": 0 + }, + { + "address": "tNULSeBaMq8njpYM63gjZUNcMe7mGq4mTxy16Q", + "amount": 458200010279, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnNZHHLwae8UAouJiro6URjwMkkMHv", + "amount": 446581185925, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuyLErNaRSwU1DK9w4EUYFcgwR3A2a", + "amount": 412844960163, + "lockTime": 0 + }, + { + "address": "tNULSeBaMyaC6zMK88P6mHMgtjQ5GcCKrNgowt", + "amount": 409452402058, + "lockTime": 0 + }, + { + "address": "tNULSeBaMwXV9T65psDGgDXnMMMJLrdzd6z5sx", + "amount": 402100000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuXBhixAkeCQ2JkHxnNb9QcGy5RX2r", + "amount": 399994026525, + "lockTime": 0 + }, + { + "address": "tNULSeBaMu8YGdXqKPuZPhmhD24sUR3HZ6sv58", + "amount": 399559218725, + "lockTime": 0 + }, + { + "address": "tNULSeBaMzK2FSk9Kx1grqcyCor4geWzptUhQs", + "amount": 375234867927, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhp88ZRTE61P7Vten6x7Rv8H7z4sLt", + "amount": 361401017975, + "lockTime": 0 + }, + { + "address": "tNULSeBaMveAHMRtdZRMuc26tPdZGTm5fsfes1", + "amount": 358780483825, + "lockTime": 0 + }, + { + "address": "tNULSeBaNAsXsY6T5VUiKzLBcMwEdbksEdGsRE", + "amount": 336275500000, + "lockTime": 0 + }, + { + "address": "tNULSeBaNAjKT3AcUMGVtk8UhV5NnKp5PZFiKf", + "amount": 333300000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN8RWdsf3gKAZPsJcGkWahL525z24wn", + "amount": 322980000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMwTgnmqeTe7Rvh3DF7j9kKNs6TuwYK", + "amount": 320000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrdU5t6iLN64kriP3adesp3XYcyhGL", + "amount": 318292236481, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpHGW4B4zdcwbWLsYVeZorU4Cpkutx", + "amount": 310000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrQugpW2r8972qiM99W2dtE7UXAvFS", + "amount": 310000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN2feyT23c9dVa74nuu2ERbgmGj9xeA", + "amount": 307316678664, + "lockTime": 0 + }, + { + "address": "tNULSeBaMncbvt4CfPSLe2DoW2bTkEgNERmUYk", + "amount": 305960134350, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuSS12qrEhoyU71dN59rNCAmUmwd7x", + "amount": 305688722918, + "lockTime": 0 + }, + { + "address": "tNULSeBaMq8uueLNHGMryF3bJFC136ZF3SJEXE", + "amount": 304580580775, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjBdte2yUGGvzc1j23T9MBbJFduRHR", + "amount": 302336904925, + "lockTime": 0 + }, + { + "address": "tNULSeBaMh3Dej16yXRVcs4JzZg8jKrUvWCoSW", + "amount": 300500000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkm3XzW7Bt7Hf8Tpqb6kt8CMepyBgv", + "amount": 300500000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMszR8NPWVEajouXaRc3SZ17erv7yzQ", + "amount": 300500000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMr76pshx1JfMcWiZJdtyHqqLXZ9s1a", + "amount": 300100000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiuX5v91YpyHbfy69kF2BRqWLS8GjE", + "amount": 300100000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfuYA6HZChxkhsaTR6ppc8LCU3RmCr", + "amount": 299993489325, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqieGzYWksFDLZHRGj4PJVhFAqopHA", + "amount": 299799499988, + "lockTime": 0 + }, + { + "address": "tNULSeBaMh1S5UVpcpu7dAmUjGdPEgMMix7cLY", + "amount": 298998293950, + "lockTime": 0 + }, + { + "address": "tNULSeBaMh8tKFHc1oH8ySn8gF8zRNGnvxsxiv", + "amount": 298699107700, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjttuCzH7ntLhRPhGHsMKmKY4Kx9fq", + "amount": 297143976650, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkpn4FsPRJgnUKY3RCLqnnCQBRBTjR", + "amount": 280099900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpQTyMygD2DLtW8pPBxHRqjjZqfyMh", + "amount": 280000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpCBDufaKw81mYeTV3CKRqoiJUyMmp", + "amount": 250749132637, + "lockTime": 0 + }, + { + "address": "tNULSeBaN9XRjVc4N7EXj7C1exTsKe74jg1Mn5", + "amount": 237800000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhZnRteniCy3UZqPjTbnWKBPHX1a5d", + "amount": 225800000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmBCeUzTT2rfseGCG54tdAr8bmFDWW", + "amount": 216588531050, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgUswXzXfQZDG7H2s7RfDtmhcP16LK", + "amount": 210000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgdorxRKEk3vzo2o4ZxvK1p7Wq47rR", + "amount": 208663978925, + "lockTime": 0 + }, + { + "address": "tNULSeBaN6HEALmcnaHLqttRbC3H9gJv71MA6R", + "amount": 207000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnTzBsXHnYkZXnjGpL1WiSZYBNSfVj", + "amount": 201928016350, + "lockTime": 0 + }, + { + "address": "tNULSeBaMr5SQn9fWZcmkgwNF3BsgAsbjKmNYk", + "amount": 201832500703, + "lockTime": 0 + }, + { + "address": "tNULSeBaNAUWvnvfKCNy4ZStT9by8eza4rMo7N", + "amount": 200100348561, + "lockTime": 0 + }, + { + "address": "tNULSeBaMzYSFpjZFdiLo8nuJmpEAPv7j4MHaz", + "amount": 200000348385, + "lockTime": 0 + }, + { + "address": "tNULSeBaMizCG38x1YkcdVjPVhi842hHGbS7A4", + "amount": 199994535210, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoMnHPK96iBVjkTVR74uMr9YhriPf5", + "amount": 199488974575, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnAaKZZH4NhSGkd6S2si1kvA3TRqUV", + "amount": 199264097125, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjC6gH6L9ZSeaaXjUDsHvNnxy4SuW1", + "amount": 199117809325, + "lockTime": 0 + }, + { + "address": "tNULSeBaMja5MimxTowHsCK4CDMSN3se8MkqQT", + "amount": 198997767225, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnrUroacSG9nAS18X6wrmWBoEPigGV", + "amount": 198996705725, + "lockTime": 0 + }, + { + "address": "tNULSeBaMt6gXabjrzirP7Rtyr9gEuL7RsGHcM", + "amount": 197996936400, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmXVUKXCxBcBZrFkceg5gK3bgKx9Un", + "amount": 183883201525, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuKSCtT7m2r1FpniwFtdGbXPLhXfPt", + "amount": 159999700000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjmopdVK9K3xiwLX9PTwch9zE4o5ax", + "amount": 149999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsQskY7f5DSXcC6MkizRCNE6a3gaCX", + "amount": 142000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrQcmCg1AZGE4635zscL9AceSMGyLm", + "amount": 140601995550, + "lockTime": 0 + }, + { + "address": "tNULSeBaN3HLnyzXGJKm1NMv86qmoNBei6Sg6w", + "amount": 130000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrWZZ3S93ukYpi4Vxo9vZ11STJhNLe", + "amount": 129999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMyirf3piDmxnmHK5JZtPk4X7pv84FF", + "amount": 120200000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmAY646TmLxZWdkk1SfTBLQSgmTReV", + "amount": 110043427250, + "lockTime": 0 + }, + { + "address": "tNULSeBaMj5v2i5XNjwKy8VvHNFW8ta3AoLhkL", + "amount": 110000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMucpLmWwwSZoUe4LJPvuB57P21BxRA", + "amount": 109999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfCBBcj4FKvuDKXjsGG7aGXvLH5p2p", + "amount": 108981741525, + "lockTime": 0 + }, + { + "address": "tNULSeBaN12GKfFxyR2JwHGNz9EcE6o4oiYkui", + "amount": 105100000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN6bQb5u6nhyqgRQ9AVaCVYZTAoyxLK", + "amount": 102000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfpximz7mxS3tM8j1jAvskHYriMFJE", + "amount": 101871002025, + "lockTime": 0 + }, + { + "address": "tNULSeBaMm4w7jwvHneLLT5kxDbJ2SD2ZYDSxm", + "amount": 100299900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMt9xPHZZcnGT1v442YtCAY8s935y5G", + "amount": 100097056725, + "lockTime": 0 + }, + { + "address": "tNULSeBaN9vLiLEAZFJZooDahtdeQ8ExswaUYr", + "amount": 100000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMn2N2BXzX6R1vTn2apxDFBgN5tEh3g", + "amount": 100000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjUDi6DJiJqjzU8cCgLUEU55WUXwpu", + "amount": 100000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkdoobdBbpyovqeWMorSRL4Hkp8Ybg", + "amount": 99991621425, + "lockTime": 0 + }, + { + "address": "tNULSeBaMm63AcisvbLTZwVsKesS1EQsbgZRHg", + "amount": 99699700000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrnQ18CTewGJM6Xwhb1zPEWjnCSky7", + "amount": 98950443200, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfFyNfsv3Y9zo7yqGXgq6Bj51NZRMC", + "amount": 98486937100, + "lockTime": 0 + }, + { + "address": "tNULSeBaNAh7MSQsFvbUahQeHFu8f2QBKLav9r", + "amount": 98400000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhUBun3CRdWjuD7mwvjdbJ9e8KRWsJ", + "amount": 98300000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjUnoMkTh9bSCYu1sGJM2vQZqGnvMK", + "amount": 96799200000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMurf6BwQC7LTC4nhWGD3w1J8uM4DLp", + "amount": 93969831700, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiXL1JA7k8sEAtX3pYwmcxKZHpHL2K", + "amount": 92699305721, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoWtPm8Jo8sPP3y7xFg7KwT8kGMNsK", + "amount": 89999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrZFmYiQWS1NCvQxTpJam9HVNTsdMM", + "amount": 89999700000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkdkA2x6Jyb1gA9G9erLrCsWgTG27F", + "amount": 89959456375, + "lockTime": 0 + }, + { + "address": "tNULSeBaN9qsnBDwCzBGPzATf5gbvUd5xfb76w", + "amount": 89000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjtRZRQYUcQZVrPjYtTxAhLdawX4SU", + "amount": 88748393900, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvHu3vTBRoxDoB9BYEXeCLnsKo6QP5", + "amount": 82499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiM4MAQTWP59eSfFehSjftoFigm4qz", + "amount": 81986713775, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhsKRyBzQAFrCsPb2BErspo2cML5R4", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMha6honSL9KqfQ9iD8rzV8mAEsZEzX", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpFWLuiNNNm5vt6er65yX1iidCvdaw", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgpDNXuP5Qov4uVRSLAyV3FoYvPxfq", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoMJoA8GSadgHtNwyxLYFpUs2on97V", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsWCwyzBMAq2Hmo84BfN6nYTRgH318", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnCUd2EzDh9dLcJNXomy8hu8jVoi9Q", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmBZVBE7uJAwdrE94jWCcrGkphKcXP", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiUcxAEQi1yWSNJik8Z9pL6oFLZE3m", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjQHtGmjDdENDcwiyAPkJRS5WzwmwH", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmHrzxgXWPFFZYkTWG6Uc86bTgKe1t", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpGd1ZJQen5gPuiQCM41L9NhEAX95D", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiMt1V8nDQbFrojxjMgzLaDZhkymzb", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpZFhrQTwPJZitg23Pt6gPXYQN7Deu", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpvDaVSHszybk7Xy4BbxgUw61DHSQq", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMo7H1W9iafGhsVD1FTwxC615iQAEc9", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMm4y26B2cJiL6sCZ8RQFL3KCJxQPuN", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtdJDPWMacUPACyXyyLZDf7YMvQpHc", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrA1q7cWZC3gqwprjfcfi2TqKzVhYx", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfttuYRKhkwE659XWeJgNvhQh64Lj9", + "amount": 80499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkBoL5JmcwMCjzk8PKsxvtXvcttwa4", + "amount": 80399900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpVdwtAD2k33tiCbEsPXhpV3E6Zvgp", + "amount": 80000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqumJQ9n7ottDYRrq4zEmWqV4CaKtM", + "amount": 77551499050, + "lockTime": 0 + }, + { + "address": "tNULSeBaMocFMpJDavQuonGyf67RYrmomyUWhZ", + "amount": 74768701600, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhezYhsW2DpdF8P9UPcnUz1fV1QSsj", + "amount": 68973500450, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnSYRzgPCwRZML1JQ4kDNASDmqKYf9", + "amount": 68040813100, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiKUm9zpU1bhXeaaZt2AdLgPTs3T28", + "amount": 51339780050, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkyGhH7gKPgtzhVLJm2gWDeSw7hyiu", + "amount": 45112902300, + "lockTime": 0 + }, + { + "address": "tNULSeBaMw4bC6QoquDYGnGDb51kaMnUBcQ8C9", + "amount": 42837864386, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhJzhygR1Q9YcUvNY2FmYeQjkgdgUv", + "amount": 42016243075, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqQYQswMcRur5NSRV89Fx3p6EmizGi", + "amount": 40408500000, + "lockTime": 0 + }, + { + "address": "tNULSeBaNAGNRLAwj9kinX9asqzmksBDc9PnJs", + "amount": 37025000055, + "lockTime": 0 + }, + { + "address": "tNULSeBaMg8FsV4PZegyg5XKhSxskXvykWm7iY", + "amount": 36900000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN1HXYCWCoV6sf16Vduxe5uuN5YGNpk", + "amount": 35800000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvSWnH5nxRxd55L2vee1Fi3rdhHZDN", + "amount": 32974999945, + "lockTime": 0 + }, + { + "address": "tNULSeBaNB9vnu1481jYx1oMRobZEa4s4cz3Zu", + "amount": 32934100000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMr8K4mu93gUZrn2H8eQhWhvgKRDVVm", + "amount": 29200000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN293SPzwWKE6nQx6CmxD2x31C1zc5j", + "amount": 26100000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmEa7Ev6cBVNQkvZhsSi1QGxCVHF7g", + "amount": 22951608700, + "lockTime": 0 + }, + { + "address": "tNULSeBaN9kxutqCocCcSV8UdbnHuH1dRS6Zs5", + "amount": 21800000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgNDafnYx7KkaRR5fgAovBgbqDQtLB", + "amount": 20000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfU7eBAPSHSSrR1yd32DmxSixi9bFS", + "amount": 18900000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMh1nrPFYaqdQBBWEV9kwjGtpVuNzK3", + "amount": 18098700000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMm8rojByJRyfBf3avRsVjcUcaGZia1", + "amount": 17923520375, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqwCW3Lk81XATBqUfuAkVncxAtxkkQ", + "amount": 16325107000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsDRLyDiAzcBfCPSxyvpBke6YGhpeM", + "amount": 14999400000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvw2QtYPhLjgCFuBQefpXDczAdd49C", + "amount": 13044000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjjc67wsJHYmb89zxRKFMgZewwaZdW", + "amount": 12783997600, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrYDwtXhATECvyQNup8usLnYpC7d4x", + "amount": 11459355900, + "lockTime": 0 + }, + { + "address": "tNULSeBaN76m184945bhSandg4zQc292KuBk93", + "amount": 11200000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMy3VXYAXB4UjYYHaELqjSe4BCdUjv7", + "amount": 10220000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN4fXFnUpGPBwXPCDUD4qfKC52Sm5KU", + "amount": 10115000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN4PqjeTLprLcrgSt44jNhLV3rh2ugQ", + "amount": 10000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpcCNcaXRc8JQ7XWJEzZQJg9SKcvMY", + "amount": 10000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhLt1Pzd4sDJqsJSN66yUvawXqgP6N", + "amount": 10000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN3FAdYCkf7ZUkNnCwHeBE62USAWnz8", + "amount": 10000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN6s55WBvjH5w16YUL9vPqPZRuC5b41", + "amount": 10000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpxNETvTsve8TuB3J4MvFEboB158JN", + "amount": 10000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMf99m2wkNvZwTnjVDhWoMvXDeypPwC", + "amount": 10000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuKCpUDqmLBhDUSbbgAzzLsdbrRHxj", + "amount": 9993122025, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgp44eQKpEXgYXjJEcp9E8ThERyTH4", + "amount": 9991715100, + "lockTime": 0 + }, + { + "address": "tNULSeBaMutmD7DUbPg2Tjv5WdC17jHbGdWrFV", + "amount": 9990369025, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsxLBS9JgeYneiTNdsdoKn2Tt1PeV5", + "amount": 9990272900, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgSUTEg4Qbdb4TU5qwLqh1vBLeYE8u", + "amount": 9990251900, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjaDW6c1uB5GLZynwiLib3HuxvbwBV", + "amount": 9990212375, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmY5gNkb8vSDqpoXS1CRcV4jzyo6Rv", + "amount": 9990188125, + "lockTime": 0 + }, + { + "address": "tNULSeBaMioR8t5cPAz4DdHMHGmiCQPSUBHGMR", + "amount": 9990185875, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsN1pYQcy7XnVNhWePoRrmufVFNvRW", + "amount": 9989270475, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnkCagbfuGpbnZVyE5AFobCYoTYL8J", + "amount": 9989207450, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsHu9BwXsufaoM35sRJCYpytkx1oeM", + "amount": 9989201100, + "lockTime": 0 + }, + { + "address": "tNULSeBaMu6mmd3qV9JJ6ftSMbqqZaF1aYRK4p", + "amount": 9989159225, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjkmRL3za8XmvDL5XpxCqQmwq53b6t", + "amount": 9989157325, + "lockTime": 0 + }, + { + "address": "tNULSeBaMp51TvTvSn1N23Yap1uGGjTomdbrZ8", + "amount": 9989143375, + "lockTime": 0 + }, + { + "address": "tNULSeBaMp41SZT8MWJNCrnDoWa4YB8xaQHBp3", + "amount": 9989140250, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhL1Dq4RGSbmuyxM74XNvKJg2NHyvu", + "amount": 9989133250, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpdHrYFnxTBkqE6mCjEkbEd5D7KZJm", + "amount": 9989132075, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoDgz9kN8KMmgt9NvptDpU8BDTrP8Z", + "amount": 9989099675, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuvw2zQFqvQinViV1X2yn4r4HLdxNs", + "amount": 9989099575, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrBmLKaeDFQ2azvidT3ZhDSYmRUEhg", + "amount": 9989066925, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjVYd4sQbq96yrHn5qtJHXKwCqWciz", + "amount": 9988986475, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfLkoQo7rzUBh8Bq1V7D9fWmGkJYfs", + "amount": 9988217650, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmD4qoJM7oZw1Q4wnK3BAWQ6TvWVZk", + "amount": 9988136525, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpsf1wDtohRKbiUkpXLbMg62ki3wML", + "amount": 9988064350, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpqMhaZcqq1uthY57HmHsrAGKYcq8n", + "amount": 9988057325, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgFtr3vmggvDv6rLp58AxSSSh9CwkN", + "amount": 9988036925, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqzXqByMV5eqmD8m9AXuzRx95UkK9h", + "amount": 9988036800, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmYaED8cmXXhbvnWfYEGvH3AcLMECs", + "amount": 9988013775, + "lockTime": 0 + }, + { + "address": "tNULSeBaMthF1avDFtBzAijVQcxDbqxDVDQpsZ", + "amount": 9988000500, + "lockTime": 0 + }, + { + "address": "tNULSeBaMud7T7gpGksc4zDUCeDbie5TEaMTp9", + "amount": 9987977825, + "lockTime": 0 + }, + { + "address": "tNULSeBaMo5QjuTnBUiQFnjLHtLHPxHqQB2jnU", + "amount": 9987896575, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrJjx13CQnw5ekfin9iev476AtHntU", + "amount": 9987885850, + "lockTime": 0 + }, + { + "address": "tNULSeBaMp9p3g4wGjyYsf3j2cG1mVwQaq7AbX", + "amount": 9987829800, + "lockTime": 0 + }, + { + "address": "tNULSeBaMq8EkbeiMWrQoPBejcLeVJ6eyhoLkT", + "amount": 9987109225, + "lockTime": 0 + }, + { + "address": "tNULSeBaMj8zKFgwpS8JbkrJjeAuevGByJ8DNv", + "amount": 9987074300, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkJYxaAWnhAajTwcwaUAdUBYcHTNzQ", + "amount": 9987068600, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhnjKk4uYAUte4nD6KtuDdnDNrJLsm", + "amount": 9986960825, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgPAj9hK7G6WQG2wesb4L2SiUqabbB", + "amount": 9986874475, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsbEcTaG82AzNTUb7iz7cNDQFytkJW", + "amount": 9986820925, + "lockTime": 0 + }, + { + "address": "tNULSeBaMocKfHz4TRMdAqWPoG3SsD5RLXsUHD", + "amount": 9986732575, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqkCRrbaCQheCZLmgWUPegWA6LqbtB", + "amount": 9986727550, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtRDukoLgjQ8MyLV1YLeE5q5NJdvxQ", + "amount": 9986668925, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsUCKvjRmGbAW6T1QtR268NgQkvshr", + "amount": 9986167775, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjwNhrcwZSiMtU2KyprEEBJUNu1mTq", + "amount": 9985438350, + "lockTime": 0 + }, + { + "address": "tNULSeBaMm4iTqPbdskbqTLs73iHWD74QKN9jQ", + "amount": 9984401500, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkaXoiDye4bCh7hJsFwa1GHXhqGFnL", + "amount": 9923901850, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmAvbnNbDH478fdxGhbAPwTB2H7rt7", + "amount": 9916023075, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfei9DVpt8KZdKmw4cxQrPyVmPyXx7", + "amount": 9913032825, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmf4fWMc4nJAFzi9i3nYopxJSU355n", + "amount": 9899900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMr5NKgxRQVhqqqZcxZcJgQEqZMpAUX", + "amount": 9899713150, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiZAJ5pe9zrGLPySL2r5C6WwJfCxpt", + "amount": 9893677175, + "lockTime": 0 + }, + { + "address": "tNULSeBaMv3pAbsaNKYyzRPUPKp5gkihMS1xyK", + "amount": 9499800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoKaKmNcfzoDQFhBrW1pkJJFuLHBTm", + "amount": 9489900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpCMSD27z8DLQb1D6iRiYACMuBSM6s", + "amount": 9399800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvL6XgxSM39LmRUV3ZXiGAacCLA25u", + "amount": 9299700000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMz9Pk3zqZsY8Tif49V86aDbt2Pa8Vk", + "amount": 9157657092, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjiQJVKpjD3naTcg4Zhvi9HY6SW6Zp", + "amount": 9000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMraUE98YQQVkUyHaEim4n3Vx4YMfKW", + "amount": 8989350600, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtPWbFyNzwbrmQXYVMdFjEbvWaRF1U", + "amount": 8989060600, + "lockTime": 0 + }, + { + "address": "tNULSeBaN6DYup5eR8pWC4TAyXsMb1eUJPt1hP", + "amount": 8800000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN4Dn9tSSBXd9s2uA14RF8viWFAaKCZ", + "amount": 8800000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtk4yQ7SNDLb2GXaNXjXFhWxyP2wU6", + "amount": 8539672725, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqf9RBq5tGpBHSfT7EETy5FTtwN5yk", + "amount": 8246417350, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiaDqM8UsMt8Rp8Sy1GLr44J5basdg", + "amount": 8241960275, + "lockTime": 0 + }, + { + "address": "tNULSeBaN9825A5YBgCC8S9pUKsqM5bjryv7jU", + "amount": 8000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMv46LcWE94oPBGobWXNgdWoKAEjBPg", + "amount": 7889831300, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqPjd9TrkBXfpPGBECzD3FiUA1yR4r", + "amount": 7550884450, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvfppg5xcfgaeeB2JcsPt46zBCj7zd", + "amount": 7000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMs9Nu9LhryyW7zAFBxqhtiJoWSF7jJ", + "amount": 6999600000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmShSTVwbU4rHkZjpD98JgFgg6rmhF", + "amount": 6959678345, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkrt4z9FYEkkR9D6choPVvQr94oYZp", + "amount": 5980102225, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuS9DvAdMPGRtvffZ4ueujwtXRd6qu", + "amount": 5966832575, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgSo5XNX15kq9usuw4j42k6Kgtf6vW", + "amount": 5681003300, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnW2PHQGyWQff9GydL2BwKAcCaRrY2", + "amount": 5670626625, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhEa7e67QuFpdQEHgYdRJSsCwbmvCK", + "amount": 5596047000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjRwM25URqjdhYMR8yXebAHiQTMphx", + "amount": 5347657361, + "lockTime": 0 + }, + { + "address": "tNULSeBaMq8uyWNyguh6MupNCWpsrJAcn4vVR9", + "amount": 5328432325, + "lockTime": 0 + }, + { + "address": "tNULSeBaMo1Bi3tcSdrEQGgfAZtHhLhX5A6WSw", + "amount": 5094720025, + "lockTime": 0 + }, + { + "address": "tNULSeBaMis4ZgigCwWp9B32tE8HXrxMSCdayL", + "amount": 5082831225, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuTaB16ko4Nx5RE8j5JfXqoUba1iXY", + "amount": 5000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoGr2RkLZPfJeS5dFzZeNj1oXmaYNe", + "amount": 4681316415, + "lockTime": 0 + }, + { + "address": "tNULSeBaMow681DHMJLV6rb6n7XBYXez6rKRX1", + "amount": 4386795775, + "lockTime": 0 + }, + { + "address": "tNULSeBaNCDfri41LZfsUvz5cKi5Loz8ETb4hU", + "amount": 4300000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoazoxe6tygAevx7jbAaDMyTh4EjAB", + "amount": 4247245075, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkeTYzPxJDLWZZp1ZvwQizycwR71La", + "amount": 4219694850, + "lockTime": 0 + }, + { + "address": "tNULSeBaN2UipbqDYZtYG2xnm9wFxLqRjMD3hr", + "amount": 4000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfWoGqcgLwWsFDiUha1Qo3WSc7T2JX", + "amount": 3968692740, + "lockTime": 0 + }, + { + "address": "tNULSeBaN2idLSNV4AfREmHnG2B77MCAuYM3fU", + "amount": 3900000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtHPTeddD5g35va34zEz2BJkpXtxJg", + "amount": 3885652975, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpcfcuEVx7rJPyEy63efQQZ318Q2Hb", + "amount": 3762708875, + "lockTime": 0 + }, + { + "address": "tNULSeBaNA1gAbvYpWcMcDLNmJNMqo58bqy9rF", + "amount": 3700000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMySaBTeR4B6LW5qwwAEqqjK6Uejb7R", + "amount": 3600000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpvw7msJTb9jwhbKcp5cMes12YPrjQ", + "amount": 3567339500, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgUH8cr5357LNy64B74Sx44obbn7fQ", + "amount": 3418710175, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoeNNoyq7tZFxhqFjf865cefEKJenb", + "amount": 3314895600, + "lockTime": 0 + }, + { + "address": "tNULSeBaN4gNHdVuBhutLbmWLNDuYMy1CzFBWK", + "amount": 3300000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtzr6HKQU1kQJMD5fgTJ7E7KNL1g8m", + "amount": 3262952700, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmst1go9Mv4YbCFhLpFMoNYSNMMesN", + "amount": 3179520000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtmQbjHyRtP4YkXU3RuYxcon4MbWvc", + "amount": 3147240000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMxVmtkiGCdfgTnQDdga3Zxj2vhDX9A", + "amount": 3122000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMyntpw4Nci2oUc8JtSXYhn1SckDzbX", + "amount": 3110000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfMiNmtfskSQQYXKVwMPKPVYBzvHES", + "amount": 3098375575, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqYJYr2qxVFpTmkW7aSSkFPD5mPcVD", + "amount": 3096829750, + "lockTime": 0 + }, + { + "address": "tNULSeBaMzeGGt8uku6bL2NUE1ZtVXeRzfEijQ", + "amount": 3000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkgnr7kHs2jmzyBdwq7JwtiyFZ9HJb", + "amount": 3000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMhuZk5QcEREWJJXUW7XTf7zRmVbrDs", + "amount": 3000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMh9QuCQRz2WxqwqG7ZHfPXuYQ42j2K", + "amount": 3000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoZhzVu4go15JiaAa3sPAzZpryM99L", + "amount": 3000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrARa1VoyTKSKQ48kMpTWPnJJ4czYw", + "amount": 3000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN9Gnvh4sx2w5te8u95svRMMUCL9v3p", + "amount": 3000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgrbjQGnThCVVrymPPPae3RZkfdcZY", + "amount": 2993155625, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpjHWfnfFovKnv7sc7i3NB2yy9P7cx", + "amount": 2899900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpdW1LKUJyGRXBaHQj3u9vfp5p7m65", + "amount": 2884800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMf6jCD5g7MoXDrU4zqwu28ywDN7rVp", + "amount": 2884734450, + "lockTime": 0 + }, + { + "address": "tNULSeBaN9F4cpTaxt4LKKKuR8B9HsdzDtyZMH", + "amount": 2789980970, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfT2jeMhByjHHJUvPABrFJ9kijLuvP", + "amount": 2584528575, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiavFfrCsTcbCkSHfiDMjjC4DJ6E3T", + "amount": 2499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN8xRW9oj5NWZJZq28Mupqtakd1pTFf", + "amount": 2280000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmduoKVBvwDdTmMWjfy2deiQfmGrdT", + "amount": 2259700000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqY8kivUA6qdeqqn8SPniSZ2uq9PjK", + "amount": 2196863450, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfrAD7J1NTVveGoEbUZjzUNDjPUWi7", + "amount": 2166091400, + "lockTime": 0 + }, + { + "address": "tNULSeBaN6zc7bZfMsytYmPKTBWW93WspGsNoj", + "amount": 2100000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkDzApThXXVvVGnp2cNfrAF2mwEVZv", + "amount": 2097925025, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgTuWwHm1og2cQxUdohw1DdqRmyBr4", + "amount": 2096126250, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjCJQJKeH1j7vciYsgmLvypqPCsEop", + "amount": 2095712300, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpigc3XfgpwAJbQvhfnCYDqPyRXkzn", + "amount": 2090260625, + "lockTime": 0 + }, + { + "address": "tNULSeBaMh8wjqtRx3hHbTSoR1PAJ57cunQUXD", + "amount": 2082245000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnsx5Z5Z3Ht2Kzzy5akNwiS2kweGvs", + "amount": 2079580925, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqLfpXS6wjGbwwgbeVY7zasxwBEmnQ", + "amount": 2079230950, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnoEHsUsRCRAikMUP5CTcaADRVF3qM", + "amount": 2054834875, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnLrfU5XKJfxGce4qT6sD7sLF7ySFJ", + "amount": 2000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN6LQZpyuCcY5PoU3NZzNS5FGFb5gfN", + "amount": 2000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN8f2CXfDXRdYkmU1jM6XnL6vLmMr8a", + "amount": 2000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqQAuB7hyTWCRCLqPbC7CtNT61p5JL", + "amount": 1998396625, + "lockTime": 0 + }, + { + "address": "tNULSeBaMt2AJW6uV2vsx1xzuBHDc7sz3EJhPr", + "amount": 1996901975, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjdWm2DU6NnR6AHenBPgaPom1oYnPZ", + "amount": 1996852950, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjSorYUdgDBrocKGKmYSFbH2X3Bb5G", + "amount": 1996312650, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgNMK3U7TYKu3mnbdZ5PsMmm1rHb7X", + "amount": 1992299600, + "lockTime": 0 + }, + { + "address": "tNULSeBaMp7GPqe7Hzf4EZ5maQXapAQ9z1c1JR", + "amount": 1899900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMo7Ptob5zGhYrLKSpUoLYL9Z1oFsWc", + "amount": 1836805890, + "lockTime": 0 + }, + { + "address": "tNULSeBaMsTPMuzPk5k5PTfqyhThHpWdcyhKRk", + "amount": 1827722825, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtFMjmh9ZUwcKbsyrmv69moU4Es345", + "amount": 1823725825, + "lockTime": 0 + }, + { + "address": "tNULSeBaMojP3hJVkTfJ5dTphEWUrhiJyvp3Ge", + "amount": 1765270250, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmiZ4sfXL2wUNz4Hp687QjkWmLsuYz", + "amount": 1761846790, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqKsXotY83kDSbvZafdoh9PoaK3bvF", + "amount": 1548354300, + "lockTime": 0 + }, + { + "address": "tNULSeBaMxfdXfR4yLPJ2B5Mv1JAwQM62GWvX9", + "amount": 1500000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN6H7nfPBxy2vHkPJBE2H1nmuoSHAj9", + "amount": 1500000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMp41MXznsL2P31ZJYaGNaS1Cs2pBHW", + "amount": 1499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuG5b4KuWuSg8rvNPttqWThhFsH3ns", + "amount": 1499900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN4gf47mHPh45sFam931c9BYEa7XcFw", + "amount": 1400000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN7xeDduG4NZrEmbvV9RjghXLXfpaEg", + "amount": 1398752439, + "lockTime": 0 + }, + { + "address": "tNULSeBaMp7Ww2yt3QUZdwegQYDVKTZ1svSonf", + "amount": 1348274325, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmBxth9wpeNZnrXrxttYHMb4mSfo8t", + "amount": 1331528300, + "lockTime": 0 + }, + { + "address": "tNULSeBaN2ZyStkD9nHSHFKGx46DUTVFtji3yB", + "amount": 1295000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfoRHCFPQENqscAqsBGF8CtQtxJvJH", + "amount": 1281519175, + "lockTime": 0 + }, + { + "address": "tNULSeBaMzWsTQMLVeTEkWki5LoDpW6ysZD9a6", + "amount": 1219000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpNgVcmwsprSYWQMM15HHJ1dgPeY6H", + "amount": 1200000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrjUJ73gY6ZKo8wCP4jXe2dE3uVr6q", + "amount": 1200000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMmWjXCTz8foPoJrde2kpvPZVwfqUan", + "amount": 1200000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpSeNiUFrcD3UY499BzPe6zZT8AvAR", + "amount": 1190638625, + "lockTime": 0 + }, + { + "address": "tNULSeBaMzVqoQ8mJ6LqVJWZPE49de1Nbe1Mfx", + "amount": 1100000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrysaMYedaAdRGaR3GJ8n1uop4rXHq", + "amount": 1100000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkJFKTzv84Xm84kGD3kKCauytpb5pQ", + "amount": 1087826175, + "lockTime": 0 + }, + { + "address": "tNULSeBaMitP7F9EG7KvmoDVh8hVnfKcVWLwuQ", + "amount": 1082828700, + "lockTime": 0 + }, + { + "address": "tNULSeBaN5QLqHrR3r9SkzRJBLa5Bu18AtFFJR", + "amount": 1011000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiw9EpTEx5ckq15kYv1cDGyZ5wCfZr", + "amount": 1001086825, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqgmNMBuHg6imiTHrNXh4ffuqECiyG", + "amount": 1000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN5drTXXaTEmHh1ssMJi1h2UTx3p722", + "amount": 1000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMxZiELhwNca7Vu4tKa9k3AhhSxFagt", + "amount": 1000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN1ASQCzVqG5C1qh3dJraY2HGQzLRc8", + "amount": 1000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN1DUHHUNFu6wpYv2fcRhkyyM1HKiN3", + "amount": 1000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN4kKFZdcCKCw4DGphXfboGpytCyESa", + "amount": 1000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMxr8kEXZbNRLD5GrdsvVw8MGZYAXim", + "amount": 1000000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnRAJarbMXyjBqPqZkk2CKSZ8HRkaD", + "amount": 999900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMr1fDYUhC3in3wdPApkFAMsDbRsyNP", + "amount": 995712750, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfMbcKnpDBxyNkZTV9rHTfbHs5PPtz", + "amount": 993565475, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnJ65gQdHiPisezoJJEYdzZJmpZauY", + "amount": 990365075, + "lockTime": 0 + }, + { + "address": "tNULSeBaMoW9Sfp8k9ZsyN9TdQJ46HE79ZJ6N1", + "amount": 990215000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMuXTeixM7NTXnqJXjpkX9pTHJYWyLi", + "amount": 987971650, + "lockTime": 0 + }, + { + "address": "tNULSeBaMu1azoD42sgbXieQXvVrJ7UaG3XZ5n", + "amount": 943664925, + "lockTime": 0 + }, + { + "address": "tNULSeBaMn8Vnc7GkrCoAeTq1WkFcp2TfqMbT8", + "amount": 931693142, + "lockTime": 0 + }, + { + "address": "tNULSeBaMyqxHH3kcs3oW9Z9F7iDVeb4mX9Shg", + "amount": 910000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMvURH3PTTymq87zWELDRPfntEcKqxe", + "amount": 900000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN6f7yZyzfEC6Fk9kn4tR91hRmZPRCe", + "amount": 900000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMxX4Cck8x4VBiEaJekSM96LuhzBioE", + "amount": 900000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMk96AQLcBYCF7Y8Uu2M2njUnBP6NnS", + "amount": 897352075, + "lockTime": 0 + }, + { + "address": "tNULSeBaN3wLRNdEAJauVSSmZDPyJSajpQcuQY", + "amount": 890000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrUxF7arWJWu8yRqg9hsYXfmSUBA5B", + "amount": 879906275, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjN2bU6SVdexbgidt2HnzVpeRnt49Z", + "amount": 872582350, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnB5ixrCA8in5EUfPeqK9Zt1xP1EYs", + "amount": 793455975, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiChHwvG7sfB3xPQTNPxkhGRtiaT3w", + "amount": 791410550, + "lockTime": 0 + }, + { + "address": "tNULSeBaMrwUz8bU1XMRUC6khm4tyq86ga7jS7", + "amount": 790504925, + "lockTime": 0 + }, + { + "address": "tNULSeBaMr3iv3RUQVv96J69NnZYPRnr8nxAFZ", + "amount": 790406650, + "lockTime": 0 + }, + { + "address": "tNULSeBaN89qJfojEeyx6sCk96wQsVPJW8ESn4", + "amount": 700000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMqU97nKCGYCa1ieibAGRvVSvqtTfWC", + "amount": 617648875, + "lockTime": 0 + }, + { + "address": "tNULSeBaMiQHAZvrYk8mVs9b2z2qLoe9fLE8eq", + "amount": 599800000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtWWtyNzxBobrVs3aUZNRGW8ctqq4L", + "amount": 592460450, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtJ1EsjuTmt3VA9JJC671QRZyAFEWe", + "amount": 584532175, + "lockTime": 0 + }, + { + "address": "tNULSeBaMh3YB3Z2au2AHx6PAWxVGbK8nNH42R", + "amount": 504715075, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtw8wa3kPrRnFqxwqTqKiTSgxQ59bn", + "amount": 503472725, + "lockTime": 0 + }, + { + "address": "tNULSeBaMyFCG3iHXFFzQyR5rrgDuNdXLPVUYg", + "amount": 500000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgveRLMLR5ePCHgG1usCJgAgpVFThw", + "amount": 500000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN9r2YoeMe8UxKKki9uvvkL2pvVoT6z", + "amount": 500000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN8yiYwrAS2cDUxiipCiiwEgBVqYKoE", + "amount": 400000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMtYoFGZnqAjtbgPaSFcgg9i5UXddCj", + "amount": 390000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMkUQuBCSYQVzZomwt5PcoG9ahRjaZd", + "amount": 336931850, + "lockTime": 0 + }, + { + "address": "tNULSeBaMv7zuJjuX7VadAskjcdJRpaWLYRrK6", + "amount": 300000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMgQ47kJpokQpiKqskW8D44tpZwUrjm", + "amount": 268625550, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfJ931baxc8Y4Qofjmmpug4vgT4qKc", + "amount": 262469200, + "lockTime": 0 + }, + { + "address": "tNULSeBaMjszE8KTrL6agA1CSeeotRuDytQ3Ke", + "amount": 206830350, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpgyue7v6vjbyy9Un9NYd8iJekpZM3", + "amount": 200000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN12uzLzrzQ3eMRitJaipvTTQeUdMje", + "amount": 200000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMizcomL3nVDSPjHLz8gXPzqGf78Q9X", + "amount": 199900000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMnf7ewzXhSHcAYd8K3zCPBL5zSy8tG", + "amount": 187905200, + "lockTime": 0 + }, + { + "address": "tNULSeBaMfakaaHfp1V4zgEd7MJL8mJ4kzsqoc", + "amount": 145118425, + "lockTime": 0 + }, + { + "address": "tNULSeBaNBaFvNEXA1wZfY2myTe55utRB5HzoL", + "amount": 140000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMk45HSNGQptGTfNKto5dcePXgRpWw8", + "amount": 130185000, + "lockTime": 0 + }, + { + "address": "tNULSeBaMn4hYKGuVzbgKaa8rjsZPJAgGmovwr", + "amount": 122179425, + "lockTime": 0 + }, + { + "address": "tNULSeBaMpgNE2cQaW2aXL9ocAgwtREXStujsB", + "amount": 110000000, + "lockTime": 0 + }, + { + "address": "tNULSeBaN8qPUMP2m9sBZzkfS2FhJAcC4eEGfW", + "amount": 100001664, "lockTime": 0 } ], "alias": [ + { + "address": "tNULSeBaMmTkgNtWA1jnyKBYKUC3vV4Sa57ovL", + "alias": "rabbit" + }, + { + "address": "tNULSeBaMspaJDzLdnDhgzS34K8i3Gs9MbcV2h", + "alias": "chinanuls_00" + }, + { + "address": "tNULSeBaMp3wgK6qReYWpLHrNEHrLmRfJSsx15", + "alias": "nede_1" + }, + { + "address": "tNULSeBaMhDQdoZJPjKPq1W8ehztifNGNPZ3EF", + "alias": "niels" + }, + { + "address": "tNULSeBaMfYYx6Pk652k5biNdACmzdSG6UU6N4", + "alias": "lin" + }, + { + "address": "tNULSeBaMiAQSiqXHBUypfMGZzcroe12W4SFbi", + "alias": "abcdefghijklmnopqrst" + }, + { + "address": "tNULSeBaMs65bgZmzzBZiHkzREz2cxtUp2bvGX", + "alias": "lichao" + }, + { + "address": "tNULSeBaMmESkMomLrvxg9Yj8nJsVyE2wW6mJF", + "alias": "nulshope" + }, + { + "address": "tNULSeBaMr9KDm7dH99h4UJYPHNi4wo6Tf5giV", + "alias": "luo" + }, + { + "address": "tNULSeBaMpZ8NxS5vJVqr5xpBjycQn2Xud3ZD2", + "alias": "testhh" + }, + { + "address": "tNULSeBaMnEysBLhWS8yMS5Cc6GLypiFAQMTpT", + "alias": "prosperous_test" + }, + { + "address": "tNULSeBaMqCqyLYqcgYZ3dyZowAyoLaS2HD8ma", + "alias": "lc" + }, + { + "address": "tNULSeBaMsvXgCBnaJ4u7rbQEKiWd23VWCudYm", + "alias": "angelillou_testnet" + }, + { + "address": "tNULSeBaMgUpGQRHxX5QgWtPLrMWJioLeiNKWD", + "alias": "mick_one" + }, + { + "address": "tNULSeBaMkDXgwPXjczu479GjBxrDSRDdLLWq6", + "alias": "nuls001" + }, + { + "address": "tNULSeBaMnm4wKr3Uj82VVeZ7Uxhm7hvvKkYCb", + "alias": "prosperity_test" + }, + { + "address": "tNULSeBaMvEtDfvZuukDf2mVyfGo3DdiN8KLRG", + "alias": "bolang" + }, + { + "address": "tNULSeBaMud9PbxkfrWyBExWjLrbyFsrsrQZC6", + "alias": "prosper_test" + }, + { + "address": "tNULSeBaMswWdvgYfR33ALR4mEp1jAahzpyeVH", + "alias": "test_windows" + }, + { + "address": "tNULSeBaMnTf4LrYZzXeQXAhX4JaCY24dcCBED", + "alias": "nulsfans" + }, + { + "address": "tNULSeBaMgC5kwDkiJKRRmNzGzDpJr3AgaA7ea", + "alias": "nuls_gold" + }, + { + "address": "tNULSeBaMrge7NFuVUodnJVfyCfSweej8AZrwr", + "alias": "fj_ly_lc_201901" + }, + { + "address": "tNULSeBaMqSDRDdeD9wj47Zu252c7xvxwMKZw5", + "alias": "nulsfather" + }, + { + "address": "tNULSeBaMraPGcjxNFfVrS9op6cPwtg1WCsCqJ", + "alias": "test148" + }, + { + "address": "tNULSeBaMvR7t3q5pxThzQBCNjd9prbjzd5tyd", + "alias": "test149" + }, + { + "address": "tNULSeBaMh1cKVLomRNUaMmtZSV8AN67sTeQ4U", + "alias": "zlin" + }, + { + "address": "tNULSeBaMpjTH4Nsc32RbGec6JQvwyYGEt1jjH", + "alias": "lining2" + }, + { + "address": "tNULSeBaMkPHjgPqwooETMzttafPepJBPED6yd", + "alias": "a_b_c_d_e_f_g_h_i" + }, + { + "address": "tNULSeBaMokyuNzNJyL3RsZjbGgzvefGULJ2wX", + "alias": "huobitest1" + }, + { + "address": "tNULSeBaMioVnTwyEvn7KNqQeGkK5XgbY3ykwX", + "alias": "nuls002" + }, + { + "address": "tNULSeBaMpPHAZ1if1a6csc1zau8SX2G3wEUfS", + "alias": "fj_ly_lc_201903" + }, + { + "address": "tNULSeBaMp31xDJLQ4sQPVP5GQBEiewUEaAwCz", + "alias": "fj_ly_lc_201902" + }, + { + "address": "tNULSeBaMhTtbe1fo1F9hijPr3x2j3XzfmhTZC", + "alias": "test145" + }, + { + "address": "tNULSeBaMmeJBW66dvE8afbBJZFFDskM2A8NCX", + "alias": "wave" + }, + { + "address": "tNULSeBaMpQaoMKRDFUCf2XgZFq22N1Swg4cho", + "alias": "nede_4" + }, + { + "address": "tNULSeBaMvJbNgG7mP3Bo6D1rTAbLLM2nQuQVD", + "alias": "nede_2" + }, + { + "address": "tNULSeBaMkTJ3QzVf1B8PDBW9Jjs54iU2aLoay", + "alias": "nede_3" + }, + { + "address": "tNULSeBaMsnVD1YFaxfnY9XKNoKQyJS8Ljibgp", + "alias": "chinanuls_01" + }, + { + "address": "tNULSeBaMhPs944jLUiUCQCK2g83NR2iLqCkL1", + "alias": "chinanuls_02" + }, + { + "address": "tNULSeBaMr55MEy1b5ErfYLZZqUhsLKVFq4CZi", + "alias": "chinanuls_03" + }, + { + "address": "tNULSeBaMtU9ta3k4oq5gpjeR3oPTCgXM5K7H3", + "alias": "chinanuls_04" + }, + { + "address": "tNULSeBaMobmtKCzTox47r4jUW4xqCgt7LvT2m", + "alias": "chinanuls_05" + }, + { + "address": "tNULSeBaMmkapqddfr2ttGwcscb9brwJM6fUNk", + "alias": "chinanuls_06" + }, + { + "address": "tNULSeBaMmDsxQhavUbA2p7vqWvG8ZuiCXBGfq", + "alias": "chinanuls_07" + }, + { + "address": "tNULSeBaMpGYFnDi9Dkfq2bX3yB3LzkcNUBtKg", + "alias": "chinanuls_08" + }, + { + "address": "tNULSeBaMftsAf77CyArjp51LABH4GyyjV7wpV", + "alias": "chinanuls_10" + }, + { + "address": "tNULSeBaMh8coYfzqHhWfK59E44A6qQBuScj5p", + "alias": "chinanuls_11" + }, + { + "address": "tNULSeBaMgC3w9W7SVp5hFHmAWFmBFkzg1Vgw9", + "alias": "chinanuls_12" + }, + { + "address": "tNULSeBaMfwmeDJp9pDS6EfjVVqVqayzGXJpfu", + "alias": "chinanuls_09" + }, + { + "address": "tNULSeBaMikNrK5aPTr6kzRcNhJzrRMVHgQLVg", + "alias": "a_______________a" + }, + { + "address": "tNULSeBaMpRWgtdmv5X5qbDAihMsXModQJCuwk", + "alias": "lining" + }, + { + "address": "tNULSeBaMk69wKjbUvAsGXsrmKH24ZmReQ8Ttv", + "alias": "lining1" + }, + { + "address": "tNULSeBaMgtJfpvp6babwow3Gw7qZcTi97ox3G", + "alias": "huawei" + }, + { + "address": "tNULSeBaMnNZHHLwae8UAouJiro6URjwMkkMHv", + "alias": "kathy" + }, + { + "address": "tNULSeBaMrdU5t6iLN64kriP3adesp3XYcyhGL", + "alias": "alias123" + }, + { + "address": "tNULSeBaMiXL1JA7k8sEAtX3pYwmcxKZHpHL2K", + "alias": "test2" + }, + { + "address": "tNULSeBaMpCMSD27z8DLQb1D6iRiYACMuBSM6s", + "alias": "nuls_create_alias" + }, + { + "address": "tNULSeBaMnRAJarbMXyjBqPqZkk2CKSZ8HRkaD", + "alias": "000000" + } ], "extend": "01000000010076c8775d0100010001005a64002056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421", "remark": "4f70656e2c204c69626572616c2c204175746f6e6f6d6f75732c2053656c662d45766f6c76696e670ae5bc80e694beefbc8ce887aae794b1efbc8ce887aae6b2bbefbc8ce8bf9be58c960a4f75766572742c204c696272652c204175746f6e6f6d652c20c389766f6c757469660ae382aae383bce38397e383b3e38081e38395e383aae383bce38081e887aae6b2bbe38081e980b2e58c960ad09ed182d0bad180d18bd182d18bd0b92c20d0a1d0b2d0bed0b1d0bed0b4d0bdd0b0d18f2c20d090d0b2d182d0bed0bdd0bed0bcd0bdd0b0d18f2c20d18dd0b2d0bed0bbd18ed186d0b8d18f0aeab09cebb0a9eca0812020eca784ebb3b4eca08120ec9e90ec9ca8eca08120ed9881ebaa85eca0810a4162696572746f2c204c696272652c20417574c3b36e6f6d6f2c2045766f6c757469766f0ad981d8aad8ad20d88c20d8add8b120d88c20d985d8b3d8aad982d98420d88c20d8aad8b7d988d8b10a4f6666656e2c20667265692c206175746f6e6f6d2c2045766f6c7574696f6e0a45766f6c75c3a7c3a36f206162657274612c206c69767265206520617574c3b36e6f6d610ac39670706e612c20667269612c206175746f6e6f6d612c2065766f6c7574696f6e0ace91cebdcebfceb9cebacf84ceae2c20ceb5cebbceb5cf8dceb8ceb5cf81ceb72c20ceb1cf85cf84cf8ccebdcebfcebcceb72c20ceb5cebeceadcebbceb9cebeceb70a41c3a7c4b16b2c20c3b67a67c3bc722c20c3b67a65726b2c20657672696d0a4f736361696c2c2073616f7220696e2061697363652c206e65616d6873706c65c3a163682c20c3a96162686cc3b36964", "privateKey": "009cf05b6b3fe8c09b84c13783140c0f1958e8841f8b6f894ef69431522bc65712" } - diff --git a/module.ncf b/module.ncf index ffb7b1b1f..c4a844a97 100644 --- a/module.ncf +++ b/module.ncf @@ -5,43 +5,45 @@ logPath=/Users/wangzhijian/workspace/nuls-v2/logs logLevel=INFO dataPath=/Users/wangzhijian/workspace/nuls-v2/data #Default This ChainID -chainId=1 +chainId=2 #Address prefix -addressPrefix=NULS +addressPrefix=tNULS #Default main asset of this chainID assetId=1 -#Default Decimal Places for Assets -decimals=8 #Default Chain Name -chainName=nuls +chainName=nuls2 #The default asset symbol for this chain symbol=NULS +#The exact decimal places of default assets +decimals=8 #Main network chainid -mainChainId=1 +mainChainId=2 #Main network assetsid mainAssetId=1 #Main network main asset symbol mainSymbol=NULS blackHolePublicKey=000000000000000000000000000000000000000000000000000000000000000000 -packageVersion=%PACKAGE_VERSION% +packageVersion=2.7.0-a4354e9 + [network] -port=8001 -crossPort=8002 +port=18001 +crossPort=18002 #Magic parameters -packetMagic=20194444 -#Seed node -selfSeedIps=127.0.0.1:8001 -#Cross chain seed connection nodes of the main network -moonSeedIps=127.0.0.1:8002 +packetMagic=20200120 +#种子节点 +selfSeedIps=seedt1.nuls.io:18001,seedt2.nuls.io:18001,seedt3.nuls.io:18001 +#主网的跨链种子连接节点 +moonSeedIps=seedt1.nuls.io:18002,seedt2.nuls.io:18002,seedt3.nuls.io:18002 #Maximum number of network connections -maxInCount=300 +maxInCount=100 #Maximum number of outbound connections maxOutCount=20 + [account] -blockAccountManager=NULSd6Hgck6xuMvGasN6yo4Ep8DatJfqpqhKZ +blockAccountManager=tNULSeBaNE8nFpFo6qYiPiNHSbsGyKSceJLwQt keystoreFolder=/keystore/backup [block] @@ -52,7 +54,7 @@ extendMaxSize=1024 #Threshold of height difference that triggers fork chain switching chainSwtichThreshold=3 #Minimum number of linked nodes,When the network node linked to is below this parameter,Will continue to wait -minNodeAmount=0 +minNodeAmount=2 #During block synchronization process,The number of blocks downloaded from nodes on the network each time downloadNumber=10 #The timeout for downloading a single block from a network node @@ -62,26 +64,22 @@ cachedBlockSizeLimit=20971520 #Genesis block file path(Supports absolute and relative paths,Relative path relative to the directory of this configuration file) genesisBlockPath=genesis-block.json - - [consensus] #Seed node list -seedNodes=NULSd6Hgck6xuMvGasN6yo4Ep8DatJfqpqhKZ +seedNodes=tNULSeBaMkrt4z9FYEkkR9D6choPVvQr94oYZp,tNULSeBaMoGr2RkLZPfJeS5dFzZeNj1oXmaYNe,tNULSeBaMmShSTVwbU4rHkZjpD98JgFgg6rmhF #Block address password password=nuls123456 #Block output interval time(unit:s) packingInterval=10 #Consensus entrusted mortgage asset chainID -agentChainId=1 +agentChainId=2 #Consensus entrusted mortgage assetsID agentAssetId=1 #Consensus reward assetsID(Consensus rewards must be assets of the same chain) awardAssetId=1 -#Consensus transaction fee unit price -feeUnit=100000 #Total Inflation totalInflationAmount=11000000000000000 -#Initial inflation amount500w/365*30 +#Initial inflation amount500w/265*30 inflationAmount=41095890410959 #Inflation start calculation time(unit:S)2020-07-12 00:00:00 initTime=1594483200 @@ -89,15 +87,20 @@ initTime=1594483200 deflationRatio=0.4 #Deflation interval time(unit:S),30day deflationTimeInterval=2592000 +feeAssets=2-1,2-201,2-202 +feeUnit=100000,10000,100000000000000 [smart-contract] #The maximum consumption of contract view method callsGas maxViewGas=100000000 -crossTokenSystemContract=NULSd6HgsyGNK1xTcx2GnC9y3Jr1DKd3qL2HS +systemLogLevel=WARN +crossTokenSystemContract=tNULSeBaMy9k29Nj4rd3U4tonVr93mrDLHMNNd +# 单位gasPrice小数点位移 +feeCoefficient=1,0.0001,10000000 [public-service] #public-serviceModule ExternalrpcPort number -rpcPort=8003 +rpcPort=18003 #databaseurladdress databaseUrl=127.0.0.1 #Database port number @@ -106,53 +109,50 @@ databasePort=27017 maxAliveConnect=20 #Maximum waiting time for connection maxWaitTime=120000 -#Maximum duration of connection -socketTimeout=300000 #Connection timeout connectTimeOut=30000 -developerNodeAddress=NULSd6Hgf15aUZj6918tEwy9aT4JG1ZQotXRF -ambassadorNodeAddress=NULSd6HgcfGtsmm79QDoBK1MAjqNmm3rgKXSj -mappingAddress=NULSd6HgcfwWCD5TLEfehrJ1fFYuZ6nqGbfiu,NULSd6HggAGpQbhhSHU9R1yRxKKuCCTFwayaB -businessAddress=NULSd6HhDrCkRJBj9nX1Gr1PnuQP7bpQz3YfH,NULSd6HhDMDJASAH7VxLRY9Btff1k3ezpM66w -teamAddress=NULSd6Hh6m73yRYCn8ff2jo9qN93bh4GpzFDn -communityAddress=NULSd6Hh76ja8dHkTdYvTJS9gEAygiU1uLRGR,NULSd6Hh84g7u61ntrWhrdEMjXvM9STRPxFZx,NULSd6Hh8xn55HeTWKwRAG31fj2eHtq6Aw2Rg +developerNodeAddress=tNULSeBaMuKuKY4UstKpXvGxd7LEvEBtd3NXAG,tNULSeBaMns1C6kTePxcQS7rGAu37foAwAMpri +ambassadorNodeAddress=tNULSeBaMhWyQBHc54oXLXB13WhJsyrTobMYYU,tNULSeBaMtCmUuBHMDAjKVSoVBsAEvLoWCspyE +mappingAddress=tNULSeBaMqTC6rnF56dnJqz1Fb8gMdVxGGvxSf,tNULSeBaMkroWKUKj6X4zURBE3V47VZwMJdHPm +businessAddress=tNULSeBaMnf1qfX7emr14att2DsSb2TSPcPBSL +teamAddress=tNULSeBaMqTvaS2NEEZfdrmPzoRvd8zN6T57LH +communityAddress=tNULSeBaMm9RQLKKUBXKJ1rQ7g4iobmWAB73mS syncCoinBase=false syncAddress= [cross-chain] #The minimum value of cross chain node links -minNodes=3 +minNodes=2 #Maximum value of cross chain node links sendHeight=6 #Byzantine proportion of cross chain transactions byzantineRatio=66 #Main network cross chain seed node list -crossSeedIps=127.0.0.1:8002 +crossSeedIps=seedt1.nuls.io:18001,seedt2.nuls.io:18001,seedt3.nuls.io:18001 #List of main network validators -verifiers=NULSd6Hgck6xuMvGasN6yo4Ep8DatJfqpqhKZ +verifiers=tNULSeBaMkrt4z9FYEkkR9D6choPVvQr94oYZp,tNULSeBaMmShSTVwbU4rHkZjpD98JgFgg6rmhF,tNULSeBaMoGr2RkLZPfJeS5dFzZeNj1oXmaYNe #Main network signature Byzantine comparison mainByzantineRatio=66 #Maximum number of signatures on the main network maxSignatureCount=100 + +[nuls-module-explorer] +apiModuleApi=http://127.0.0.1:18003/ +explorerPort=1999 +explorerHost=0.0.0.0 + +[nuls-module-web-wallet] +apiModuleApi=http://127.0.0.1:18003/ +webWalletPort=18006 +webWalletHost=0.0.0.0 + [protocol-update] #How many blocks do we count the proportion of protocols per second -interval=1000 +interval=10 [nuls-api] #httpServerStart ofip serverIp=0.0.0.0 #httpServerStart ofport -serverPort=8004 - - -[nuls-module-web-wallet] -apiModuleApi=http://127.0.0.1:8003/ -webWalletPort=8006 -webWalletHost=0.0.0.0 - -[nuls-module-explorer] -apiModuleApi=http://127.0.0.1:8003/ -explorerPort=1999 -explorerHost=0.0.0.0 - +serverPort=18004 diff --git a/module/nuls-cmd-client/src/main/java/io/nuls/cmd/client/processor/block/RollbackProcessor.java b/module/nuls-cmd-client/src/main/java/io/nuls/cmd/client/processor/block/RollbackProcessor.java index 42b14cb67..66e8b7082 100644 --- a/module/nuls-cmd-client/src/main/java/io/nuls/cmd/client/processor/block/RollbackProcessor.java +++ b/module/nuls-cmd-client/src/main/java/io/nuls/cmd/client/processor/block/RollbackProcessor.java @@ -87,7 +87,7 @@ public CommandResult execute(String[] args) { if(height>1000){ return CommandResult.getFailed("The count is too big"); } - Result result = blockService.rollback(new GetBlockHeaderByHeightReq(height)); + Result result = blockService.rollback(new GetBlockHeaderByHeightReq(height)); if(result.isFailed()){ return CommandResult.getFailed(result); diff --git a/module/nuls-cmd-client/src/main/java/io/nuls/cmd/client/processor/ledger/GetBalanceProcessor.java b/module/nuls-cmd-client/src/main/java/io/nuls/cmd/client/processor/ledger/GetBalanceProcessor.java index 37d861f7d..1350bd6dc 100644 --- a/module/nuls-cmd-client/src/main/java/io/nuls/cmd/client/processor/ledger/GetBalanceProcessor.java +++ b/module/nuls-cmd-client/src/main/java/io/nuls/cmd/client/processor/ledger/GetBalanceProcessor.java @@ -106,9 +106,9 @@ public CommandResult execute(String[] args) { } Integer decimalInt = AssetsUtil.getCrossAssetDecimal(assetChainId, assetId); Map r = new HashMap<>(3); - r.put("available",config.toBigUnit(result.getData().getAvailable(),decimalInt)); - r.put("freeze",config.toBigUnit(result.getData().getFreeze(),decimalInt)); - r.put("total",config.toBigUnit(result.getData().getTotal(),decimalInt)); + r.put("available",AssetsUtil.toBigUnit(result.getData().getAvailable(),decimalInt)); + r.put("freeze",AssetsUtil.toBigUnit(result.getData().getFreeze(),decimalInt)); + r.put("total",AssetsUtil.toBigUnit(result.getData().getTotal(),decimalInt)); return CommandResult.getSuccess(new Result(r)); } diff --git a/module/nuls-cmd-client/src/main/java/io/nuls/cmd/client/utils/AssetsUtil.java b/module/nuls-cmd-client/src/main/java/io/nuls/cmd/client/utils/AssetsUtil.java index d14fdbf76..de5f61afe 100644 --- a/module/nuls-cmd-client/src/main/java/io/nuls/cmd/client/utils/AssetsUtil.java +++ b/module/nuls-cmd-client/src/main/java/io/nuls/cmd/client/utils/AssetsUtil.java @@ -10,12 +10,15 @@ import io.nuls.core.rpc.model.message.Response; import io.nuls.core.rpc.netty.processor.ResponseMessageProcessor; +import java.math.BigDecimal; +import java.math.BigInteger; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Asset instruments + * * @author lanjinsheng * @description * @date 2019/11/07 @@ -32,7 +35,17 @@ public static Integer getCrossAssetDecimal(int chainId, int assetId) { if (null == ASSETS_DECIMALS.get(key)) { initRegisteredChainInfo(); } - return ASSETS_DECIMALS.get(key); + Integer val = ASSETS_DECIMALS.get(key); + if (null != val) { + return val; + } + if (chainId == 2 && assetId == 201) { + return 8; + } + if (chainId == 2 && assetId == 202) { + return 18; + } + return null; } public static Result initRegisteredChainInfo() { @@ -99,4 +112,10 @@ public static Object request(String moduleCode, String cmd, Map params, Long tim throw new NulsException(ErrorCodeConstants.SYSTEM_ERR, e.getMessage()); } } + + public static BigDecimal toBigUnit(BigInteger val, Integer decimals) { + BigDecimal decimal = BigDecimal.TEN.pow(decimals); + BigDecimal dval = new BigDecimal(val); + return dval.divide(decimal); + } } diff --git a/module/nuls-cores/pom.xml b/module/nuls-cores/pom.xml index 4bab24fc9..cce4de283 100644 --- a/module/nuls-cores/pom.xml +++ b/module/nuls-cores/pom.xml @@ -100,7 +100,7 @@ com.google.guava guava - 31.0.1-jre + 33.2.1-jre diff --git a/module/nuls-cores/src/main/java/io/nuls/account/service/impl/AliasServiceImpl.java b/module/nuls-cores/src/main/java/io/nuls/account/service/impl/AliasServiceImpl.java index ad62aa127..e3793b8f0 100644 --- a/module/nuls-cores/src/main/java/io/nuls/account/service/impl/AliasServiceImpl.java +++ b/module/nuls-cores/src/main/java/io/nuls/account/service/impl/AliasServiceImpl.java @@ -75,6 +75,7 @@ import java.util.concurrent.locks.ReentrantLock; import static io.nuls.account.util.TxUtil.getSuccess; +import static io.nuls.common.CommonConstant.NORMAL_PRICE_PRE_1024_BYTES_NULS; /** * @author: EdwardChan @@ -318,7 +319,7 @@ private Transaction createAliasTrasactionWithoutSign(Chain chain, Account accoun CoinTo coinTo = new CoinTo(AddressTool.getAddress(NulsConfig.BLACK_HOLE_PUB_KEY,account.getChainId()), account.getChainId(), assetsId, AccountConstant.ALIAS_FEE); int txSize = tx.size() + coinFrom.size() + coinTo.size() + P2PHKSignature.SERIALIZE_LENGTH; //Calculate handling fees - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize,NORMAL_PRICE_PRE_1024_BYTES_NULS); //The total cost is BigInteger totalAmount = AccountConstant.ALIAS_FEE.add(fee); coinFrom.setAmount(totalAmount); diff --git a/module/nuls-cores/src/main/java/io/nuls/account/service/impl/TransactionServiceImpl.java b/module/nuls-cores/src/main/java/io/nuls/account/service/impl/TransactionServiceImpl.java index fddad1711..f4e2356f7 100644 --- a/module/nuls-cores/src/main/java/io/nuls/account/service/impl/TransactionServiceImpl.java +++ b/module/nuls-cores/src/main/java/io/nuls/account/service/impl/TransactionServiceImpl.java @@ -78,6 +78,8 @@ import java.util.function.Function; import java.util.stream.Collectors; +import static io.nuls.common.CommonConstant.NORMAL_PRICE_PRE_1024_BYTES_NULS; + /** * @author: qinyifeng */ @@ -398,7 +400,7 @@ public Transaction createSetAliasTxWithoutSign(Chain chain, Address address, Str CoinTo coinTo = new CoinTo(blackHoleAddress, assetChainId, assetId, AccountConstant.ALIAS_FEE); int txSize = tx.size() + coinFrom.size() + coinTo.size() + msign * P2PHKSignature.SERIALIZE_LENGTH; //Calculate handling fees - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize, NORMAL_PRICE_PRE_1024_BYTES_NULS); //The total cost is BigInteger totalAmount = AccountConstant.ALIAS_FEE.add(fee); coinFrom.setAmount(totalAmount); @@ -634,7 +636,7 @@ private CoinData getCoinData(Chain chain, List listFrom, List } } //The expected handling fee for this transaction - BigInteger targetFee = TransactionFeeCalculator.getNormalTxFee(txSize); + BigInteger targetFee = TransactionFeeCalculator.getNormalTxFee(txSize, NORMAL_PRICE_PRE_1024_BYTES_NULS); //Actual transaction fees collected, Maybe I have already assembled it myself BigInteger actualFee = feeTotalFrom.subtract(feeTotalTo); if (BigIntegerUtils.isLessThan(actualFee, BigInteger.ZERO)) { @@ -734,7 +736,7 @@ private boolean getFeeIndirect(Chain chain, List listFrom, int txSize, feeCoinFrom.setNonce(nonceBalance.getNonce()); txSize += feeCoinFrom.size(); //Due to the addition ofCoinFrom, it is necessary to recalculate the expected handling fee for this transaction - targetFee = TransactionFeeCalculator.getNormalTxFee(txSize); + targetFee = TransactionFeeCalculator.getNormalTxFee(txSize, NORMAL_PRICE_PRE_1024_BYTES_NULS); //Current outstanding handling fees BigInteger current = targetFee.subtract(actualFee); //The handling fees that this account can pay diff --git a/module/nuls-cores/src/main/java/io/nuls/chain/rpc/cmd/BaseChainCmd.java b/module/nuls-cores/src/main/java/io/nuls/chain/rpc/cmd/BaseChainCmd.java index b37c3f66c..f340d439b 100644 --- a/module/nuls-cores/src/main/java/io/nuls/chain/rpc/cmd/BaseChainCmd.java +++ b/module/nuls-cores/src/main/java/io/nuls/chain/rpc/cmd/BaseChainCmd.java @@ -51,6 +51,8 @@ import java.math.BigInteger; import java.util.List; +import static io.nuls.common.CommonConstant.NORMAL_PRICE_PRE_1024_BYTES_NULS; + /** * @author lan * @date 2018/11/28 @@ -97,7 +99,7 @@ CoinData getRegCoinData(Asset asset, int nulsChainId, int nulsAssetId, int txSiz txSize += to1.size(); txSize += to2.size(); txSize += from.size(); - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize, NORMAL_PRICE_PRE_1024_BYTES_NULS); String fromAmount = BigIntegerUtils.bigIntegerToString(asset.getDepositNuls().add(fee)); if (BigIntegerUtils.isLessThan(accountBalance.getAvailable(), fromAmount)) { throw new NulsRuntimeException(CmErrorCode.BALANCE_NOT_ENOUGH); @@ -120,7 +122,7 @@ CoinData getRegCoinDataV7(Asset asset, int nulsChainId, int nulsAssetId, int txS coinData.addTo(to); txSize += from.size(); - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize, NORMAL_PRICE_PRE_1024_BYTES_NULS); String fromAmount = BigIntegerUtils.bigIntegerToString(fee); if (BigIntegerUtils.isLessThan(accountBalance.getAvailable(), fromAmount)) { throw new NulsRuntimeException(CmErrorCode.BALANCE_NOT_ENOUGH); @@ -146,7 +148,7 @@ CoinData getDisableCoinData(Asset asset, int nulsChainId, int nulsAssetId, coinData.addFrom(from); coinData.addTo(to); txSize += from.size(); - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize, NORMAL_PRICE_PRE_1024_BYTES_NULS); String fromAmount = BigIntegerUtils.bigIntegerToString(fee); if (BigIntegerUtils.isLessThan(accountBalance.getAvailable(), fromAmount)) { throw new NulsRuntimeException(CmErrorCode.BALANCE_NOT_ENOUGH); @@ -158,7 +160,7 @@ CoinData getDisableCoinData(Asset asset, int nulsChainId, int nulsAssetId, coinData.addTo(to); txSize += to.size(); txSize += from.size(); - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize, NORMAL_PRICE_PRE_1024_BYTES_NULS); //The handling fee is deducted from the mortgage to.setAmount(lockAmount.subtract(fee)); } diff --git a/module/nuls-cores/src/main/java/io/nuls/common/CommonConstant.java b/module/nuls-cores/src/main/java/io/nuls/common/CommonConstant.java new file mode 100644 index 000000000..27fe6793f --- /dev/null +++ b/module/nuls-cores/src/main/java/io/nuls/common/CommonConstant.java @@ -0,0 +1,8 @@ +package io.nuls.common; + +public class CommonConstant { + + public static final long NORMAL_PRICE_PRE_1024_BYTES_NULS = 100000; + public static final long NORMAL_PRICE_PRE_1024_BYTES_BTC = 10000; + public static final long NORMAL_PRICE_PRE_1024_BYTES_ETH = 100000000000000L; +} diff --git a/module/nuls-cores/src/main/java/io/nuls/common/ConfigBean.java b/module/nuls-cores/src/main/java/io/nuls/common/ConfigBean.java index 5b86f2df4..098f2536a 100644 --- a/module/nuls-cores/src/main/java/io/nuls/common/ConfigBean.java +++ b/module/nuls-cores/src/main/java/io/nuls/common/ConfigBean.java @@ -24,20 +24,29 @@ */ package io.nuls.common; +import io.nuls.core.model.StringUtils; + import java.math.BigInteger; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Set; /** * Transaction module chain setting + * * @author: Charlie * @date: 2019/03/14 */ public class ConfigBean { - /** chain id*/ + /** + * chain id + */ private int chainId; - /** assets id*/ + /** + * assets id + */ private int assetId; /*-------------------------[Block]-----------------------------*/ /** @@ -133,7 +142,7 @@ public class ConfigBean { /** * Minimum number of links * Minimum number of links - * */ + */ private int minNodes; /** @@ -272,12 +281,6 @@ public class ConfigBean { */ private int awardAssetId; - /** - * Transaction fee unit price - * Transaction fee unit price - */ - private long feeUnit; - /** * Total shrinkage * Total inflation amount @@ -325,8 +328,73 @@ public class ConfigBean { private long txUnverifiedQueueSize; /** Orphan Trading Lifetime,Exceeding will be cleared**/ private int orphanTtl; + + private String feeAssets; + private String feeUnit; + + private String feeCoefficient; + + private Map feeUnitMap; + private Map feeCoeffMap; /*----------------------------------------------------------------------*/ + private void initFeeUnitMap() { + if (StringUtils.isNotBlank(feeAssets) && StringUtils.isNotBlank(feeUnit) && feeUnitMap == null) { + feeUnitMap = new HashMap<>(); + String[] keys = feeAssets.split(","); + String[] vals = feeUnit.split(","); + for (int i = 0; i < keys.length; i++) { + feeUnitMap.put(keys[i], Long.parseLong(vals[i])); + } + } + if (StringUtils.isNotBlank(feeAssets) && StringUtils.isNotBlank(feeCoefficient) && feeCoeffMap == null) { + feeCoeffMap = new HashMap<>(); + String[] keys = feeAssets.split(","); + String[] vals = feeCoefficient.split(","); + for (int i = 0; i < keys.length; i++) { + feeCoeffMap.put(keys[i], Double.parseDouble(vals[i])); + } + } + } + + + public Long getFeeUnit(int chainId, int assetId) { + return getFeeUnit(NCUtils.getTokenId(chainId, assetId)); + } + + public Long getFeeUnit(String tokenId) { + if (null == feeUnitMap) { + initFeeUnitMap(); + } + return feeUnitMap.get(tokenId); + } + + public Double getFeeCoefficient(int chainId, int assetId) { + return getFeeCoefficient(NCUtils.getTokenId(chainId, assetId)); + } + + public Double getFeeCoefficient(String tokenId) { + if (null == feeCoeffMap) { + initFeeUnitMap(); + } + return feeCoeffMap.get(tokenId); + } + + public void setFeeAssets(String feeAssets) { + this.feeAssets = feeAssets; + } + + public Set getFeeAssetsSet() { + if (null == feeUnitMap) { + initFeeUnitMap(); + } + return feeUnitMap.keySet(); + } + + public void setFeeUnit(String feeUnit) { + this.feeUnit = feeUnit; + } + public int getChainId() { return chainId; } @@ -719,14 +787,6 @@ public void setAwardAssetId(int awardAssetId) { this.awardAssetId = awardAssetId; } - public long getFeeUnit() { - return feeUnit; - } - - public void setFeeUnit(long feeUnit) { - this.feeUnit = feeUnit; - } - public BigInteger getTotalInflationAmount() { return totalInflationAmount; } diff --git a/module/nuls-cores/src/main/java/io/nuls/common/NCUtils.java b/module/nuls-cores/src/main/java/io/nuls/common/NCUtils.java new file mode 100644 index 000000000..77e57f569 --- /dev/null +++ b/module/nuls-cores/src/main/java/io/nuls/common/NCUtils.java @@ -0,0 +1,18 @@ +package io.nuls.common; + +import io.nuls.core.model.StringUtils; + +public class NCUtils { + + public static String getTokenId(int chainId, int assetId) { + return chainId + "-" + assetId; + } + + public static int[] splitTokenId(String key) { + if (StringUtils.isBlank(key)) { + return null; + } + String[] arr = key.split("-"); + return new int[]{Integer.parseInt(arr[0]), Integer.parseInt(arr[1])}; + } +} diff --git a/module/nuls-cores/src/main/java/io/nuls/common/NulsCoresConfig.java b/module/nuls-cores/src/main/java/io/nuls/common/NulsCoresConfig.java index 6d267e5fd..18158bbf6 100644 --- a/module/nuls-cores/src/main/java/io/nuls/common/NulsCoresConfig.java +++ b/module/nuls-cores/src/main/java/io/nuls/common/NulsCoresConfig.java @@ -219,6 +219,10 @@ public class NulsCoresConfig extends ConfigBean implements ModuleConfig { private String defaultDecimalPlaces = "8"; private int chainAssetsTaskIntervalMinute; + + + //Cross-chain transaction drop time + private long crossTxDropTime = 0; /*----------------------------------------------------------------------*/ public boolean isCollectedSmartContractModule() { @@ -229,6 +233,14 @@ public void setCollectedSmartContractModule(boolean collectedSmartContractModule this.collectedSmartContractModule = collectedSmartContractModule; } + public long getCrossTxDropTime() { + return crossTxDropTime; + } + + public void setCrossTxDropTime(long crossTxDropTime) { + this.crossTxDropTime = crossTxDropTime; + } + public List getLocalIps() { return localIps; diff --git a/module/nuls-cores/src/main/java/io/nuls/consensus/service/impl/AgentServiceImpl.java b/module/nuls-cores/src/main/java/io/nuls/consensus/service/impl/AgentServiceImpl.java index a5358bc68..dbaf59bd8 100644 --- a/module/nuls-cores/src/main/java/io/nuls/consensus/service/impl/AgentServiceImpl.java +++ b/module/nuls-cores/src/main/java/io/nuls/consensus/service/impl/AgentServiceImpl.java @@ -268,7 +268,10 @@ public Result stopAgent(Map params) { long txTime = NulsDateUtils.getCurrentTimeSeconds(); tx.setTime(txTime); CoinData coinData = coinDataManager.getStopAgentCoinData(chain, agent, txTime + chain.getConfig().getStopAgentLockTime()); - BigInteger fee = TransactionFeeCalculator.getConsensusTxFee(tx.size() + P2PHKSignature.SERIALIZE_LENGTH + coinData.serialize().length, chain.getConfig().getFeeUnit()); + + int agentChainId = chain.getConfig().getAgentChainId(); + int agentAssetId = chain.getConfig().getAgentAssetId(); + BigInteger fee = TransactionFeeCalculator.getConsensusTxFee(tx.size() + P2PHKSignature.SERIALIZE_LENGTH + coinData.serialize().length, chain.getConfig().getFeeUnit(agentChainId+"-"+agentAssetId)); coinData.getTo().get(0).setAmount(coinData.getTo().get(0).getAmount().subtract(fee)); tx.setCoinData(coinData.serialize()); //Transaction signature diff --git a/module/nuls-cores/src/main/java/io/nuls/consensus/service/impl/MultiSignServiceImpl.java b/module/nuls-cores/src/main/java/io/nuls/consensus/service/impl/MultiSignServiceImpl.java index ae8c68cd0..3fed5b143 100644 --- a/module/nuls-cores/src/main/java/io/nuls/consensus/service/impl/MultiSignServiceImpl.java +++ b/module/nuls-cores/src/main/java/io/nuls/consensus/service/impl/MultiSignServiceImpl.java @@ -152,7 +152,7 @@ public Result stopMultiAgent(Map params) { tx.setTime(NulsDateUtils.getCurrentTimeSeconds()); int txSignSize = multiSigAccount.getM() * P2PHKSignature.SERIALIZE_LENGTH; CoinData coinData = coinDataManager.getStopAgentCoinData(chain, agent, NulsDateUtils.getCurrentTimeSeconds() + chain.getConfig().getStopAgentLockTime()); - BigInteger fee = TransactionFeeCalculator.getConsensusTxFee(tx.size() + txSignSize + coinData.serialize().length, chain.getConfig().getFeeUnit()); + BigInteger fee = TransactionFeeCalculator.getConsensusTxFee(tx.size() + txSignSize + coinData.serialize().length, chain.getConfig().getFeeUnit( coinData.getTo().get(0).getAssetsChainId(), coinData.getTo().get(0).getAssetsId())); coinData.getTo().get(0).setAmount(coinData.getTo().get(0).getAmount().subtract(fee)); tx.setCoinData(coinData.serialize()); diff --git a/module/nuls-cores/src/main/java/io/nuls/consensus/utils/manager/CoinDataManager.java b/module/nuls-cores/src/main/java/io/nuls/consensus/utils/manager/CoinDataManager.java index e1e983a52..d47e7b6c6 100644 --- a/module/nuls-cores/src/main/java/io/nuls/consensus/utils/manager/CoinDataManager.java +++ b/module/nuls-cores/src/main/java/io/nuls/consensus/utils/manager/CoinDataManager.java @@ -46,13 +46,13 @@ public CoinData getCoinData(byte[] address, Chain chain, BigInteger amount, long coinData.addTo(to); txSize += to.size(); //Mortgage asset amount - Map result = CallMethodUtils.getBalanceAndNonce(chain, AddressTool.getStringAddressByBytes(address),assetChainId,assetId); + Map result = CallMethodUtils.getBalanceAndNonce(chain, AddressTool.getStringAddressByBytes(address), assetChainId, assetId); byte[] nonce = RPCUtil.decode((String) result.get("nonce")); BigInteger available = new BigInteger(result.get("available").toString()); //Verify if the account balance is sufficient CoinFrom from = new CoinFrom(address, assetChainId, assetId, amount, nonce, (byte) 0); txSize += from.size(); - BigInteger fee = TransactionFeeCalculator.getConsensusTxFee(txSize,chain.getConfig().getFeeUnit()); + BigInteger fee = TransactionFeeCalculator.getConsensusTxFee(txSize, chain.getConfig().getFeeUnit(assetChainId, assetId)); BigInteger fromAmount = amount.add(fee); if (BigIntegerUtils.isLessThan(available, fromAmount)) { throw new NulsException(ConsensusErrorCode.BANANCE_NOT_ENNOUGH); @@ -100,7 +100,7 @@ public CoinData getContractCoinData(byte[] address, Chain chain, BigInteger amou public CoinData getUnlockCoinData(byte[] address, Chain chain, BigInteger amount, long lockTime, int txSize) throws NulsException { int agentChainId = chain.getConfig().getAgentChainId(); int agentAssetId = chain.getConfig().getAssetId(); - Map balanceMap = CallMethodUtils.getBalance(chain, AddressTool.getStringAddressByBytes(address),agentChainId,agentAssetId); + Map balanceMap = CallMethodUtils.getBalance(chain, AddressTool.getStringAddressByBytes(address), agentChainId, agentAssetId); BigInteger freeze = new BigInteger(balanceMap.get("freeze").toString()); if (BigIntegerUtils.isLessThan(freeze, amount)) { throw new NulsException(ConsensusErrorCode.BANANCE_NOT_ENNOUGH); @@ -113,7 +113,7 @@ public CoinData getUnlockCoinData(byte[] address, Chain chain, BigInteger amount CoinFrom from = new CoinFrom(address, agentChainId, agentAssetId, amount, (byte) -1); coinData.addFrom(from); txSize += from.size(); - BigInteger fee = TransactionFeeCalculator.getConsensusTxFee(txSize,chain.getConfig().getFeeUnit()); + BigInteger fee = TransactionFeeCalculator.getConsensusTxFee(txSize, chain.getConfig().getFeeUnit(agentChainId, agentAssetId)); BigInteger realToAmount = amount.subtract(fee); to.setAmount(realToAmount); return coinData; @@ -130,7 +130,7 @@ public CoinData getUnlockCoinData(byte[] address, Chain chain, BigInteger amount * @return AssembledCoinData/Assembled CoinData */ public CoinData getContractUnlockCoinData(byte[] address, Chain chain, BigInteger amount, long lockTime) throws NulsException { - Map balanceMap = CallMethodUtils.getBalance(chain, AddressTool.getStringAddressByBytes(address),chain.getConfig().getChainId(),chain.getConfig().getAssetId()); + Map balanceMap = CallMethodUtils.getBalance(chain, AddressTool.getStringAddressByBytes(address), chain.getConfig().getChainId(), chain.getConfig().getAssetId()); BigInteger freeze = new BigInteger(balanceMap.get("freeze").toString()); if (BigIntegerUtils.isLessThan(freeze, amount)) { throw new NulsException(ConsensusErrorCode.BANANCE_NOT_ENNOUGH); diff --git a/module/nuls-cores/src/main/java/io/nuls/consensus/utils/validator/TxValidator.java b/module/nuls-cores/src/main/java/io/nuls/consensus/utils/validator/TxValidator.java index 0e5759c07..253607099 100644 --- a/module/nuls-cores/src/main/java/io/nuls/consensus/utils/validator/TxValidator.java +++ b/module/nuls-cores/src/main/java/io/nuls/consensus/utils/validator/TxValidator.java @@ -231,7 +231,7 @@ private boolean validateDeposit(Chain chain, Transaction tx) throws NulsExceptio size -= tx.getTransactionSignature().length; } - BigInteger fee = TransactionFeeCalculator.getConsensusTxFee(size, chain.getConfig().getFeeUnit()); + BigInteger fee = TransactionFeeCalculator.getConsensusTxFee(size, chain.getConfig().getFeeUnit(chain.getConfig().getAgentChainId(), chain.getConfig().getAgentAssetId())); if (fee.compareTo(consensusManager.getFee(coinData, chain.getConfig().getAgentChainId(), chain.getConfig().getAgentAssetId())) > 0) { chain.getLogger().error("Insufficient handling fees!"); throw new NulsException(ConsensusErrorCode.FEE_NOT_ENOUGH); @@ -344,7 +344,7 @@ private boolean createAgentBasicValid(Chain chain, Transaction tx, Agent agent) size += transactionSignature.getM() * P2PHKSignature.SERIALIZE_LENGTH; size -= tx.getTransactionSignature().length; } - BigInteger fee = TransactionFeeCalculator.getConsensusTxFee(size, chain.getConfig().getFeeUnit()); + BigInteger fee = TransactionFeeCalculator.getConsensusTxFee(size, chain.getConfig().getFeeUnit(chain.getConfig().getAgentChainId(), chain.getConfig().getAgentAssetId())); if (fee.compareTo(consensusManager.getFee(coinData, chain.getConfig().getAgentChainId(), chain.getConfig().getAgentAssetId())) > 0) { chain.getLogger().error("Insufficient handling fees!"); throw new NulsException(ConsensusErrorCode.FEE_NOT_ENOUGH); @@ -457,7 +457,7 @@ private boolean stopAgentCoinDataValid(Chain chain, Transaction tx, AgentPo agen size += transactionSignature.getM() * P2PHKSignature.SERIALIZE_LENGTH; } size -= tx.getTransactionSignature().length; - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(size); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(size, chain.getConfig().getFeeUnit(chain.getConfig().getChainId(), 1)); last.setAmount(last.getAmount().subtract(fee)); } return Arrays.equals(coinData.serialize(), localCoinData.serialize()); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/SmartContractBootStrap.java b/module/nuls-cores/src/main/java/io/nuls/contract/SmartContractBootStrap.java index ef83d3c97..28675e617 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/SmartContractBootStrap.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/SmartContractBootStrap.java @@ -93,8 +93,9 @@ private void initNulsConfig() { ContractContext.DATA_PATH = contractConfig.getDataPath() + File.separator + ModuleE.SC.name; ContractContext.MAIN_ASSETS_ID = contractConfig.getMainAssetId(); ContractContext.MAIN_CHAIN_ID = contractConfig.getMainChainId(); - ContractContext.CHAIN_ID = contractConfig.getChainId(); - ContractContext.ASSET_ID = contractConfig.getAssetId(); + ContractContext.LOCAL_CHAIN_ID = contractConfig.getChainId(); + ContractContext.LOCAL_MAIN_ASSET_ID = contractConfig.getAssetId(); + ContractContext.FEE_ASSETS_SET = contractConfig.getFeeAssetsSet(); if (StringUtils.isNotBlank(contractConfig.getCrossTokenSystemContract())) { ContractContext.CROSS_CHAIN_SYSTEM_CONTRACT = AddressTool.getAddress(contractConfig.getCrossTokenSystemContract()); } diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/callable/ContractTxCallable.java b/module/nuls-cores/src/main/java/io/nuls/contract/callable/ContractTxCallable.java index eed3f9826..178a4a817 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/callable/ContractTxCallable.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/callable/ContractTxCallable.java @@ -23,9 +23,6 @@ */ package io.nuls.contract.callable; -import io.nuls.base.data.CoinData; -import io.nuls.base.data.CoinTo; -import io.nuls.base.data.Transaction; import io.nuls.base.protocol.ProtocolGroupManager; import io.nuls.contract.config.ContractContext; import io.nuls.contract.helper.ContractConflictChecker; @@ -34,7 +31,6 @@ import io.nuls.contract.manager.ChainManager; import io.nuls.contract.manager.ContractTempBalanceManager; import io.nuls.contract.model.bo.*; -import io.nuls.contract.model.txdata.CallContractData; import io.nuls.contract.model.txdata.ContractData; import io.nuls.contract.service.ContractExecutor; import io.nuls.contract.util.ContractUtil; @@ -51,8 +47,6 @@ import java.util.Set; import java.util.concurrent.Callable; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; import static io.nuls.contract.util.ContractUtil.*; import static io.nuls.core.constant.TxType.*; diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/callable/ContractTxCallableV14.java b/module/nuls-cores/src/main/java/io/nuls/contract/callable/ContractTxCallableV14.java index 7fe02aeb0..5d52ab90f 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/callable/ContractTxCallableV14.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/callable/ContractTxCallableV14.java @@ -56,8 +56,8 @@ import java.util.Arrays; import java.util.List; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_MAIN_ASSET_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_CHAIN_ID; import static io.nuls.contract.util.ContractUtil.extractPublicKey; import static io.nuls.contract.util.ContractUtil.makeContractResult; import static io.nuls.core.constant.TxType.*; @@ -220,7 +220,7 @@ private void handleFailedContract(ContractResult contractResult) throws IOExcept for(CoinFrom from : fromList) { assetChainId = from.getAssetsChainId(); assetId = from.getAssetsId(); - if (CHAIN_ID != assetChainId || ASSET_ID != assetId) { + if (LOCAL_CHAIN_ID != assetChainId || LOCAL_MAIN_ASSET_ID != assetId) { // Multiple accounts transfer multiple assets to the contract, and if the contract fails to execute, the amount of transferred assets will be refunded ContractTransferTransaction tx = this.generateContractTransferTransaction(orginTxHash, contractAddress, from.getAddress(), from.getAmount(), assetChainId, assetId); contractResult.getContractTransferList().add(tx); @@ -234,7 +234,7 @@ private void handleFailedContract(ContractResult contractResult) throws IOExcept if (sender == null) { sender = contractData.getSender(); } - ContractTransferTransaction tx = this.generateContractTransferTransaction(orginTxHash, contractAddress, sender, value, CHAIN_ID, ASSET_ID); + ContractTransferTransaction tx = this.generateContractTransferTransaction(orginTxHash, contractAddress, sender, value, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID); contractResult.getContractTransferList().add(tx); } contractResult.setMergedTransferList(contractTransferHandler.contractTransfer2mergedTransfer(orginTx, contractResult.getContractTransferList())); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/callable/ContractTxCallableV8.java b/module/nuls-cores/src/main/java/io/nuls/contract/callable/ContractTxCallableV8.java index d8e00caf5..a3b0cd712 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/callable/ContractTxCallableV8.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/callable/ContractTxCallableV8.java @@ -56,8 +56,8 @@ import java.util.Arrays; import java.util.List; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_MAIN_ASSET_ID; import static io.nuls.contract.util.ContractUtil.extractPublicKey; import static io.nuls.contract.util.ContractUtil.makeContractResult; import static io.nuls.core.constant.TxType.*; @@ -213,7 +213,7 @@ private void handleFailedContract(ContractResult contractResult) throws IOExcept assetChainId = from.getAssetsChainId(); assetId = from.getAssetsId(); //assetKey = assetChainId + "_" + assetId; - if (CHAIN_ID != assetChainId || ASSET_ID != assetId) { + if (LOCAL_CHAIN_ID != assetChainId || LOCAL_MAIN_ASSET_ID != assetId) { //multyAssetMap.put(assetKey, from.getAddress()); // Multiple accounts transfer multiple assets to the contract, and if the contract fails to execute, the amount of transferred assets will be refunded ContractTransferTransaction tx = this.generateContractTransferTransaction(orginTxHash, contractAddress, from.getAddress(), from.getAmount(), assetChainId, assetId); @@ -228,7 +228,7 @@ private void handleFailedContract(ContractResult contractResult) throws IOExcept if (sender == null) { sender = contractData.getSender(); } - ContractTransferTransaction tx = this.generateContractTransferTransaction(orginTxHash, contractAddress, sender, value, CHAIN_ID, ASSET_ID); + ContractTransferTransaction tx = this.generateContractTransferTransaction(orginTxHash, contractAddress, sender, value, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID); contractResult.getContractTransferList().add(tx); } /*int toSize = toList.size(); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/config/ContractContext.java b/module/nuls-cores/src/main/java/io/nuls/contract/config/ContractContext.java index 99ab3d02b..8b2e2b51d 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/config/ContractContext.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/config/ContractContext.java @@ -34,6 +34,8 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -63,11 +65,11 @@ public class ContractContext { /** * Current ChainID */ - public static int CHAIN_ID = 1; + public static int LOCAL_CHAIN_ID = 1; /** * Current Chain AssetsID */ - public static int ASSET_ID = 1; + public static int LOCAL_MAIN_ASSET_ID = 1; /** * Token Cross Chain System Contract Address @@ -88,7 +90,9 @@ public class ContractContext { public static short PROTOCOL_16 = 16; public static short PROTOCOL_17 = 17; public static short PROTOCOL_19 = 19; + public static short PROTOCOL_20 = 20; private static final LoadingCache CONTRACT_INFO_CACHE; + public static Set FEE_ASSETS_SET = new HashSet<>(); private static ContractHelper contractHelper; static { @@ -99,7 +103,7 @@ public class ContractContext { .build(new CacheLoader() { @Override public ContractAddressInfoPo load(String contract) { - Result contractAddressInfoResult = contractHelper.getContractAddressInfo(CHAIN_ID, AddressTool.getAddress(contract)); + Result contractAddressInfoResult = contractHelper.getContractAddressInfo(LOCAL_CHAIN_ID, AddressTool.getAddress(contract)); ContractAddressInfoPo po = contractAddressInfoResult.getData(); return po; } diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractHelper.java b/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractHelper.java index b0b0edfe2..6140f4d7d 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractHelper.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractHelper.java @@ -62,8 +62,8 @@ import java.nio.charset.StandardCharsets; import java.util.*; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_MAIN_ASSET_ID; import static io.nuls.contract.constant.ContractConstant.*; import static io.nuls.contract.constant.ContractErrorCode.ADDRESS_ERROR; import static io.nuls.contract.util.ContractUtil.*; @@ -849,7 +849,7 @@ public ContractReturnGasTransaction makeReturnGasTx(List resultL Set> entries = returnMap.entrySet(); CoinTo returnCoin; for (Map.Entry entry : entries) { - returnCoin = new CoinTo(entry.getKey().getBytes(), CHAIN_ID, ASSET_ID, entry.getValue(), 0L); + returnCoin = new CoinTo(entry.getKey().getBytes(), LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID, entry.getValue(), 0L); toList.add(returnCoin); } ContractReturnGasTransaction tx = new ContractReturnGasTransaction(); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractNewTxHandler.java b/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractNewTxHandler.java index e8f680dd8..1f0a583ef 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractNewTxHandler.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractNewTxHandler.java @@ -42,8 +42,8 @@ import java.math.BigInteger; import java.util.*; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_MAIN_ASSET_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_CHAIN_ID; /** * @author: PierreLuo @@ -92,7 +92,7 @@ public boolean handleContractNewTx(int chainId, long blockTime, ContractWrapperT if (Arrays.equals(to.getAddress(), contractAddress)) { assetChainId = to.getAssetsChainId(); assetId = to.getAssetsId(); - mainAsset = assetChainId == CHAIN_ID && assetId == ASSET_ID; + mainAsset = assetChainId == LOCAL_CHAIN_ID && assetId == LOCAL_MAIN_ASSET_ID; if (!mainAsset) { // Initialize temporary balances for other assets tempBalanceManager.getBalance(contractAddress, assetChainId, assetId); @@ -105,8 +105,8 @@ public boolean handleContractNewTx(int chainId, long blockTime, ContractWrapperT BigInteger value = contractData.getValue(); if (value.compareTo(BigInteger.ZERO) > 0) { // initializationNULSTemporary balance of main assets - tempBalanceManager.getBalance(contractAddress, CHAIN_ID, ASSET_ID); - tempBalanceManager.addTempBalance(contractAddress, value, CHAIN_ID, ASSET_ID); + tempBalanceManager.getBalance(contractAddress, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID); + tempBalanceManager.addTempBalance(contractAddress, value, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID); } boolean isSuccess = true; @@ -173,14 +173,14 @@ public boolean handleContractNewTx(int chainId, long blockTime, ContractWrapperT if (!isSuccess) { // RollBACK - Deducting the amount transferred when calling the contract if (value.compareTo(BigInteger.ZERO) > 0) { - tempBalanceManager.minusTempBalance(contractAddress, value, CHAIN_ID, ASSET_ID); + tempBalanceManager.minusTempBalance(contractAddress, value, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID); } if (toList != null && !toList.isEmpty()) { for (CoinTo to : toList) { if (Arrays.equals(to.getAddress(), contractAddress)) { assetChainId = to.getAssetsChainId(); assetId = to.getAssetsId(); - mainAsset = assetChainId == CHAIN_ID && assetId == ASSET_ID; + mainAsset = assetChainId == LOCAL_CHAIN_ID && assetId == LOCAL_MAIN_ASSET_ID; if (!mainAsset) { // RollBACK - Temporary balance after deducting other assets tempBalanceManager.minusTempBalance(contractAddress, to.getAmount(), assetChainId, assetId); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractTransferHandler.java b/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractTransferHandler.java index 88dd749b7..11605616e 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractTransferHandler.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractTransferHandler.java @@ -45,8 +45,8 @@ import java.math.BigInteger; import java.util.*; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_MAIN_ASSET_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_CHAIN_ID; import static io.nuls.contract.constant.ContractConstant.MININUM_TRANSFER_AMOUNT; import static io.nuls.contract.constant.ContractErrorCode.TOO_SMALL_AMOUNT; import static io.nuls.contract.util.ContractUtil.*; @@ -252,7 +252,7 @@ private Result verifyTransfer(List transfers) { return getSuccess(); } for (ProgramTransfer transfer : transfers) { - if (transfer.getAssetChainId() == CHAIN_ID && transfer.getAssetId() == ASSET_ID && transfer.getValue().compareTo(MININUM_TRANSFER_AMOUNT) < 0) { + if (transfer.getAssetChainId() == LOCAL_CHAIN_ID && transfer.getAssetId() == LOCAL_MAIN_ASSET_ID && transfer.getValue().compareTo(MININUM_TRANSFER_AMOUNT) < 0) { return Result.getFailed(TOO_SMALL_AMOUNT); } } @@ -353,7 +353,7 @@ public List contractMultyAssetTransfer2mergedT CoinFrom coinFrom = coinData.getFrom().get(0); int assetChainId = coinFrom.getAssetsChainId(); int assetId = coinFrom.getAssetsId(); - if (CHAIN_ID != assetChainId || ASSET_ID != assetId) { + if (LOCAL_CHAIN_ID != assetChainId || LOCAL_MAIN_ASSET_ID != assetId) { resultList.add(this.transformMultyAssetMergedTransfer(tx.getHash(), transfer)); } } @@ -367,7 +367,7 @@ public List contractTransfer2mergedTransfer(Transaction CoinFrom coinFrom = coinData.getFrom().get(0); int assetChainId = coinFrom.getAssetsChainId(); int assetId = coinFrom.getAssetsId(); - if (CHAIN_ID == assetChainId && ASSET_ID == assetId) { + if (LOCAL_CHAIN_ID == assetChainId && LOCAL_MAIN_ASSET_ID == assetId) { resultList.add(this.transformMergedTransfer(tx.getHash(), transfer)); } } diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractTxHelper.java b/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractTxHelper.java index e1eb18469..ffda584dc 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractTxHelper.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/helper/ContractTxHelper.java @@ -29,7 +29,9 @@ import io.nuls.base.data.*; import io.nuls.contract.constant.ContractConstant; import io.nuls.contract.constant.ContractErrorCode; +import io.nuls.contract.manager.ChainManager; import io.nuls.contract.manager.ContractTxValidatorManager; +import io.nuls.contract.model.bo.Chain; import io.nuls.contract.model.bo.ContractBalance; import io.nuls.contract.model.bo.ContractResult; import io.nuls.contract.model.dto.AccountAmountDto; @@ -64,8 +66,8 @@ import java.util.Set; import java.util.stream.Collectors; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_MAIN_ASSET_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_CHAIN_ID; import static io.nuls.contract.constant.ContractConstant.MAX_GASLIMIT; import static io.nuls.contract.constant.ContractConstant.UNLOCKED_TX; import static io.nuls.contract.constant.ContractErrorCode.*; @@ -111,7 +113,7 @@ public Result makeCreateTx(int chainId, String sender } public Result newCreateTx(int chainId, String sender, byte[] senderBytes, byte[] contractAddressBytes, String alias, Long gasLimit, Long price, - byte[] contractCode, String[][] args, String remark) { + byte[] contractCode, String[][] args, String remark) { try { BigInteger value = BigInteger.ZERO; @@ -232,8 +234,8 @@ public Result makeCoinData(int chainId, String sender, byte[] senderBytes, byte[ BigInteger imputedValue = BigInteger.valueOf(LongUtils.mul(gasUsed, price)); // Total expenses BigInteger totalValue = imputedValue; - int assetChainId = CHAIN_ID; - int assetId = ASSET_ID; + int assetChainId = LOCAL_CHAIN_ID; + int assetId = LOCAL_MAIN_ASSET_ID; totalValue = totalValue.add(value); if (value.compareTo(BigInteger.ZERO) > 0) { coinData.addTo(new CoinTo(contractAddress, assetChainId, assetId, value)); @@ -267,11 +269,11 @@ public Result makeCoinData(int chainId, String sender, byte[] senderBytes, byte[ } } } - - BigInteger fee = TransactionFeeCalculator.getNormalUnsignedTxFee(txSize + calcSize(txData) + calcSize(coinData)); + Chain chain = contractHelper.getChain(chainId); + BigInteger fee = TransactionFeeCalculator.getNormalUnsignedTxFee(txSize + calcSize(txData) + calcSize(coinData), chain.getConfig().getFeeUnit(assetChainId, assetId), chain.getConfig().getFeeCoefficient(assetChainId, assetId)); totalValue = totalValue.add(fee); if (senderBalance.getBalance().compareTo(totalValue) < 0) { - Log.error("Insufficient balance, asset: {}-{}", CHAIN_ID, ASSET_ID); + Log.error("Insufficient balance, asset: {}-{}", LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID); return Result.getFailed(INSUFFICIENT_BALANCE); } coinFrom.setAmount(totalValue); @@ -625,7 +627,7 @@ public Result validateDelete(int chainId, byte[] senderBytes, String contractAdd return Result.getFailed(ContractErrorCode.CONTRACT_DELETE_CREATER); } - ContractBalance balance = contractHelper.getRealBalance(chainId, CHAIN_ID, ASSET_ID, contractAddress); + ContractBalance balance = contractHelper.getRealBalance(chainId, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID, contractAddress); BigInteger totalBalance = balance.getTotal(); if (totalBalance.compareTo(BigInteger.ZERO) != 0) { return Result.getFailed(ContractErrorCode.CONTRACT_DELETE_BALANCE); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/manager/ContractTxValidatorManager.java b/module/nuls-cores/src/main/java/io/nuls/contract/manager/ContractTxValidatorManager.java index 5d25c13d8..dc770405e 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/manager/ContractTxValidatorManager.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/manager/ContractTxValidatorManager.java @@ -55,6 +55,9 @@ public Result createValidator(int chainId, CreateContractTransaction tx) throws } public Result callValidator(int chainId, CallContractTransaction tx) throws NulsException { + if (ProtocolGroupManager.getCurrentVersion(chainId) >= ContractContext.PROTOCOL_20) { + return callContractTxValidator.validateV20(chainId, tx); + } if (ProtocolGroupManager.getCurrentVersion(chainId) >= ContractContext.PROTOCOL_14) { return callContractTxValidator.validateV14(chainId, tx); } diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/service/impl/ResultHandlerImpl.java b/module/nuls-cores/src/main/java/io/nuls/contract/service/impl/ResultHandlerImpl.java index 1dd00a792..adf4a88e3 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/service/impl/ResultHandlerImpl.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/service/impl/ResultHandlerImpl.java @@ -49,8 +49,8 @@ import java.util.*; import java.util.stream.Collectors; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_MAIN_ASSET_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_CHAIN_ID; import static io.nuls.core.constant.TxType.CALL_CONTRACT; /** @@ -110,7 +110,7 @@ private void handleFailedContract(int chainId, AnalyzerResult analyzerResult, lo ContractTransferData txData = new ContractTransferData(orginTx.getHash(), contractAddress); CoinData coinData = new CoinData(); - ContractBalance balance = tempBalanceManager.getBalance(contractAddress, CHAIN_ID, ASSET_ID).getData(); + ContractBalance balance = tempBalanceManager.getBalance(contractAddress, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID).getData(); byte[] nonceBytes = RPCUtil.decode(balance.getNonce()); CoinFrom coinFrom = new CoinFrom(contractAddress, chainId, assetsId, value, nonceBytes, (byte) 0); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/tx/v20/CallContractProcessorV20.java b/module/nuls-cores/src/main/java/io/nuls/contract/tx/v20/CallContractProcessorV20.java new file mode 100644 index 000000000..e00203263 --- /dev/null +++ b/module/nuls-cores/src/main/java/io/nuls/contract/tx/v20/CallContractProcessorV20.java @@ -0,0 +1,211 @@ +package io.nuls.contract.tx.v20; + +import io.nuls.base.basic.AddressTool; +import io.nuls.base.data.BlockHeader; +import io.nuls.base.data.Transaction; +import io.nuls.base.protocol.TransactionProcessor; +import io.nuls.contract.enums.TokenTypeStatus; +import io.nuls.contract.helper.ContractHelper; +import io.nuls.contract.manager.ChainManager; +import io.nuls.contract.model.bo.BatchInfoV8; +import io.nuls.contract.model.bo.ContractInternalCreate; +import io.nuls.contract.model.bo.ContractResult; +import io.nuls.contract.model.bo.ContractWrapperTransaction; +import io.nuls.contract.model.dto.CallContractDataDto; +import io.nuls.contract.model.dto.ContractResultDto; +import io.nuls.contract.model.po.ContractAddressInfoPo; +import io.nuls.contract.model.tx.CallContractTransaction; +import io.nuls.contract.model.txdata.CallContractData; +import io.nuls.contract.model.txdata.ContractData; +import io.nuls.contract.processor.CallContractTxProcessor; +import io.nuls.contract.service.ContractService; +import io.nuls.contract.util.ContractUtil; +import io.nuls.contract.util.Log; +import io.nuls.contract.validator.CallContractTxValidator; +import io.nuls.core.basic.Result; +import io.nuls.core.constant.TxType; +import io.nuls.core.core.annotation.Autowired; +import io.nuls.core.core.annotation.Component; +import io.nuls.core.exception.NulsException; +import io.nuls.core.parse.JSONUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static io.nuls.contract.util.ContractUtil.getFailed; + +// add by pierre at 2023/4/26 +@Component("CallContractProcessorV20") +public class CallContractProcessorV20 implements TransactionProcessor { + + @Autowired + private CallContractTxProcessor callContractTxProcessor; + @Autowired + private CallContractTxValidator callContractTxValidator; + @Autowired + private ContractHelper contractHelper; + @Autowired + private ChainManager chainManager; + @Autowired + private ContractService contractService; + + @Override + public int getType() { + return TxType.CALL_CONTRACT; + } + + @Override + public Map validate(int chainId, List txs, Map> txMap, BlockHeader blockHeader) { + ChainManager.chainHandle(chainId); + Map result = new HashMap<>(); + List errorList = new ArrayList<>(); + result.put("txList", errorList); + String errorCode = null; + CallContractTransaction callTx; + for(Transaction tx : txs) { + callTx = new CallContractTransaction(); + callTx.copyTx(tx); + try { + Result validate = callContractTxValidator.validateV20(chainId, callTx); + if(validate.isFailed()) { + errorCode = validate.getErrorCode().getCode(); + errorList.add(tx); + } + } catch (NulsException e) { + Log.error(e); + errorCode = e.getErrorCode().getCode(); + errorList.add(tx); + } + } + result.put("errorCode", errorCode); + return result; + } + + @Override + public boolean commit(int chainId, List txs, BlockHeader header) { + try { + BatchInfoV8 batchInfo = contractHelper.getChain(chainId).getBatchInfoV8(); + if (batchInfo != null) { + Map contractResultMap = batchInfo.getContractResultMap(); + ContractResult contractResult; + ContractWrapperTransaction wrapperTx; + String txHash; + for (Transaction tx : txs) { + txHash = tx.getHash().toString(); + contractResult = contractResultMap.get(txHash); + if (contractResult == null) { + Log.warn("empty contract result with txHash: {}, txType: {}", txHash, tx.getType()); + continue; + } + wrapperTx = contractResult.getTx(); + wrapperTx.setContractResult(contractResult); + this.onCommit(chainId, wrapperTx); + } + } + + return true; + } catch (Exception e) { + Log.error(e); + return false; + } + } + + @Override + public boolean rollback(int chainId, List txs, BlockHeader blockHeader) { + try { + ChainManager.chainHandle(chainId); + CallContractData call; + for (Transaction tx : txs) { + if (tx.getType() == TxType.CROSS_CHAIN) { + call = ContractUtil.parseCrossChainTx(tx, chainManager); + if (call == null) { + continue; + } + } else { + call = new CallContractData(); + call.parse(tx.getTxData(), 0); + } + this.onRollback(chainId, new ContractWrapperTransaction(tx, call)); + } + return true; + } catch (NulsException e) { + Log.error(e); + return false; + } + } + + private Result onCommit(int chainId, ContractWrapperTransaction tx) { + try { + BlockHeader blockHeader = contractHelper.getBatchInfoCurrentBlockHeaderV8(chainId); + byte[] stateRoot = blockHeader.getStateRoot(); + long blockHeight = blockHeader.getHeight(); + ContractResult contractResult = tx.getContractResult(); + contractResult.setBlockHeight(blockHeight); + + // 保存代币交易 + ContractData callContractData = tx.getContractData(); + byte[] contractAddress = callContractData.getContractAddress(); + String contractAddressStr = AddressTool.getStringAddressByBytes(contractAddress); + + Result contractAddressInfoPoResult = contractHelper.getContractAddressInfo(chainId, contractAddress); + ContractAddressInfoPo contractAddressInfoPo = contractAddressInfoPoResult.getData(); + contractResult.setNrc20(contractAddressInfoPo.isNrc20()); + tx.setBlockHeight(blockHeight); + + Map infoPoMap = new HashMap<>(); + infoPoMap.put(contractAddressStr, contractAddressInfoPo); + // 处理内部创建合约 + List internalCreates = contractResult.getInternalCreates(); + if (internalCreates != null && !internalCreates.isEmpty()) { + for (ContractInternalCreate internalCreate : internalCreates) { + Result result = contractHelper.onCommitForCreateV16(chainId, blockHeader, internalCreate, tx.getHash(), tx.getTime(), internalCreate.getContractAddress(), + internalCreate.getSender(), contractHelper.getContractCode(chainId, stateRoot, internalCreate.getCodeCopyBy()), "internal_create", infoPoMap); + if (result.isFailed()) { + return result; + } + } + } + // 保存合约执行结果 + return contractService.saveContractExecuteResult(chainId, tx.getHash(), contractResult); + } catch (Exception e) { + Log.error("save call contract tx error.", e); + return getFailed(); + } + } + + private Result onRollback(int chainId, ContractWrapperTransaction tx) { + try { + // 回滚代币转账交易 + ContractResult contractResult = tx.getContractResult(); + if (contractResult == null) { + contractResult = contractService.getContractExecuteResult(chainId, tx.getHash()); + } + if (contractResult == null) { + return ContractUtil.getSuccess(); + } + try { + CallContractData contractData = (CallContractData) tx.getContractData(); + Log.info("rollback call tx, contract data is {}, result is {}", JSONUtils.obj2json(new CallContractDataDto(contractData)), JSONUtils.obj2json(new ContractResultDto(chainId, contractResult, contractData.getGasLimit()))); + } catch (Exception e) { + Log.warn("failed to trace call rollback log, error is {}", e.getMessage()); + } + // 处理内部创建合约 + List internalCreates = contractResult.getInternalCreates(); + if (internalCreates != null && !internalCreates.isEmpty()) { + for (ContractInternalCreate internalCreate : internalCreates) { + Result result = contractHelper.onRollbackForCreateV16(chainId, internalCreate.getContractAddress(), internalCreate.getTokenType() == TokenTypeStatus.NRC20.status()); + if (result.isFailed()) { + return result; + } + } + } + // 删除合约执行结果 + return contractService.deleteContractExecuteResult(chainId, tx.getHash()); + } catch (Exception e) { + Log.error("rollback call contract tx error.", e); + return getFailed(); + } + } +} diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/tx/v20/CreateContractProcessorV20.java b/module/nuls-cores/src/main/java/io/nuls/contract/tx/v20/CreateContractProcessorV20.java new file mode 100644 index 000000000..ac398f864 --- /dev/null +++ b/module/nuls-cores/src/main/java/io/nuls/contract/tx/v20/CreateContractProcessorV20.java @@ -0,0 +1,186 @@ +package io.nuls.contract.tx.v20; + +import io.nuls.base.data.BlockHeader; +import io.nuls.base.data.Transaction; +import io.nuls.base.protocol.TransactionProcessor; +import io.nuls.contract.helper.ContractHelper; +import io.nuls.contract.manager.ChainManager; +import io.nuls.contract.model.bo.BatchInfoV8; +import io.nuls.contract.model.bo.ContractCreate; +import io.nuls.contract.model.bo.ContractResult; +import io.nuls.contract.model.bo.ContractWrapperTransaction; +import io.nuls.contract.model.dto.ContractResultDto; +import io.nuls.contract.model.dto.CreateContractDataDto; +import io.nuls.contract.model.po.ContractAddressInfoPo; +import io.nuls.contract.model.tx.CreateContractTransaction; +import io.nuls.contract.model.txdata.ContractData; +import io.nuls.contract.model.txdata.CreateContractData; +import io.nuls.contract.processor.CreateContractTxProcessor; +import io.nuls.contract.service.ContractService; +import io.nuls.contract.util.Log; +import io.nuls.contract.validator.CreateContractTxValidator; +import io.nuls.core.basic.Result; +import io.nuls.core.constant.TxType; +import io.nuls.core.core.annotation.Autowired; +import io.nuls.core.core.annotation.Component; +import io.nuls.core.exception.NulsException; +import io.nuls.core.parse.JSONUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static io.nuls.contract.util.ContractUtil.getSuccess; + +// add by pierre at 2023/4/26 +@Component("CreateContractProcessorV20") +public class CreateContractProcessorV20 implements TransactionProcessor { + + @Autowired + private CreateContractTxProcessor createContractTxProcessor; + @Autowired + private CreateContractTxValidator createContractTxValidator; + @Autowired + private ContractHelper contractHelper; + @Autowired + private ContractService contractService; + + @Override + public int getType() { + return TxType.CREATE_CONTRACT; + } + + @Override + public Map validate(int chainId, List txs, Map> txMap, BlockHeader blockHeader) { + ChainManager.chainHandle(chainId); + Map result = new HashMap<>(); + List errorList = new ArrayList<>(); + result.put("txList", errorList); + String errorCode = null; + CreateContractTransaction createTx; + for(Transaction tx : txs) { + createTx = new CreateContractTransaction(); + createTx.copyTx(tx); + try { + Result validate = createContractTxValidator.validate(chainId, createTx); + if(validate.isFailed()) { + errorCode = validate.getErrorCode().getCode(); + errorList.add(tx); + } + } catch (NulsException e) { + Log.error(e); + errorCode = e.getErrorCode().getCode(); + errorList.add(tx); + } + } + result.put("errorCode", errorCode); + return result; + } + + @Override + public boolean commit(int chainId, List txs, BlockHeader header) { + try { + BatchInfoV8 batchInfo = contractHelper.getChain(chainId).getBatchInfoV8(); + if (batchInfo != null) { + Map contractResultMap = batchInfo.getContractResultMap(); + ContractResult contractResult; + ContractWrapperTransaction wrapperTx; + String txHash; + for (Transaction tx : txs) { + txHash = tx.getHash().toString(); + contractResult = contractResultMap.get(txHash); + if (contractResult == null) { + Log.warn("empty contract result with txHash: {}", txHash); + continue; + } + wrapperTx = contractResult.getTx(); + wrapperTx.setContractResult(contractResult); + this.onCommit(chainId, wrapperTx); + } + } + + return true; + } catch (Exception e) { + Log.error(e); + return false; + } + } + + @Override + public boolean rollback(int chainId, List txs, BlockHeader blockHeader) { + try { + ChainManager.chainHandle(chainId); + CreateContractData create; + for (Transaction tx : txs) { + create = new CreateContractData(); + create.parse(tx.getTxData(), 0); + this.onRollback(chainId, new ContractWrapperTransaction(tx, create)); + } + return true; + } catch (Exception e) { + Log.error(e); + return false; + } + } + + private Result onCommit(int chainId, ContractWrapperTransaction tx) throws Exception { + BlockHeader blockHeader = contractHelper.getBatchInfoCurrentBlockHeaderV8(chainId); + long blockHeight = blockHeader.getHeight(); + tx.setBlockHeight(blockHeight); + ContractResult contractResult = tx.getContractResult(); + contractResult.setBlockHeight(blockHeight); + Result saveContractExecuteResult = contractService.saveContractExecuteResult(chainId, tx.getHash(), contractResult); + if (saveContractExecuteResult.isFailed()) { + return saveContractExecuteResult; + } + // 执行失败的合约直接返回 + if (!contractResult.isSuccess()) { + return getSuccess(); + } + CreateContractData txData = (CreateContractData) tx.getContractData(); + byte[] contractAddress = txData.getContractAddress(); + byte[] sender = txData.getSender(); + String alias = txData.getAlias(); + byte[] code = txData.getCode(); + byte[] newestStateRoot = blockHeader.getStateRoot(); + + ContractCreate create = new ContractCreate(); + create.setTokenType(contractResult.getTokenType()); + create.setTokenName(contractResult.getTokenName()); + create.setTokenSymbol(contractResult.getTokenSymbol()); + create.setTokenDecimals(contractResult.getTokenDecimals()); + create.setTokenTotalSupply(contractResult.getTokenTotalSupply()); + create.setAcceptDirectTransfer(contractResult.isAcceptDirectTransfer()); + Map infoPoMap = new HashMap<>(); + Result result = contractHelper.onCommitForCreateV16(chainId, blockHeader, create, tx.getHash(), tx.getTime(), contractAddress, sender, code, alias, infoPoMap); + if (result.isFailed()) { + return result; + } + return result; + } + + private Result onRollback(int chainId, ContractWrapperTransaction tx) throws Exception { + ContractData txData = tx.getContractData(); + byte[] contractAddress = txData.getContractAddress(); + // 回滚代币转账交易 + ContractResult contractResult = tx.getContractResult(); + if (contractResult == null) { + contractResult = contractService.getContractExecuteResult(chainId, tx.getHash()); + } + if (contractResult == null) { + return Result.getSuccess(null); + } + try { + CreateContractData contractData = (CreateContractData) tx.getContractData(); + Log.info("rollback create tx, contract data is {}, result is {}", JSONUtils.obj2json(new CreateContractDataDto(contractData)), JSONUtils.obj2json(new ContractResultDto(chainId, contractResult, contractData.getGasLimit()))); + } catch (Exception e) { + Log.warn("failed to trace create rollback log, error is {}", e.getMessage()); + } + Result result = contractHelper.onRollbackForCreateV16(chainId, contractAddress, contractResult.isNrc20()); + if (result.isFailed()) { + return result; + } + return contractService.deleteContractExecuteResult(chainId, tx.getHash()); + } +} diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/util/ContractUtil.java b/module/nuls-cores/src/main/java/io/nuls/contract/util/ContractUtil.java index 8aee8010a..babdba8a5 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/util/ContractUtil.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/util/ContractUtil.java @@ -67,8 +67,8 @@ import java.util.*; import java.util.stream.Collectors; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_MAIN_ASSET_ID; import static io.nuls.contract.constant.ContractConstant.*; import static io.nuls.contract.constant.ContractErrorCode.FAILED; import static io.nuls.core.constant.TxType.*; @@ -952,7 +952,7 @@ public static List extractMultyAssetInfoFromCallTransact } List list = null; for (CoinTo to : toList) { - if (to.getAssetsChainId() == CHAIN_ID && to.getAssetsId() == ASSET_ID) { + if (to.getAssetsChainId() == LOCAL_CHAIN_ID && to.getAssetsId() == LOCAL_MAIN_ASSET_ID) { continue; } if (list == null) { diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/validator/CallContractTxValidator.java b/module/nuls-cores/src/main/java/io/nuls/contract/validator/CallContractTxValidator.java index cc4743385..2f2a0c72a 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/validator/CallContractTxValidator.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/validator/CallContractTxValidator.java @@ -31,6 +31,7 @@ import io.nuls.base.data.CoinFrom; import io.nuls.base.data.CoinTo; import io.nuls.base.signture.SignatureUtil; +import io.nuls.common.NCUtils; import io.nuls.contract.helper.ContractHelper; import io.nuls.contract.model.bo.Chain; import io.nuls.contract.model.tx.CallContractTransaction; @@ -48,8 +49,7 @@ import java.math.BigInteger; import java.util.*; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.*; import static io.nuls.contract.constant.ContractConstant.MININUM_TRANSFER_AMOUNT; import static io.nuls.contract.constant.ContractErrorCode.*; import static io.nuls.contract.util.ContractUtil.getSuccess; @@ -74,12 +74,12 @@ public Result validate(int chainId, CallContractTransaction tx) throws NulsExcep boolean existSender = false; Chain chain = contractHelper.getChain(chainId); int assetsId = chain.getConfig().getAssetId(); - for(CoinFrom from : fromList) { - if(from.getAssetsChainId() != chainId || from.getAssetsId() != assetsId) { + for (CoinFrom from : fromList) { + if (from.getAssetsChainId() != chainId || from.getAssetsId() != assetsId) { Log.error("contract call error: The chain id or assets id of coin from is error."); return Result.getFailed(CONTRACT_COIN_ASSETS_ERROR); } - if(!existSender && Arrays.equals(from.getAddress(), sender)) { + if (!existSender && Arrays.equals(from.getAddress(), sender)) { existSender = true; } } @@ -107,7 +107,7 @@ public Result validate(int chainId, CallContractTransaction tx) throws NulsExcep BigInteger contractReceivedValue = BigInteger.ZERO; for (CoinTo coin : toList) { - if(coin.getAssetsChainId() != chainId || coin.getAssetsId() != assetsId) { + if (coin.getAssetsChainId() != chainId || coin.getAssetsId() != assetsId) { Log.error("contract call error: The chain id or assets id of coin to is error."); return Result.getFailed(CONTRACT_COIN_ASSETS_ERROR); } @@ -137,7 +137,8 @@ public Result validate(int chainId, CallContractTransaction tx) throws NulsExcep } BigInteger realFee = tx.getFee(); - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(tx.size()).add(BigInteger.valueOf(txData.getGasLimit()).multiply(BigInteger.valueOf(txData.getPrice()))); + + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(tx.size(), chain.getConfig().getFeeUnit(chainId, assetsId)).add(BigInteger.valueOf(txData.getGasLimit()).multiply(BigInteger.valueOf(txData.getPrice()))); if (realFee.compareTo(fee) >= 0) { return getSuccess(); } else { @@ -176,11 +177,11 @@ public Result validateV8(int chainId, CallContractTransaction tx) throws NulsExc int assetChainId, assetId; String assetKey; BigInteger nulsValue = BigInteger.ZERO; - for(CoinFrom from : fromList) { + for (CoinFrom from : fromList) { assetChainId = from.getAssetsChainId(); assetId = from.getAssetsId(); assetKey = assetChainId + "_" + assetId; - if (CHAIN_ID == assetChainId && ASSET_ID == assetId) { + if (LOCAL_CHAIN_ID == assetChainId && LOCAL_MAIN_ASSET_ID == assetId) { nulsValue = nulsValue.add(from.getAmount()); } else { multyAssetKeys.add(assetKey); @@ -205,7 +206,7 @@ public Result validateV8(int chainId, CallContractTransaction tx) throws NulsExc } assetChainId = coin.getAssetsChainId(); assetId = coin.getAssetsId(); - boolean mainAsset = assetChainId == CHAIN_ID && assetId == ASSET_ID; + boolean mainAsset = assetChainId == LOCAL_CHAIN_ID && assetId == LOCAL_MAIN_ASSET_ID; if (!mainAsset) { if (coin.getAmount().compareTo(BigInteger.ZERO) == 0) { Log.error("contract call error: Transfer amount cannot be zero."); @@ -231,7 +232,7 @@ public Result validateV8(int chainId, CallContractTransaction tx) throws NulsExc for (String multyAssetKey : multyAssetKeys) { assetKeyFrom = multyAssetMap.get(multyAssetKey + "from"); assetKeyTo = multyAssetMap.get(multyAssetKey + "to"); - if(null == assetKeyFrom){ + if (null == assetKeyFrom) { Log.error("contract call error: Illegal coinFrom in the contract."); return Result.getFailed(CONTRACT_COIN_FROM_ERROR); } @@ -259,8 +260,9 @@ public Result validateV8(int chainId, CallContractTransaction tx) throws NulsExc } } - BigInteger realFee = coinData.getFeeByAsset(CHAIN_ID, ASSET_ID); - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(tx.size()).add(BigInteger.valueOf(txData.getGasLimit()).multiply(BigInteger.valueOf(txData.getPrice()))); + BigInteger realFee = coinData.getFeeByAsset(LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID); + Chain chain = contractHelper.getChain(chainId); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(tx.size(), chain.getConfig().getFeeUnit(LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID)).add(BigInteger.valueOf(txData.getGasLimit()).multiply(BigInteger.valueOf(txData.getPrice()))); if (realFee.compareTo(fee) >= 0) { return getSuccess(); } else { @@ -302,11 +304,11 @@ public Result validateV13(int chainId, CallContractTransaction tx) throws NulsEx int assetChainId, assetId; String assetKey; BigInteger nulsValue = BigInteger.ZERO; - for(CoinFrom from : fromList) { + for (CoinFrom from : fromList) { assetChainId = from.getAssetsChainId(); assetId = from.getAssetsId(); assetKey = assetChainId + "_" + assetId; - if (CHAIN_ID == assetChainId && ASSET_ID == assetId) { + if (LOCAL_CHAIN_ID == assetChainId && LOCAL_MAIN_ASSET_ID == assetId) { nulsValue = nulsValue.add(from.getAmount()); } else { multyAssetKeys.add(assetKey); @@ -330,7 +332,7 @@ public Result validateV13(int chainId, CallContractTransaction tx) throws NulsEx boolean isContractReceiver = Arrays.equals(to, contractAddress); assetChainId = coin.getAssetsChainId(); assetId = coin.getAssetsId(); - boolean mainAsset = assetChainId == CHAIN_ID && assetId == ASSET_ID; + boolean mainAsset = assetChainId == LOCAL_CHAIN_ID && assetId == LOCAL_MAIN_ASSET_ID; if (!mainAsset) { if (coin.getAmount().compareTo(BigInteger.ZERO) == 0) { Log.error("contract call error: Transfer amount cannot be zero."); @@ -367,7 +369,7 @@ public Result validateV13(int chainId, CallContractTransaction tx) throws NulsEx for (String multyAssetKey : multyAssetKeys) { assetKeyFrom = multyAssetMap.get(multyAssetKey + "from"); assetKeyTo = multyAssetMap.get(multyAssetKey + "to"); - if(null == assetKeyFrom){ + if (null == assetKeyFrom) { Log.error("contract call error: Illegal coinFrom in the contract."); return Result.getFailed(CONTRACT_COIN_FROM_ERROR); } @@ -395,8 +397,9 @@ public Result validateV13(int chainId, CallContractTransaction tx) throws NulsEx } } - BigInteger realFee = coinData.getFeeByAsset(CHAIN_ID, ASSET_ID); - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(tx.size()).add(BigInteger.valueOf(txData.getGasLimit()).multiply(BigInteger.valueOf(txData.getPrice()))); + BigInteger realFee = coinData.getFeeByAsset(LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID); + Chain chain = contractHelper.getChain(chainId); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(tx.size(), chain.getConfig().getFeeUnit(LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID)).add(BigInteger.valueOf(txData.getGasLimit()).multiply(BigInteger.valueOf(txData.getPrice()))); if (realFee.compareTo(fee) >= 0) { return getSuccess(); } else { @@ -404,6 +407,7 @@ public Result validateV13(int chainId, CallContractTransaction tx) throws NulsEx return Result.getFailed(FEE_NOT_RIGHT); } } + /** * 1. New feature that supports multiple address signatures when calling contracts */ @@ -447,11 +451,11 @@ public Result validateV14(int chainId, CallContractTransaction tx) throws NulsEx int assetChainId, assetId; String assetKey; BigInteger nulsValue = BigInteger.ZERO; - for(CoinFrom from : fromList) { + for (CoinFrom from : fromList) { assetChainId = from.getAssetsChainId(); assetId = from.getAssetsId(); assetKey = assetChainId + "_" + assetId; - if (CHAIN_ID == assetChainId && ASSET_ID == assetId) { + if (LOCAL_CHAIN_ID == assetChainId && LOCAL_MAIN_ASSET_ID == assetId) { nulsValue = nulsValue.add(from.getAmount()); } else { multyAssetKeys.add(assetKey); @@ -475,7 +479,7 @@ public Result validateV14(int chainId, CallContractTransaction tx) throws NulsEx boolean isContractReceiver = Arrays.equals(to, contractAddress); assetChainId = coin.getAssetsChainId(); assetId = coin.getAssetsId(); - boolean mainAsset = assetChainId == CHAIN_ID && assetId == ASSET_ID; + boolean mainAsset = assetChainId == LOCAL_CHAIN_ID && assetId == LOCAL_MAIN_ASSET_ID; if (!mainAsset) { if (coin.getAmount().compareTo(BigInteger.ZERO) == 0) { Log.error("contract call error: Transfer amount cannot be zero."); @@ -512,7 +516,7 @@ public Result validateV14(int chainId, CallContractTransaction tx) throws NulsEx for (String multyAssetKey : multyAssetKeys) { assetKeyFrom = multyAssetMap.get(multyAssetKey + "from"); assetKeyTo = multyAssetMap.get(multyAssetKey + "to"); - if(null == assetKeyFrom){ + if (null == assetKeyFrom) { Log.error("contract call error: Illegal coinFrom in the contract."); return Result.getFailed(CONTRACT_COIN_FROM_ERROR); } @@ -540,8 +544,170 @@ public Result validateV14(int chainId, CallContractTransaction tx) throws NulsEx } } - BigInteger realFee = coinData.getFeeByAsset(CHAIN_ID, ASSET_ID); - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(tx.size()).add(BigInteger.valueOf(txData.getGasLimit()).multiply(BigInteger.valueOf(txData.getPrice()))); + BigInteger realFee = coinData.getFeeByAsset(LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID); + + Chain chain = contractHelper.getChain(chainId); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(tx.size(), chain.getConfig().getFeeUnit(LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID)).add(BigInteger.valueOf(txData.getGasLimit()).multiply(BigInteger.valueOf(txData.getPrice()))); + if (realFee.compareTo(fee) >= 0) { + return getSuccess(); + } else { + Log.error("contract call error: The contract transaction fee is not right."); + return Result.getFailed(FEE_NOT_RIGHT); + } + } + + + /** + * 1. 新增功能,调用合约时支持多签地址 + */ + public Result validateV20(int chainId, CallContractTransaction tx) throws NulsException { + + CoinData coinData = tx.getCoinDataInstance(); + List fromList = coinData.getFrom(); + List toList = coinData.getTo(); + CallContractData txData = tx.getTxDataObj(); + byte[] sender = txData.getSender(); + + if (fromList == null || fromList.isEmpty()) { + Log.error("contract call error: The contract caller is not the transaction signer.[0]"); + return Result.getFailed(CONTRACT_CALLER_SIGN_ERROR); + } + boolean existSender = false; + for (CoinFrom from : fromList) { + if (Arrays.equals(from.getAddress(), sender)) { + existSender = true; + break; + } + } + if (!existSender) { + Log.error("contract call error: The contract caller is not the transaction signer.[1]"); + return Result.getFailed(CONTRACT_CALLER_SIGN_ERROR); + } + if (!ContractUtil.checkGasLimit(txData.getGasLimit())) { + Log.error("contract call error: The value of gas limit ranges from 0 to 10,000,000."); + return Result.getFailed(CONTRACT_GAS_LIMIT_ERROR); + } + + byte[] contractAddress = txData.getContractAddress(); + + if (!ContractLedgerUtil.isExistContractAddress(chainId, contractAddress)) { + Log.error("contract call error: The contract does not exist."); + return Result.getFailed(CONTRACT_ADDRESS_NOT_EXIST); + } + + Map multyAssetMap = new HashMap<>(); + Set multyAssetKeys = new HashSet<>(); + int assetChainId, assetId; + String assetKey; + BigInteger nulsValue = BigInteger.ZERO; + for (CoinFrom from : fromList) { + assetChainId = from.getAssetsChainId(); + assetId = from.getAssetsId(); + assetKey = assetChainId + "_" + assetId; + if (LOCAL_CHAIN_ID == assetChainId && LOCAL_MAIN_ASSET_ID == assetId) { + nulsValue = nulsValue.add(from.getAmount()); + } else { + multyAssetKeys.add(assetKey); + BigInteger multyAssetValue = multyAssetMap.getOrDefault(assetKey + "from", BigInteger.ZERO); + multyAssetMap.put(assetKey + "from", multyAssetValue.add(from.getAmount())); + } + } + + int toSize = toList.size(); + BigInteger transferNulsToContractValue = txData.getValue(); + BigInteger contractReceivedNulsValue = BigInteger.ZERO; + // The caller transfers funds to other accounts while calling the contract + BigInteger transferNulsToOtherAccountValue = BigInteger.ZERO; + if (toSize > 0) { + for (CoinTo coin : toList) { + if (coin.getLockTime() != 0) { + Log.error("contract call error: Transfer amount cannot be locked."); + return Result.getFailed(AMOUNT_LOCK_ERROR); + } + byte[] to = coin.getAddress(); + boolean isContractReceiver = Arrays.equals(to, contractAddress); + assetChainId = coin.getAssetsChainId(); + assetId = coin.getAssetsId(); + boolean mainAsset = assetChainId == LOCAL_CHAIN_ID && assetId == LOCAL_MAIN_ASSET_ID; + if (!mainAsset) { + if (coin.getAmount().compareTo(BigInteger.ZERO) == 0) { + Log.error("contract call error: Transfer amount cannot be zero."); + return Result.getFailed(TOO_SMALL_AMOUNT); + } + assetKey = assetChainId + "_" + assetId; + multyAssetKeys.add(assetKey); + BigInteger multyAssetValue = multyAssetMap.getOrDefault(assetKey + "to", BigInteger.ZERO); + multyAssetMap.put(assetKey + "to", multyAssetValue.add(coin.getAmount())); + continue; + } + if (coin.getAmount().compareTo(MININUM_TRANSFER_AMOUNT) < 0) { + Log.error("contract call error: The amount of the transfer is too small."); + return Result.getFailed(TOO_SMALL_AMOUNT); + } + if (isContractReceiver) { + contractReceivedNulsValue = contractReceivedNulsValue.add(coin.getAmount()); + } else { + // inspecttoIs the address on the account whitelist + String toStr = AddressTool.getStringAddressByBytes(to); + boolean whiteAddress = AccountCall.validationWhitelistForTransferOnContractCall(chainId, toStr); + if (!whiteAddress) { + Log.error("contract call error: The receiver is not a whitelisted address."); + return Result.getFailed(CONTRACT_COIN_TO_ERROR); + } + transferNulsToOtherAccountValue = transferNulsToOtherAccountValue.add(coin.getAmount()); + } + } + + } + + // Other asset verification + BigInteger assetKeyFrom, assetKeyTo; + for (String multyAssetKey : multyAssetKeys) { + assetKeyFrom = multyAssetMap.get(multyAssetKey + "from"); + assetKeyTo = multyAssetMap.get(multyAssetKey + "to"); + if (null == assetKeyFrom) { + Log.error("contract call error: Illegal coinFrom in the contract."); + return Result.getFailed(CONTRACT_COIN_FROM_ERROR); + } + if (FEE_ASSETS_SET.contains(multyAssetKey.replace("_", "-"))) { + continue; + } + if (null == assetKeyTo) { + Log.error("contract call error: Illegal coinTo in the contract."); + return Result.getFailed(CONTRACT_COIN_TO_ERROR); + } + if (!BigIntegerUtils.isEqual(assetKeyFrom, assetKeyTo)) { + Log.error("contract call error: The amount of coin data is error."); + return Result.getFailed(CONTRACT_COIN_ASSETS_ERROR); + } + } + + // Main asset verification + if (contractReceivedNulsValue.compareTo(transferNulsToContractValue) < 0) { + Log.error("contract call error: Insufficient balance of nuls to transfer to the contract address."); + return Result.getFailed(INSUFFICIENT_BALANCE_TO_CONTRACT); + } + + if (transferNulsToContractValue.compareTo(BigInteger.ZERO) > 0) { + // Handling fee accounts can also be used to transfer assets to contracts + if (nulsValue.compareTo(transferNulsToContractValue.add(transferNulsToOtherAccountValue)) < 0) { + Log.error("contract call error: Insufficient balance to transfer to the contract address."); + return Result.getFailed(INSUFFICIENT_BALANCE_TO_CONTRACT); + } + } + + BigInteger realFee = BigInteger.ZERO; + int[] arr = new int[0]; + for (String key : FEE_ASSETS_SET) { + if (realFee.compareTo(BigInteger.ZERO) != 0) { + break; + } + arr = NCUtils.splitTokenId(key); + realFee = coinData.getFeeByAsset(arr[0], arr[1]); + } + + Chain chain = contractHelper.getChain(chainId); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(tx.size(), chain.getConfig().getFeeUnit(arr[0], arr[1])).add(BigInteger.valueOf(txData.getGasLimit()).multiply(BigInteger.valueOf(txData.getPrice()))); if (realFee.compareTo(fee) >= 0) { return getSuccess(); } else { diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/validator/CreateContractTxValidator.java b/module/nuls-cores/src/main/java/io/nuls/contract/validator/CreateContractTxValidator.java index 435bbf412..d2b410161 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/validator/CreateContractTxValidator.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/validator/CreateContractTxValidator.java @@ -31,6 +31,7 @@ import io.nuls.base.data.CoinFrom; import io.nuls.base.data.CoinTo; import io.nuls.base.signture.SignatureUtil; +import io.nuls.common.NCUtils; import io.nuls.common.NulsCoresConfig; import io.nuls.contract.helper.ContractHelper; import io.nuls.contract.model.bo.Chain; @@ -50,6 +51,7 @@ import java.util.List; import java.util.Set; +import static io.nuls.contract.config.ContractContext.FEE_ASSETS_SET; import static io.nuls.contract.constant.ContractErrorCode.*; import static io.nuls.contract.util.ContractUtil.getSuccess; @@ -72,13 +74,13 @@ public Result validate(int chainId, CreateContractTransaction tx) throws NulsExc // inspect toList, Except for the black hole address, others are not allowed 000000000000000000000000000000000000000000000000000000000000000000 int toListSize = toList.size(); do { - if(toListSize == 0) { + if (toListSize == 0) { break; } - if(toListSize == 1) { + if (toListSize == 1) { CoinTo coinTo = toList.get(0); byte[] blockHoleAddress = AddressTool.getAddress(HexUtil.decode(contractConfig.getBlackHolePublicKey()), contractConfig.getChainId()); - if(Arrays.equals(blockHoleAddress, coinTo.getAddress())) { + if (Arrays.equals(blockHoleAddress, coinTo.getAddress())) { break; } } @@ -90,15 +92,19 @@ public Result validate(int chainId, CreateContractTransaction tx) throws NulsExc byte[] sender = txData.getSender(); boolean existSender = false; Chain chain = contractHelper.getChain(chainId); - int assetsId = chain.getConfig().getAssetId(); - for(CoinFrom from : fromList) { - if(from.getAssetsChainId() != chainId || from.getAssetsId() != assetsId) { + int feeAssetId = chain.getConfig().getAssetId(); + int feeAssetChainId = chain.getConfig().getAssetId(); + for (CoinFrom from : fromList) { + if (!FEE_ASSETS_SET.contains(NCUtils.getTokenId(from.getAssetsChainId(), from.getAssetsId()))) { Log.error("contract create error: The chain id or assets id of coin from is error."); return Result.getFailed(CONTRACT_COIN_ASSETS_ERROR); } - if(!existSender && Arrays.equals(from.getAddress(), sender)) { + if (!existSender && Arrays.equals(from.getAddress(), sender)) { existSender = true; } + + feeAssetId = from.getAssetsId(); + feeAssetChainId = from.getAssetsChainId(); } Set addressSet = SignatureUtil.getAddressFromTX(tx, chainId); if (!existSender || !addressSet.contains(AddressTool.getStringAddressByBytes(sender))) { @@ -106,7 +112,7 @@ public Result validate(int chainId, CreateContractTransaction tx) throws NulsExc return Result.getFailed(CONTRACT_CREATOR_ERROR); } String alias = txData.getAlias(); - if(!FormatValidUtils.validAlias(alias)) { + if (!FormatValidUtils.validAlias(alias)) { Log.error("contract create error: The contract alias format error."); return Result.getFailed(CONTRACT_ALIAS_FORMAT_ERROR); } @@ -126,7 +132,7 @@ public Result validate(int chainId, CreateContractTransaction tx) throws NulsExc } BigInteger realFee = tx.getFee(); - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(tx.size()).add(BigInteger.valueOf(txData.getGasLimit()).multiply(BigInteger.valueOf(txData.getPrice()))); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(tx.size(), chain.getConfig().getFeeUnit(feeAssetChainId, feeAssetId)).add(BigInteger.valueOf(txData.getGasLimit()).multiply(BigInteger.valueOf(txData.getPrice()))); if (realFee.compareTo(fee) >= 0) { return getSuccess(); } else { diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/validator/DeleteContractTxValidator.java b/module/nuls-cores/src/main/java/io/nuls/contract/validator/DeleteContractTxValidator.java index 09bb38b3c..5c6a36dbc 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/validator/DeleteContractTxValidator.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/validator/DeleteContractTxValidator.java @@ -48,8 +48,8 @@ import java.util.List; import java.util.Set; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_MAIN_ASSET_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_CHAIN_ID; import static io.nuls.contract.constant.ContractErrorCode.*; import static io.nuls.contract.util.ContractUtil.getSuccess; @@ -107,7 +107,7 @@ public Result validate(int chainId, DeleteContractTransaction tx) throws NulsExc return Result.getFailed(CONTRACT_OWNER_ERROR); } - ContractBalance balance = contractHelper.getRealBalance(chainId, CHAIN_ID, ASSET_ID, AddressTool.getStringAddressByBytes(contractAddressBytes)); + ContractBalance balance = contractHelper.getRealBalance(chainId, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID, AddressTool.getStringAddressByBytes(contractAddressBytes)); if (balance == null) { Log.error("contract delete error: That balance of the contract is abnormal."); return Result.getFailed(CONTRACT_BALANCE_ERROR); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/vm/Heap.java b/module/nuls-cores/src/main/java/io/nuls/contract/vm/Heap.java index f85ad165f..187d45deb 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/vm/Heap.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/vm/Heap.java @@ -186,7 +186,7 @@ public Map getFieldsFromState(ObjectRef objectRef) { } byte[] value = dataWord.getNoLeadZeroesData(); Map map = (Map) JsonUtils.decode(new String(value), classNames); - if (ProtocolGroupManager.getCurrentVersion(ContractContext.CHAIN_ID) < ContractContext.UPDATE_VERSION_CONTRACT_BALANCE ) { + if (ProtocolGroupManager.getCurrentVersion(ContractContext.LOCAL_CHAIN_ID) < ContractContext.UPDATE_VERSION_CONTRACT_BALANCE ) { return map; } if (!VariableType.HASH_MAP_TYPE.getDesc().equals(objectRef.getDesc())) { diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/vm/code/ClassCodeLoader.java b/module/nuls-cores/src/main/java/io/nuls/contract/vm/code/ClassCodeLoader.java index 9fec609eb..af1d05cc4 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/vm/code/ClassCodeLoader.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/vm/code/ClassCodeLoader.java @@ -123,13 +123,13 @@ public static ClassCode loadFromResource_v15(String className) { } public static ClassCode getFromResource(String className) { - if (ProtocolGroupManager.getCurrentVersion(ContractContext.CHAIN_ID) >= ContractContext.PROTOCOL_15) { + if (ProtocolGroupManager.getCurrentVersion(ContractContext.LOCAL_CHAIN_ID) >= ContractContext.PROTOCOL_15) { return RESOURCE_CLASS_CODES_V15.get(className); } - if (ProtocolGroupManager.getCurrentVersion(ContractContext.CHAIN_ID) >= ContractContext.PROTOCOL_14) { + if (ProtocolGroupManager.getCurrentVersion(ContractContext.LOCAL_CHAIN_ID) >= ContractContext.PROTOCOL_14) { return RESOURCE_CLASS_CODES_V14.get(className); } - if (ProtocolGroupManager.getCurrentVersion(ContractContext.CHAIN_ID) >= ContractContext.UPDATE_VERSION_CONTRACT_ASSET) { + if (ProtocolGroupManager.getCurrentVersion(ContractContext.LOCAL_CHAIN_ID) >= ContractContext.UPDATE_VERSION_CONTRACT_ASSET) { return RESOURCE_CLASS_CODES_V8.get(className); } return RESOURCE_CLASS_CODES.get(className); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/vm/instructions/references/Invokespecial.java b/module/nuls-cores/src/main/java/io/nuls/contract/vm/instructions/references/Invokespecial.java index f24835965..7919a21dc 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/vm/instructions/references/Invokespecial.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/vm/instructions/references/Invokespecial.java @@ -63,7 +63,7 @@ public static void invokespecial(Frame frame) { return; } - if (ProtocolGroupManager.getCurrentVersion(ContractContext.CHAIN_ID) >= ContractContext.UPDATE_VERSION_CONTRACT_BALANCE) { + if (ProtocolGroupManager.getCurrentVersion(ContractContext.LOCAL_CHAIN_ID) >= ContractContext.UPDATE_VERSION_CONTRACT_BALANCE) { if (methodCode.isMethod(GROW_CLASS_NAME, GROW_METHOD_NAME, GROW_METHOD_DESC)) { // ArrayList Expansion restrictions MethodCode sizeMethod = frame.vm.methodArea.loadMethod(className, Constants.SIZE, Constants.SIZE_DESC); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/vm/instructions/references/Invokevirtual.java b/module/nuls-cores/src/main/java/io/nuls/contract/vm/instructions/references/Invokevirtual.java index 58ad0546d..a4ba4f749 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/vm/instructions/references/Invokevirtual.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/vm/instructions/references/Invokevirtual.java @@ -78,7 +78,7 @@ public static void invokevirtual(Frame frame) { return; } - if (ProtocolGroupManager.getCurrentVersion(ContractContext.CHAIN_ID) >= ContractContext.UPDATE_VERSION_CONTRACT_BALANCE) { + if (ProtocolGroupManager.getCurrentVersion(ContractContext.LOCAL_CHAIN_ID) >= ContractContext.UPDATE_VERSION_CONTRACT_BALANCE) { if (methodCode.isMethod(RESIZE_CLASS_NAME, RESIZE_METHOD_NAME, RESIZE_METHOD_DESC)) { // HashMap Expansion restrictions MethodCode sizeMethod = frame.vm.methodArea.loadMethod(className, Constants.SIZE, Constants.SIZE_DESC); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/vm/natives/io/nuls/contract/sdk/NativeAddress.java b/module/nuls-cores/src/main/java/io/nuls/contract/vm/natives/io/nuls/contract/sdk/NativeAddress.java index 6e217cd26..b6ac238cd 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/vm/natives/io/nuls/contract/sdk/NativeAddress.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/vm/natives/io/nuls/contract/sdk/NativeAddress.java @@ -39,8 +39,8 @@ import java.util.Iterator; import java.util.List; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_MAIN_ASSET_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_CHAIN_ID; import static io.nuls.contract.vm.natives.NativeMethod.NOT_SUPPORT_NATIVE; import static io.nuls.contract.vm.natives.NativeMethod.SUPPORT_NATIVE; @@ -133,11 +133,11 @@ public static Result nativeRun(MethodCode methodCode, MethodArgs methodArgs, Fra } private static BigInteger balance(byte[] address, Frame frame) { - return frame.vm.getProgramExecutor().getAccount(address, CHAIN_ID, ASSET_ID).getBalance(); + return frame.vm.getProgramExecutor().getAccount(address, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID).getBalance(); } private static BigInteger totalBalance(byte[] address, Frame frame) { - return frame.vm.getProgramExecutor().getAccount(address, CHAIN_ID, ASSET_ID).getTotalBalance(); + return frame.vm.getProgramExecutor().getAccount(address, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID).getTotalBalance(); } public static final String balance = TYPE + "." + "balance" + "()Ljava/math/BigInteger;"; @@ -206,12 +206,12 @@ private static Result totalBalanceOfDesignatedAsset(MethodCode methodCode, Metho * see Address#transfer(BigInteger) */ private static Result transfer(MethodCode methodCode, MethodArgs methodArgs, Frame frame) { - return transferBase(methodCode, methodArgs, frame, CHAIN_ID, ASSET_ID, 0); + return transferBase(methodCode, methodArgs, frame, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID, 0); } private static Result transferLocked(MethodCode methodCode, MethodArgs methodArgs, Frame frame) { long lockedTime = (long) methodArgs.invokeArgs[1]; - return transferBase(methodCode, methodArgs, frame, CHAIN_ID, ASSET_ID, lockedTime); + return transferBase(methodCode, methodArgs, frame, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID, lockedTime); } private static Result transferOfDesignatedAsset(MethodCode methodCode, MethodArgs methodArgs, Frame frame) { @@ -235,7 +235,7 @@ private static Result transferBase(MethodCode methodCode, MethodArgs methodArgs, frame.vm.addGasUsed(GasCost.TRANSFER); - boolean mainAsset = assetChainId == CHAIN_ID && assetId == ASSET_ID; + boolean mainAsset = assetChainId == LOCAL_CHAIN_ID && assetId == LOCAL_MAIN_ASSET_ID; if (frame.heap.existContract(to)) { if (lockedTime > 0) { throw new ErrorException(String.format("Cannot transfer the locked amount to the contract address %s", address), frame.vm.getGasUsed(), null); @@ -380,9 +380,9 @@ public static ProgramResult call(String address, String methodName, String metho programCall.setInternalCall(true); if (programCall.getValue().compareTo(BigInteger.ZERO) > 0) { - checkBalance(programCall.getSender(), CHAIN_ID, ASSET_ID, programCall.getValue(), frame); - frame.vm.getProgramExecutor().getAccount(programCall.getSender(), CHAIN_ID, ASSET_ID).addBalance(programCall.getValue().negate()); - ProgramTransfer programTransfer = new ProgramTransfer(programCall.getSender(), programCall.getContractAddress(), programCall.getValue(), CHAIN_ID, ASSET_ID, 0); + checkBalance(programCall.getSender(), LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID, programCall.getValue(), frame); + frame.vm.getProgramExecutor().getAccount(programCall.getSender(), LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID).addBalance(programCall.getValue().negate()); + ProgramTransfer programTransfer = new ProgramTransfer(programCall.getSender(), programCall.getContractAddress(), programCall.getValue(), LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID, 0); frame.vm.getTransfers().add(programTransfer); // add by pierre at 2019-11-23 sign Add contract generation transactions in the order of contract execution, and process the business of contract generation transactions in this order Uncertain Protocol upgrade required frame.vm.getOrderedInnerTxs().add(programTransfer); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/vm/natives/io/nuls/contract/sdk/NativeUtils.java b/module/nuls-cores/src/main/java/io/nuls/contract/vm/natives/io/nuls/contract/sdk/NativeUtils.java index 9a713827b..304a2093d 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/vm/natives/io/nuls/contract/sdk/NativeUtils.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/vm/natives/io/nuls/contract/sdk/NativeUtils.java @@ -70,8 +70,8 @@ import java.math.BigInteger; import java.util.*; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_MAIN_ASSET_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_CHAIN_ID; import static io.nuls.contract.constant.ContractConstant.RPC_RESULT_KEY; import static io.nuls.contract.vm.natives.NativeMethod.NOT_SUPPORT_NATIVE; import static io.nuls.contract.vm.natives.NativeMethod.SUPPORT_NATIVE; @@ -648,7 +648,7 @@ private static Result invokeExternalCmd(MethodCode methodCode, MethodArgs method BlockHeaderDto blockHeaderDto = frame.vm.getBlockHeader(programInvoke.getNumber() + 1); long blockTime = blockHeaderDto.getTime(); // Contract balance maintained internally using virtual machines - ProgramAccount account = frame.vm.getProgramExecutor().getAccount(contractAddressBytes, CHAIN_ID, ASSET_ID); + ProgramAccount account = frame.vm.getProgramExecutor().getAccount(contractAddressBytes, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID); argsMap.put("contractBalance", account.getBalance().toString()); argsMap.put("contractNonce", account.getNonce()); argsMap.put("blockTime", blockTime); diff --git a/module/nuls-cores/src/main/java/io/nuls/contract/vm/program/impl/ProgramExecutorImpl.java b/module/nuls-cores/src/main/java/io/nuls/contract/vm/program/impl/ProgramExecutorImpl.java index 02a18776e..f821ebed3 100644 --- a/module/nuls-cores/src/main/java/io/nuls/contract/vm/program/impl/ProgramExecutorImpl.java +++ b/module/nuls-cores/src/main/java/io/nuls/contract/vm/program/impl/ProgramExecutorImpl.java @@ -61,8 +61,8 @@ import java.util.*; import java.util.stream.Collectors; -import static io.nuls.contract.config.ContractContext.ASSET_ID; -import static io.nuls.contract.config.ContractContext.CHAIN_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_MAIN_ASSET_ID; +import static io.nuls.contract.config.ContractContext.LOCAL_CHAIN_ID; import static io.nuls.contract.constant.ContractConstant.BALANCE_TRIGGER_FOR_CONSENSUS_CONTRACT_METHOD_DESC; import static io.nuls.contract.constant.ContractConstant.BALANCE_TRIGGER_METHOD_NAME; import static io.nuls.contract.util.ContractUtil.addressKey; @@ -530,7 +530,7 @@ private ProgramResult execute(ProgramInvoke programInvoke) { if (transferValue.compareTo(BigInteger.ZERO) > 0) { // Changes in asset balances corresponding to contracts - getAccount(contractAddressBytes, CHAIN_ID, ASSET_ID).addBalance(transferValue); + getAccount(contractAddressBytes, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID).addBalance(transferValue); } if (multyAssetValues != null && !multyAssetValues.isEmpty()) { for (ProgramMultyAssetValue assetValue : multyAssetValues) { @@ -674,7 +674,7 @@ public ProgramResult stop(long blockNumber, byte[] address, byte[] sender) { return revert("only the owner can stop the contract"); } // Chain Master Asset - BigInteger balance = getTotalBalance(address, null, CHAIN_ID, ASSET_ID); + BigInteger balance = getTotalBalance(address, null, LOCAL_CHAIN_ID, LOCAL_MAIN_ASSET_ID); if (BigInteger.ZERO.compareTo(balance) != 0) { return revert("contract balance is not zero"); } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/constant/CommandConstant.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/constant/CommandConstant.java index 9f7b32e58..8878bc30c 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/constant/CommandConstant.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/constant/CommandConstant.java @@ -63,4 +63,7 @@ public interface CommandConstant { */ String CROSS_TX_REHANDLE_MESSAGE = "ctxRehandle"; + + String CROSS_CTX_FULL_SIGN_MESSAGE = "recvCtxFullSign"; + } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/CtxFullSignMessage.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/CtxFullSignMessage.java new file mode 100644 index 000000000..c7c5a5644 --- /dev/null +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/CtxFullSignMessage.java @@ -0,0 +1,76 @@ +package io.nuls.crosschain.base.message; + +import io.nuls.base.basic.NulsByteBuffer; +import io.nuls.base.basic.NulsOutputStreamBuffer; +import io.nuls.base.data.NulsHash; +import io.nuls.core.exception.NulsException; +import io.nuls.core.parse.SerializeUtils; +import io.nuls.crosschain.base.message.base.BaseMessage; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Objects; + +/** + * @description TODO + * @date 2024/6/17 14:09 + * @COPYRIGHT nabox.io + */ +public class CtxFullSignMessage extends BaseMessage { + + private NulsHash localTxHash; + + private byte[] transactionSignature; + + @Override + protected void serializeToStream(NulsOutputStreamBuffer stream) throws IOException { + stream.write(localTxHash.getBytes()); + stream.writeBytesWithLength(transactionSignature); + } + + @Override + public void parse(NulsByteBuffer byteBuffer) throws NulsException { + this.localTxHash = byteBuffer.readHash(); + this.transactionSignature = byteBuffer.readByLengthByte(); + } + + @Override + public int size() { + int size = 0; + size += NulsHash.HASH_LENGTH; + size += SerializeUtils.sizeOfBytes(transactionSignature); + return size; + } + + + public byte[] getTransactionSignature() { + return transactionSignature; + } + + public void setTransactionSignature(byte[] transactionSignature) { + this.transactionSignature = transactionSignature; + } + + public NulsHash getLocalTxHash() { + return localTxHash; + } + + public void setLocalTxHash(NulsHash localTxHash) { + this.localTxHash = localTxHash; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CtxFullSignMessage that = (CtxFullSignMessage) o; + return Objects.equals(localTxHash, that.localTxHash) && Arrays.equals(transactionSignature, that.transactionSignature); + } + + @Override + public int hashCode() { + int result = Objects.hash(localTxHash); + result = 31 * result + Arrays.hashCode(transactionSignature); + return result; + } +} diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/BroadCtxHashHandler.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/BroadCtxHashHandler.java index 6b91a313e..1f50d67c1 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/BroadCtxHashHandler.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/BroadCtxHashHandler.java @@ -4,9 +4,13 @@ import io.nuls.base.protocol.MessageProcessor; import io.nuls.core.core.annotation.Autowired; import io.nuls.core.core.annotation.Component; +import io.nuls.core.log.Log; import io.nuls.crosschain.base.constant.CommandConstant; import io.nuls.crosschain.base.message.BroadCtxHashMessage; import io.nuls.crosschain.base.service.ProtocolService; +import io.nuls.crosschain.base.utils.HashSetTimeDuplicateProcessor; +import io.nuls.crosschain.model.bo.Chain; +import io.nuls.crosschain.utils.manager.ChainManager; /** * BroadCtxHashMessageProcessing class @@ -21,6 +25,8 @@ public class BroadCtxHashHandler implements MessageProcessor { @Autowired private ProtocolService protocolService; + private HashSetTimeDuplicateProcessor processor = new HashSetTimeDuplicateProcessor(1000, 300000L); + @Override public String getCmd() { return CommandConstant.BROAD_CTX_HASH_MESSAGE; @@ -32,6 +38,11 @@ public void process(int chainId, String nodeId, String message) { if (message == null) { return; } - protocolService.receiveCtxHash(chainId, nodeId, realMessage); + if (processor.insertAndCheck(nodeId + realMessage)) { +// Log.info("C process : " + nodeId + "," + message); + protocolService.receiveCtxHash(chainId, nodeId, realMessage); + } else { +// Log.info("C discard : " + nodeId + "," + message); + } } } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/BroadCtxSignHandler.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/BroadCtxSignHandler.java index 40e342725..33a112b11 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/BroadCtxSignHandler.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/BroadCtxSignHandler.java @@ -4,9 +4,13 @@ import io.nuls.base.protocol.MessageProcessor; import io.nuls.core.core.annotation.Autowired; import io.nuls.core.core.annotation.Component; +import io.nuls.core.log.Log; import io.nuls.crosschain.base.constant.CommandConstant; import io.nuls.crosschain.base.message.BroadCtxSignMessage; import io.nuls.crosschain.base.service.ProtocolService; +import io.nuls.crosschain.base.utils.HashSetTimeDuplicateProcessor; +import io.nuls.crosschain.model.bo.Chain; +import io.nuls.crosschain.utils.manager.ChainManager; /** * BroadCtxSignMessageProcessing class @@ -21,6 +25,8 @@ public class BroadCtxSignHandler implements MessageProcessor { @Autowired private ProtocolService protocolService; + private HashSetTimeDuplicateProcessor processor = new HashSetTimeDuplicateProcessor(1000, 60000L); + @Override public String getCmd() { return CommandConstant.BROAD_CTX_SIGN_MESSAGE; @@ -29,9 +35,29 @@ public String getCmd() { @Override public void process(int chainId, String nodeId, String message) { BroadCtxSignMessage realMessage = RPCUtil.getInstanceRpcStr(message, BroadCtxSignMessage.class); - if (message == null) { + if (realMessage == null || realMessage.getLocalHash() == null) { return; } - protocolService.receiveCtxSign(chainId, nodeId, realMessage); + String hash = realMessage.getLocalHash().toHex(); + if (processor.insertAndCheck(nodeId + hash)) { + protocolService.receiveCtxSign(chainId, nodeId, realMessage); +// Log.info("A process : " + nodeId + "," + hash); + } else { +// Log.info("A discard : " + nodeId + "," + hash); + } } +// +// public static void main(String[] args) throws InterruptedException { +// String key = "sdfesgjlsdflksdf"; +// HashSetTimeDuplicateProcessor processor = new HashSetTimeDuplicateProcessor(1000, 60000L); +// boolean b = processor.insertAndCheck(key); +// System.out.println(b); +// b = processor.insertAndCheck(key); +// System.out.println(b); +// Thread.sleep(60001L); +// b = processor.insertAndCheck(key); +// System.out.println(b); +// b = processor.insertAndCheck(key); +// System.out.println(b); +// } } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/CtxFullSignHandler.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/CtxFullSignHandler.java new file mode 100644 index 000000000..aa51831aa --- /dev/null +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/CtxFullSignHandler.java @@ -0,0 +1,37 @@ +package io.nuls.crosschain.base.message.handler; + +import io.nuls.base.RPCUtil; +import io.nuls.base.protocol.MessageProcessor; +import io.nuls.core.core.annotation.Autowired; +import io.nuls.core.core.annotation.Component; +import io.nuls.core.model.StringUtils; +import io.nuls.crosschain.base.constant.CommandConstant; +import io.nuls.crosschain.base.message.BroadCtxSignMessage; +import io.nuls.crosschain.base.message.CtxFullSignMessage; +import io.nuls.crosschain.base.service.ProtocolService; + +/** + * @description TODO + * @date 2024/6/17 14:47 + * @COPYRIGHT nabox.io + */ +@Component("CtxFullSignHandlerV1") +public class CtxFullSignHandler implements MessageProcessor { + + @Autowired + private ProtocolService protocolService; + + @Override + public String getCmd() { + return CommandConstant.CROSS_CTX_FULL_SIGN_MESSAGE; + } + + @Override + public void process(int chainId, String nodeId, String message) { + if (StringUtils.isBlank(message)) { + return; + } + CtxFullSignMessage ctxFullSignMessage = RPCUtil.getInstanceRpcStr(message, CtxFullSignMessage.class); + protocolService.receiveCtxFullSign(chainId, nodeId, ctxFullSignMessage); + } +} diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/GetOtherCtxHandler.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/GetOtherCtxHandler.java index 9acf52657..0d9846a01 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/GetOtherCtxHandler.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/message/handler/GetOtherCtxHandler.java @@ -4,9 +4,13 @@ import io.nuls.base.protocol.MessageProcessor; import io.nuls.core.core.annotation.Autowired; import io.nuls.core.core.annotation.Component; +import io.nuls.core.log.Log; import io.nuls.crosschain.base.constant.CommandConstant; import io.nuls.crosschain.base.message.GetOtherCtxMessage; import io.nuls.crosschain.base.service.ProtocolService; +import io.nuls.crosschain.base.utils.HashSetTimeDuplicateProcessor; +import io.nuls.crosschain.model.bo.Chain; +import io.nuls.crosschain.utils.manager.ChainManager; /** * GetOtherCtxMessageProcessing class @@ -21,6 +25,8 @@ public class GetOtherCtxHandler implements MessageProcessor { @Autowired private ProtocolService protocolService; + private HashSetTimeDuplicateProcessor processor = new HashSetTimeDuplicateProcessor(1000, 300000L); + @Override public String getCmd() { return CommandConstant.GET_OTHER_CTX_MESSAGE; @@ -29,9 +35,17 @@ public String getCmd() { @Override public void process(int chainId, String nodeId, String message) { GetOtherCtxMessage realMessage = RPCUtil.getInstanceRpcStr(message, GetOtherCtxMessage.class); - if (message == null) { + if (realMessage == null || realMessage.getRequestHash() == null) { +// Log.info("0 discard : " + nodeId + "," + message); return; } - protocolService.getOtherCtx(chainId, nodeId, realMessage); + String hash = realMessage.getRequestHash().toHex(); + if (processor.insertAndCheck(nodeId + hash)) { +// Log.info("B process : " + nodeId + "," + hash); + protocolService.getOtherCtx(chainId, nodeId, realMessage); + } else { +// Log.info("B discard : " + nodeId + "," + hash); + } + } } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/service/ProtocolService.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/service/ProtocolService.java index bfe417b2b..ff8308400 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/service/ProtocolService.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/service/ProtocolService.java @@ -65,4 +65,13 @@ public interface ProtocolService { * @param messageBody Message Body * */ void receiveCtxSign(int chainId,String nodeId,BroadCtxSignMessage messageBody); + + + /** + * Receive cross chain full transaction signature + * @param chainId + * @param nodeId + * @param messageBody + */ + void receiveCtxFullSign(int chainId, String nodeId, CtxFullSignMessage messageBody); } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/base/utils/HashSetTimeDuplicateProcessor.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/utils/HashSetTimeDuplicateProcessor.java new file mode 100644 index 000000000..91e474a25 --- /dev/null +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/base/utils/HashSetTimeDuplicateProcessor.java @@ -0,0 +1,122 @@ +/* + * MIT License + * + * Copyright (c) 2017-2019 nuls.io + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + */ + +package io.nuls.crosschain.base.utils; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * @author: Niels Wang + * @date: 2018/7/9 + */ +public class HashSetTimeDuplicateProcessor { + + private final int maxSize; + private final int percent90; + private final long timeoutMs; + private Map map1 = new HashMap<>(); + private Map map2 = new HashMap<>(); + + public HashSetTimeDuplicateProcessor(int maxSize, long ms) { + this.maxSize = maxSize; + this.percent90 = maxSize * 9 / 10; + this.timeoutMs = ms; + } + + public synchronized boolean insertAndCheck(String hash) { + boolean result = map1.containsKey(hash); + if (!result) { + map1.put(hash, System.currentTimeMillis()); + return true; + } + Long start = map1.get(hash); + long sub = System.currentTimeMillis() - start; + long timeVal = System.currentTimeMillis(); + if (sub >= timeoutMs) { + result = true; + } else { + timeVal = start; + result = false; + } + map1.put(hash, timeVal); + int size = map1.size(); + if (size >= maxSize) { + map2.put(hash, timeVal); + map1.clear(); + map1.putAll(map2); + map2.clear(); + } else if (size >= percent90) { + map2.put(hash, timeVal); + } + return result; + } + + public boolean contains(String hash) { + return map1.containsKey(hash); + } + + public void remove(String hash) { + map1.remove(hash); + map2.remove(hash); + } + + public static void main(String[] args) { + HashSetTimeDuplicateProcessor processor = new HashSetTimeDuplicateProcessor(1000,10000L); + assertTrueTest(processor.insertAndCheck("1")); + assertTrueTest(processor.insertAndCheck("2")); + assertTrueTest(processor.insertAndCheck("3")); + + assertFlaseTest(processor.insertAndCheck("1")); + assertFlaseTest(processor.insertAndCheck("2")); + + try { + Thread.sleep(10000L); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + + assertTrueTest(processor.insertAndCheck("1")); + assertTrueTest(processor.insertAndCheck("2")); + assertTrueTest(processor.insertAndCheck("3")); + assertFlaseTest(processor.insertAndCheck("1")); + assertFlaseTest(processor.insertAndCheck("2")); + + } + + private static void assertTrueTest(boolean b) { + if(!b){ + throw new RuntimeException("预期为true,实际得到false"); + } + } + + private static void assertFlaseTest(boolean b) { + if(b){ + throw new RuntimeException("预期为false,实际得到true"); + } + } +} diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/model/bo/Chain.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/model/bo/Chain.java index 558dcda03..f536cebbd 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/model/bo/Chain.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/model/bo/Chain.java @@ -82,6 +82,8 @@ public class Chain { private LinkedBlockingQueue getCtxStateQueue; + private LinkedBlockingQueue txFullSignMessageQueue; + /** * Thread pool * */ @@ -157,6 +159,9 @@ public Chain(){ signMessageByzantineQueue = new LinkedBlockingQueue<>(); otherCtxMessageQueue = new LinkedBlockingQueue<>(); getCtxStateQueue = new LinkedBlockingQueue<>(); + + txFullSignMessageQueue = new LinkedBlockingQueue<>(); + futureMessageMap = new ConcurrentHashMap<>(); verifierList = new ArrayList<>(); mainChain = false; @@ -330,4 +335,8 @@ public synchronized Transaction isExistVerifierChangeTx(Transaction verifierChan } return this.verifierChangeTx; } + + public LinkedBlockingQueue getTxFullSignMessageQueue() { + return txFullSignMessageQueue; + } } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/rpc/call/NetWorkCall.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/rpc/call/NetWorkCall.java index 82546d855..aeb0ecea0 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/rpc/call/NetWorkCall.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/rpc/call/NetWorkCall.java @@ -58,7 +58,7 @@ public static boolean broadcast(int chainId, BaseMessage message, String exclude params.put("isCross", isCross); Response cmdResp = ResponseMessageProcessor.requestAndResponse(ModuleE.NW.abbr, "nw_broadcast", params, NulsCrossChainConstant.RPC_TIME_OUT); if (!cmdResp.isSuccess()) { - LoggerUtil.commonLog.error("Packing state failed to send!"); + LoggerUtil.commonLog.error("[nw_broadcast] Packing state failed to send!"); return false; } return (boolean)((HashMap) ((HashMap) cmdResp.getResponseData()).get("nw_broadcast")).get("value"); diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/servive/impl/BlockServiceImpl.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/servive/impl/BlockServiceImpl.java index 5b6d9d022..23f3c84a8 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/servive/impl/BlockServiceImpl.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/servive/impl/BlockServiceImpl.java @@ -6,6 +6,7 @@ import io.nuls.base.data.NulsHash; import io.nuls.base.data.Transaction; import io.nuls.common.NulsCoresConfig; +import io.nuls.contract.util.Log; import io.nuls.core.basic.Result; import io.nuls.core.constant.CommonCodeConstanst; import io.nuls.core.core.annotation.Autowired; @@ -29,6 +30,7 @@ /** * Interface implementation class provided for block module calls + * * @author tag * @date 2019/4/25 */ @@ -69,9 +71,9 @@ public Result syncStatusUpdate(Map params) { if (chain == null) { return Result.getFailed(NulsCrossChainErrorCode.CHAIN_NOT_EXIST); } - int syncStatus = (int)params.get(ParamConstant.SYNC_STATUS); + int syncStatus = (int) params.get(ParamConstant.SYNC_STATUS); chain.setSyncStatus(syncStatus); - chain.getLogger().info("Node synchronization status change,syncStatus:{}",syncStatus ); + chain.getLogger().info("Node synchronization status change,syncStatus:{}", syncStatus); return Result.getSuccess(CommonCodeConstanst.SUCCESS); } @@ -79,66 +81,67 @@ public Result syncStatusUpdate(Map params) { @SuppressWarnings("unchecked") public Result newBlockHeight(Map params) { Result result = paramValid(params); - if(result.isFailed()){ + if (result.isFailed()) { + Log.error(result.getMsg()); return result; } int chainId = (int) params.get(ParamConstant.CHAIN_ID); Chain chain = chainManager.getChainMap().get(chainId); long height = Long.valueOf(params.get(ParamConstant.NEW_BLOCK_HEIGHT).toString()); - chain.getLogger().info("Received block height update information, the latest block height is:{}", height); + chain.getLogger().debug("Received block height update information, the latest block height is:{}", height); //Check if there are cross chain transactions waiting to be broadcasted - Map sendHeightMap = sendHeightService.getList(chainId); - if(sendHeightMap != null && sendHeightMap.size() >0){ + Map sendHeightMap = sendHeightService.getList(chainId); + if (sendHeightMap != null && sendHeightMap.size() > 0) { Set sortSet = new TreeSet<>(sendHeightMap.keySet()); //Cache the status of each chain - Map crossStatusMap = new HashMap<>(NulsCrossChainConstant.INIT_CAPACITY_16); + Map crossStatusMap = new HashMap<>(NulsCrossChainConstant.INIT_CAPACITY_16); //Broadcast to cache various transaction types that have failed on each chain to avoid broadcasting out of order Map broadFailMap = new HashMap<>(NulsCrossChainConstant.INIT_CAPACITY_16); - for (long cacheHeight:sortSet) { - if(height >= cacheHeight){ - chain.getLogger().debug("The height of the broadcast block is{}Cross chain transactions to other chains",cacheHeight ); + for (long cacheHeight : sortSet) { + if (height >= cacheHeight && height - cacheHeight < 2000) { + chain.getLogger().debug("The height of the broadcast block is{}Cross chain transactions to other chains", cacheHeight); SendCtxHashPO po = sendHeightMap.get(cacheHeight); List broadSuccessCtxHash = new ArrayList<>(); List broadFailCtxHash = new ArrayList<>(); - for (NulsHash ctxHash:po.getHashList()) { - if(BroadCtxUtil.broadCtxHash(chain, ctxHash, cacheHeight, crossStatusMap,broadFailMap)){ + for (NulsHash ctxHash : po.getHashList()) { + if (BroadCtxUtil.broadCtxHash(chain, ctxHash, cacheHeight, crossStatusMap, broadFailMap)) { broadSuccessCtxHash.add(ctxHash); - }else{ + } else { broadFailCtxHash.add(ctxHash); } } - if(broadSuccessCtxHash.size() > 0){ - SendCtxHashPO sendedPo = sendedHeightService.get(cacheHeight,chainId); - if(sendedPo != null){ + if (broadSuccessCtxHash.size() > 0) { + SendCtxHashPO sendedPo = sendedHeightService.get(cacheHeight, chainId); + if (sendedPo != null) { sendedPo.getHashList().addAll(broadSuccessCtxHash); - }else{ + } else { sendedPo = new SendCtxHashPO(broadSuccessCtxHash); } - if(!sendedHeightService.save(cacheHeight, sendedPo, chainId)){ + if (!sendedHeightService.save(cacheHeight, sendedPo, chainId)) { continue; } } - if(broadFailCtxHash.size() > 0){ + if (broadFailCtxHash.size() > 0) { int ONE_DAY_HEIGHT = 360 * 24; - if(height - cacheHeight < ONE_DAY_HEIGHT){ + if (height - cacheHeight < ONE_DAY_HEIGHT) { po.setHashList(broadFailCtxHash); sendHeightService.save(cacheHeight, po, chainId); - chain.getLogger().error("The block height is{}Cross chain transaction broadcast failed for",cacheHeight); + chain.getLogger().error("The block height is {} Cross chain transaction broadcast failed for {}", cacheHeight, broadFailCtxHash); } - }else{ + } else { sendHeightService.delete(cacheHeight, chainId); - chain.getLogger().info("The block height is{}Cross chain transaction broadcast successful",cacheHeight); + chain.getLogger().info("The block height is {} Cross chain transaction broadcast successful", cacheHeight); } - }else{ - break; + } else { + continue; } } } - chain.getLogger().debug("Block height update message processing completed,Height:{}\n\n",height); + chain.getLogger().info("Block height update message processing completed,Height:{}\n\n", height); return Result.getSuccess(CommonCodeConstanst.SUCCESS); } - private Result paramValid(Map params){ + private Result paramValid(Map params) { if (params.get(ParamConstant.CHAIN_ID) == null || params.get(ParamConstant.NEW_BLOCK_HEIGHT) == null || params.get(ParamConstant.PARAM_BLOCK_HEADER) == null) { return Result.getFailed(CommonCodeConstanst.PARAMETER_ERROR); } @@ -155,52 +158,54 @@ private Result paramValid(Map params){ BlockHeader blockHeader = new BlockHeader(); String headerHex = (String) params.get(ParamConstant.PARAM_BLOCK_HEADER); blockHeader.parse(RPCUtil.decode(headerHex), 0); - if(!chainManager.isCrossNetUseAble()){ + if (!chainManager.isCrossNetUseAble()) { chainManager.getChainHeaderMap().put(chainId, blockHeader); chain.getLogger().info("Waiting for consensus network networking completion"); return Result.getSuccess(CommonCodeConstanst.SUCCESS); } - if(config.isMainNet() && chainManager.getRegisteredCrossChainList().size() <= 1){ - chain.getLogger().info("There is currently no registration chain" ); + if (config.isMainNet() && chainManager.getRegisteredCrossChainList().size() <= 1) { + chain.getLogger().info("There is currently no registration chain"); chainManager.getChainHeaderMap().put(chainId, blockHeader); return Result.getSuccess(CommonCodeConstanst.SUCCESS); } /* Blockchain in running state(download 0Blocking download in progress,1Received the latest block)Check for round changes. If there are round changes, query the consensus module for any changes in the consensus node. If there are changes, create a validator change transaction(This operation needs to be done after the validator initializes the transaction) */ - if(download == 1 && chain.getVerifierList() != null && !chain.getVerifierList().isEmpty()){ - Map> agentChangeMap; + if (download == 1 && chain.getVerifierList() != null && !chain.getVerifierList().isEmpty()) { + Map> agentChangeMap; BlockHeader localHeader = chainManager.getChainHeaderMap().get(chainId); - if(localHeader != null){ + if (localHeader != null) { BlockExtendsData blockExtendsData = blockHeader.getExtendsData(); BlockExtendsData localExtendsData = localHeader.getExtendsData(); - if(blockExtendsData.getRoundIndex() == localExtendsData.getRoundIndex()){ + if (blockExtendsData.getRoundIndex() == localExtendsData.getRoundIndex()) { chainManager.getChainHeaderMap().put(chainId, blockHeader); + chain.getLogger().info("ChainHeaderMap put : {} -- {}", chainId, blockHeader.getHeight()); return Result.getSuccess(CommonCodeConstanst.SUCCESS); } agentChangeMap = ConsensusCall.getAgentChangeInfo(chain, localHeader.getExtend(), blockHeader.getExtend()); - }else{ + } else { agentChangeMap = ConsensusCall.getAgentChangeInfo(chain, null, blockHeader.getExtend()); } - if(agentChangeMap != null){ + if (agentChangeMap != null) { List registerAgentList = agentChangeMap.get(ParamConstant.PARAM_REGISTER_AGENT_LIST); List cancelAgentList = agentChangeMap.get(ParamConstant.PARAM_CANCEL_AGENT_LIST); //Special processing for the first block,Check if the list of validators for the obtained changes is correct - if(localHeader == null){ - if(registerAgentList != null){ + if (localHeader == null) { + if (registerAgentList != null) { registerAgentList.removeAll(chain.getVerifierList()); } } boolean verifierChange = (registerAgentList != null && !registerAgentList.isEmpty()) || (cancelAgentList != null && !cancelAgentList.isEmpty()); - if(verifierChange){ - chain.getLogger().info("There is a change in verifier, create a transaction with a change in verifier, and the latest round shares a block address with the previous round:{},New Verifier List:{},Reduced list of validators:{}", chain.getVerifierList().toString(),registerAgentList,cancelAgentList); - Transaction verifierChangeTx = TxUtil.createVerifierChangeTx(registerAgentList, cancelAgentList, blockHeader.getExtendsData().getRoundStartTime(),chainId); + if (verifierChange) { + chain.getLogger().info("There is a change in verifier, create a transaction with a change in verifier, and the latest round shares a block address with the previous round:{},New Verifier List:{},Reduced list of validators:{}", chain.getVerifierList().toString(), registerAgentList, cancelAgentList); + Transaction verifierChangeTx = TxUtil.createVerifierChangeTx(registerAgentList, cancelAgentList, blockHeader.getExtendsData().getRoundStartTime(), chainId); chain.getCrossTxThreadPool().execute(new VerifierChangeTxHandler(chain, verifierChangeTx, blockHeader.getHeight())); } } } chainManager.getChainHeaderMap().put(chainId, blockHeader); - }catch (Exception e){ + chain.getLogger().info("ChainHeaderMap put : {} -- {}", chainId, blockHeader.getHeight()); + } catch (Exception e) { chain.getLogger().error(e); return Result.getFailed(CommonCodeConstanst.DATA_PARSE_ERROR); } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/servive/impl/NulsProtocolServiceImpl.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/servive/impl/NulsProtocolServiceImpl.java index 910a43c67..156526915 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/servive/impl/NulsProtocolServiceImpl.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/servive/impl/NulsProtocolServiceImpl.java @@ -16,11 +16,14 @@ import io.nuls.crosschain.base.message.*; import io.nuls.crosschain.base.model.bo.Circulation; import io.nuls.crosschain.base.service.ProtocolService; +import io.nuls.crosschain.base.service.ResetLocalVerifierService; import io.nuls.crosschain.constant.NulsCrossChainConstant; +import io.nuls.crosschain.constant.ParamConstant; import io.nuls.crosschain.model.bo.Chain; import io.nuls.crosschain.model.bo.CtxStateEnum; import io.nuls.crosschain.model.bo.message.UntreatedMessage; import io.nuls.crosschain.model.po.CtxStatusPO; +import io.nuls.crosschain.rpc.call.ConsensusCall; import io.nuls.crosschain.rpc.call.LedgerCall; import io.nuls.crosschain.rpc.call.NetWorkCall; import io.nuls.crosschain.srorage.*; @@ -57,6 +60,9 @@ public class NulsProtocolServiceImpl implements ProtocolService { @Autowired private CtxStateService ctxStateService; + @Autowired + private static ResetLocalVerifierService resetLocalVerifierService; + @Override /** * Query transaction processing status @@ -132,7 +138,7 @@ public void receiveCtxSign(int chainId, String nodeId, BroadCtxSignMessage messa if (messageBody.getSignature() != null) { signHex = HexUtil.encode(messageBody.getSignature()); } - chain.getLogger().debug("Received in chain node{}Cross chain transactions broadcasted overHashAnd signature,Hash:{},autograph:{}", nodeId, nativeHex, signHex); + chain.getLogger().info("Received in chain node{}Cross chain transactions broadcasted overHashAnd signature,Hash:{},autograph:{}", nodeId, nativeHex, signHex); //If the transaction is received for the first time, obtain the complete cross chain transaction from the broadcast node CtxStatusPO ctxStatusPO = ctxStatusService.get(localHash, handleChainId); if (ctxStatusPO == null) { @@ -140,7 +146,7 @@ public void receiveCtxSign(int chainId, String nodeId, BroadCtxSignMessage messa chain.getFutureMessageMap().putIfAbsent(localHash, new ArrayList<>()); chain.getFutureMessageMap().get(localHash).add(untreatedSignMessage); //TODO pierre test - chain.getLogger().debug("The current node has not yet confirmed the cross chain transaction, caching signature messages"); + chain.getLogger().info("The current node has not yet confirmed the cross chain transaction, caching signature messages"); return; } //If the transaction has been confirmed at this node, there is no need for further signature processing @@ -148,6 +154,10 @@ public void receiveCtxSign(int chainId, String nodeId, BroadCtxSignMessage messa chain.getLogger().debug("Cross chain transactions have been processed at this node,Hash:{}\n\n", nativeHex); return; } + if(System.currentTimeMillis()/1000 - ctxStatusPO.getTx().getTime()>30*24*3600){ + chain.getLogger().info("Cross chain transaction id old,Hash:{}\n\n", nativeHex); + return; + } try { UntreatedMessage untreatedSignMessage = new UntreatedMessage(chainId,nodeId,messageBody,localHash); chain.getSignMessageByzantineQueue().offer(untreatedSignMessage); @@ -169,10 +179,10 @@ public void receiveCtxHash(int chainId, String nodeId, BroadCtxHashMessage messa //Cross chain transmission involves main network protocol transactionsHASH NulsHash mainHash = messageBody.getConvertHash(); String mainHex = mainHash.toHex(); - chain.getLogger().debug("Received other chain nodes{}Cross chain transactions broadcasted over,Hash:{}", nodeId, mainHex); + chain.getLogger().info("Received other chain nodes{}Cross chain transactions broadcasted over,Hash:{}", nodeId, mainHex); //Determine if the transaction has been received,If it has been received, it will be returned directly. If it has not been received, it will be sent to the broadcast node to obtain the complete cross chain transaction message if (convertHashService.get(mainHash, handleChainId) != null) { - chain.getLogger().debug("This node has already received the cross chain transaction,Hash:{}\n\n", mainHex); + chain.getLogger().info("This node has already received the cross chain transaction,Hash:{}\n\n", mainHex); return; } if (chain.getOtherCtxStageMap().get(mainHash) == null && chain.getOtherCtxStageMap().putIfAbsent(mainHash, NulsCrossChainConstant.CTX_STAGE_WAIT_RECEIVE) == null) { @@ -185,7 +195,7 @@ public void receiveCtxHash(int chainId, String nodeId, BroadCtxHashMessage messa UntreatedMessage untreatedSignMessage = new UntreatedMessage(chainId,nodeId,messageBody,mainHash); chain.getHashMessageQueue().offer(untreatedSignMessage); } - chain.getLogger().debug("Cross chain transactions of other chain broadcastsHashMessage reception completed,Hash:{}\n\n", mainHex); + chain.getLogger().info("Cross chain transactions of other chain broadcastsHashMessage reception completed,Hash:{}\n\n", mainHex); } @Override @@ -297,4 +307,40 @@ public void getCirculation(int chainId, String nodeId, GetCirculationMessage mes chain.getLogger().error(e); } } + + + @Override + public void receiveCtxFullSign(int chainId, String nodeId, CtxFullSignMessage messageBody) { + int handleChainId = chainId; + if (config.isMainNet()) { + handleChainId = config.getMainChainId(); + } + Chain chain = chainManager.getChainMap().get(handleChainId); + + if (messageBody.getTransactionSignature() == null || messageBody.getTransactionSignature().length == 0) { + chain.getLogger().error("The full signature of the cross chain transaction is empty,txHash:{}", messageBody.getLocalTxHash().toHex()); + return; + } + + chain.getLogger().debug("Received the full Byzantine signature of a cross-chain transaction from another node,txHash:{},sign:{}" + , messageBody.getLocalTxHash().toHex() + , HexUtil.encode(messageBody.getTransactionSignature())); + + UntreatedMessage untreatedSignMessage = new UntreatedMessage(chainId,nodeId,messageBody,messageBody.getLocalTxHash()); + chain.getHashMessageQueue().offer(untreatedSignMessage); +// Transaction tx = ctxStatusPO.getTx(); +// List packAddressList = getPackingAddressList(tx, tx.getHash(), chain); +// TransactionSignature transactionSignature = new TransactionSignature(); +// try { +// transactionSignature.parse(messageBody.getTransactionSignature(),0); +// List signList = CommonUtil.getMisMatchSigns(chain,transactionSignature,packAddressList); +// +// } catch (NulsException e) { +// throw new RuntimeException(e); +// } + + + } + + } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/servive/impl/ResetLocalVerifierServiceImpl.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/servive/impl/ResetLocalVerifierServiceImpl.java index 1547e3035..262ecf30f 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/servive/impl/ResetLocalVerifierServiceImpl.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/servive/impl/ResetLocalVerifierServiceImpl.java @@ -36,7 +36,6 @@ import java.util.*; import java.util.stream.Collectors; -import static io.nuls.base.basic.TransactionFeeCalculator.NORMAL_PRICE_PRE_1024_BYTES; import static io.nuls.core.constant.CommonCodeConstanst.PARAMETER_ERROR; /** @@ -63,7 +62,6 @@ public class ResetLocalVerifierServiceImpl implements ResetLocalVerifierService LocalVerifierManager localVerifierManager; - /** * Cache reset for heterogeneous chain storage, initialization of main chain validators, validator transactionshash * Used to distinguish from regular initialization validator transactions when processing Byzantine signatures @@ -84,13 +82,15 @@ private CoinData assemblyCoinFrom(Chain chain, String addressStr) throws NulsExc Map result = LedgerCall.getBalanceAndNonce(chain, addressStr, assetChainId, assetId); byte[] nonce = RPCUtil.decode((String) result.get("nonce")); BigInteger balance = new BigInteger(result.get("available").toString()); + + BigInteger NORMAL_PRICE_PRE_1024_BYTES = BigInteger.valueOf(chain.getConfig().getFeeUnit(chain.getChainId(), 1)); if (BigIntegerUtils.isLessThan(balance, NORMAL_PRICE_PRE_1024_BYTES)) { chain.getLogger().error("Insufficient account balance"); throw new NulsException(NulsCrossChainErrorCode.INSUFFICIENT_BALANCE); } CoinData coinData = new CoinData(); coinData.setFrom(List.of(new CoinFrom(address, assetChainId, assetId, NORMAL_PRICE_PRE_1024_BYTES, nonce, NulsCrossChainConstant.UNLOCKED_TX))); - coinData.setTo(List.of(new CoinTo(address,assetChainId,assetId,BigInteger.ZERO))); + coinData.setTo(List.of(new CoinTo(address, assetChainId, assetId, BigInteger.ZERO))); return coinData; } @@ -117,7 +117,7 @@ public Result createResetLocalVerifierTx(int chainId, String address, String pas try { Transaction tx = new Transaction(TxType.RESET_LOCAL_VERIFIER_LIST); tx.setTime(NulsDateUtils.getCurrentTimeSeconds()); - tx.setCoinData(assemblyCoinFrom(chain,address).serialize()); + tx.setCoinData(assemblyCoinFrom(chain, address).serialize()); TransactionSignature transactionSignature = new TransactionSignature(); List p2PHKSignatures = new ArrayList<>(); P2PHKSignature p2PHKSignature = AccountCall.signDigest(address, password, tx.getHash().getBytes()); @@ -244,7 +244,7 @@ public boolean commitTx(int chainId, List txs, BlockHeader blockHea } chain.getLogger().info("Reset the list of validators in this chain completed:{}",chain.getVerifierList()); int syncStatus = BlockCall.getBlockStatus(chain); - List otherChainInfoList = chainManager.getRegisteredCrossChainList().stream().filter(d->d.getChainId() != chainId).collect(Collectors.toList()); + List otherChainInfoList = chainManager.getRegisteredCrossChainList().stream().filter(d -> d.getChainId() != chainId).collect(Collectors.toList()); List newTxList = Lists.newArrayList(); otherChainInfoList.forEach(chainInfo -> { try { @@ -254,12 +254,12 @@ public boolean commitTx(int chainId, List txs, BlockHeader blockHea chain.getLogger().error("Transaction failure in assembling and resetting the main network validator list for parallel chain storage",e); } }); - if(otherChainInfoList.size() != newTxList.size()){ + if (otherChainInfoList.size() != newTxList.size()) { return false; } - newTxList.forEach(initOtherVerifierTx->{ + newTxList.forEach(initOtherVerifierTx -> { chain.getCrossTxThreadPool().execute( - new ResetOtherChainVerifierListHandler(chain, initOtherVerifierTx,syncStatus)); + new ResetOtherChainVerifierListHandler(chain, initOtherVerifierTx, syncStatus)); String txHash = initOtherVerifierTx.getHash().toHex(); resetOtherVerifierTxList.add(txHash); chain.getLogger().info("Initiate a transaction to reset the main chain verifier list stored in parallel chains,txHash:{}",txHash); @@ -268,14 +268,13 @@ public boolean commitTx(int chainId, List txs, BlockHeader blockHea } - @Override public boolean rollbackTx(int chainId, List txs, BlockHeader blockHeader) { Chain chain = chainManager.getChainMap().get(chainId); if (chain == null) { return false; } - return localVerifierService.rollback(chainId,blockHeader.getHeight()); + return localVerifierService.rollback(chainId, blockHeader.getHeight()); } @Override diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/CommonUtil.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/CommonUtil.java index f38e8df5a..9694670cd 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/CommonUtil.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/CommonUtil.java @@ -118,7 +118,7 @@ public static List getMisMatchSigns(Chain chain, TransactionSign iterator.remove(); } } - chain.getLogger().info("Verification successful account list,signedList:{}",signedList); + chain.getLogger().debug("Verification successful account list,signedList:{}",signedList); return misMatchSignList; } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/MessageUtil.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/MessageUtil.java index e5520733c..e337779c4 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/MessageUtil.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/MessageUtil.java @@ -2,6 +2,7 @@ import io.nuls.base.RPCUtil; import io.nuls.base.basic.AddressTool; +import io.nuls.base.data.BlockHeader; import io.nuls.base.data.CoinData; import io.nuls.base.data.NulsHash; import io.nuls.base.data.Transaction; @@ -19,6 +20,7 @@ import io.nuls.crosschain.base.constant.CommandConstant; import io.nuls.crosschain.base.constant.CrossChainConstant; import io.nuls.crosschain.base.message.BroadCtxSignMessage; +import io.nuls.crosschain.base.message.CtxFullSignMessage; import io.nuls.crosschain.base.message.GetOtherCtxMessage; import io.nuls.crosschain.base.model.bo.ChainInfo; import io.nuls.crosschain.base.model.bo.txdata.VerifierChangeData; @@ -95,6 +97,12 @@ public static void handleSignMessage(Chain chain, NulsHash hash, int chainId, St P2PHKSignature p2PHKSignature = new P2PHKSignature(); p2PHKSignature.parse(messageBody.getSignature(), 0); Transaction convertCtx = ctxStatusPO.getTx(); + + if (config.getCrossTxDropTime() > convertCtx.getTime()) { + chain.getLogger().warn("The cross-chain transaction has expired and is no longer processed"); + return; + } + if (!config.isMainNet() && convertCtx.getType() == config.getCrossCtxType()) { convertCtx = convertCtxService.get(hash, handleChainId); } @@ -190,9 +198,16 @@ public static void signByzantine(Chain chain, int chainId, NulsHash realHash, Tr } else { packAddressList = chain.getVerifierList(); } - signByzantineInChain(chain, ctx, signature, packAddressList, realHash, signCountOverflow); + boolean byzantineSignIsDone = signByzantineInChain(chain, ctx, signature, packAddressList, realHash, signCountOverflow); + if (byzantineSignIsDone) { + chain.getLogger().debug("The local Byzantine signature collection is complete and the signature is passed back to the node that sent the signature,to node:{}", excludeNodes); + CtxFullSignMessage ctxFullSignMessage = new CtxFullSignMessage(); + ctxFullSignMessage.setLocalTxHash(realHash); + ctxFullSignMessage.setTransactionSignature(ctx.getTransactionSignature()); + NetWorkCall.sendToNode(chainId, ctxFullSignMessage, excludeNodes, CommandConstant.CROSS_CTX_FULL_SIGN_MESSAGE); + } NetWorkCall.broadcast(chainId, messageBody, excludeNodes, CommandConstant.BROAD_CTX_SIGN_MESSAGE, false); - chain.getLogger().info("Broadcast newly received cross chain transaction signatures to other nodes linked to them,Hash:{},autograph:{}\n\n", nativeHex, signHex); + chain.getLogger().info("Broadcast newly received cross chain transaction signatures to other nodes linked to them,Hash:{} ,autograph:{} ,node: {}", nativeHex, signHex, excludeNodes); } /** @@ -358,7 +373,11 @@ private static boolean crossTransferLocalByzantine( TransactionSignature signature, NulsHash realHash) throws NulsException, IOException { List handleAddressList; - long broadHeight = chainManager.getChainHeaderMap().get(chain.getChainId()).getHeight(); + BlockHeader blockheader = chainManager.getChainHeaderMap().get(chain.getChainId()); + if (null == blockheader) { + chain.getLogger().info("ChainHeaderMap get failed : {} -of- {}", chain.getChainId(), chainManager.getChainHeaderMap().size()); + } + long broadHeight = blockheader.getHeight(); try { chain.getSwitchVerifierLock().readLock().lock(); handleAddressList = new ArrayList<>(chain.getVerifierList()); diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/TxUtil.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/TxUtil.java index f95882fef..2a1335a1e 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/TxUtil.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/TxUtil.java @@ -223,6 +223,11 @@ public static void verifierChangeWait(Chain chain, long height) { */ @SuppressWarnings("unchecked") public static void localCtxByzantine(Transaction ctx, Chain chain) { + if(config.getCrossTxDropTime() > ctx.getTime()){ + chain.getLogger().warn("The cross-chain transaction has expired and is no longer signed locally"); + return ; + } + int chainId = chain.getChainId(); NulsHash hash = ctx.getHash(); try { diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/manager/ChainManager.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/manager/ChainManager.java index 2e7e10f9e..a4669e22f 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/manager/ChainManager.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/manager/ChainManager.java @@ -9,17 +9,17 @@ import io.nuls.core.rockdb.service.RocksDBService; import io.nuls.crosschain.base.model.bo.ChainInfo; import io.nuls.crosschain.base.model.bo.txdata.RegisteredChainMessage; +import io.nuls.crosschain.base.service.ResetLocalVerifierService; import io.nuls.crosschain.constant.NulsCrossChainConstant; import io.nuls.crosschain.model.bo.Chain; import io.nuls.crosschain.model.bo.CmdRegisterDto; import io.nuls.crosschain.rpc.call.BlockCall; import io.nuls.crosschain.rpc.call.SmartContractCall; +import io.nuls.crosschain.srorage.ConvertCtxService; +import io.nuls.crosschain.srorage.CtxStatusService; import io.nuls.crosschain.srorage.RegisteredCrossChainService; import io.nuls.crosschain.utils.LoggerUtil; -import io.nuls.crosschain.utils.thread.handler.GetCtxStateHandler; -import io.nuls.crosschain.utils.thread.handler.HashMessageHandler; -import io.nuls.crosschain.utils.thread.handler.OtherCtxMessageHandler; -import io.nuls.crosschain.utils.thread.handler.SignMessageByzantineHandler; +import io.nuls.crosschain.utils.thread.handler.*; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -37,6 +37,15 @@ public class ChainManager { private NulsCoresConfig config; @Autowired private RegisteredCrossChainService registeredCrossChainService; + + + @Autowired + CtxStatusService ctxStatusService; + + @Autowired + private static ResetLocalVerifierService resetLocalVerifierService; + @Autowired + private ConvertCtxService convertCtxService; /** * Chain cache * Chain cache @@ -136,6 +145,7 @@ public void runChain() { chain.getThreadPool().execute(new OtherCtxMessageHandler(chain)); chain.getThreadPool().execute(new GetCtxStateHandler(chain)); chain.getThreadPool().execute(new SignMessageByzantineHandler(chain)); + chain.getThreadPool().execute(new SaveCtxFullSignHandler(chain,config,ctxStatusService,resetLocalVerifierService,convertCtxService)); int syncStatus = BlockCall.getBlockStatus(chain); chain.getLogger().info("The current status of the node is:{}",syncStatus); chain.setSyncStatus(syncStatus); diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/CrossTxHandler.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/CrossTxHandler.java index 90866dde6..ec714e4ee 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/CrossTxHandler.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/CrossTxHandler.java @@ -14,6 +14,7 @@ public CrossTxHandler(Chain chain, Transaction transaction,int syncStatus){ this.chain = chain; this.transaction = transaction; this.syncStatus = syncStatus; + chain.getLogger().info("TxHash: {}",transaction.getHash().toHex()); } @Override diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/ResetOtherChainVerifierListHandler.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/ResetOtherChainVerifierListHandler.java index 336c1db95..4c2213a2e 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/ResetOtherChainVerifierListHandler.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/ResetOtherChainVerifierListHandler.java @@ -12,18 +12,19 @@ public class ResetOtherChainVerifierListHandler implements Runnable { private Transaction transaction; private int syncStatus; - public ResetOtherChainVerifierListHandler(Chain chain, Transaction transaction, int syncStatus){ + public ResetOtherChainVerifierListHandler(Chain chain, Transaction transaction, int syncStatus) { this.chain = chain; this.transaction = transaction; this.syncStatus = syncStatus; + chain.getLogger().info("TxHash: {}", transaction.getHash().toHex()); } @Override public void run() { - if(syncStatus == 0){ + if (syncStatus == 0) { TxUtil.signAndBroad(chain, transaction); return; } - TxUtil.handleResetOtherVerifierListCtx(transaction,chain); + TxUtil.handleResetOtherVerifierListCtx(transaction, chain); } } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/VerifierChangeTxHandler.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/VerifierChangeTxHandler.java index 9f3dededf..2deb527dc 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/VerifierChangeTxHandler.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/VerifierChangeTxHandler.java @@ -1,4 +1,5 @@ package io.nuls.crosschain.utils.thread; + import io.nuls.base.data.Transaction; import io.nuls.core.exception.NulsException; import io.nuls.crosschain.base.model.bo.txdata.VerifierChangeData; @@ -15,10 +16,11 @@ public class VerifierChangeTxHandler implements Runnable { private Transaction transaction; private long height; - public VerifierChangeTxHandler(Chain chain, Transaction transaction,long height) { + public VerifierChangeTxHandler(Chain chain, Transaction transaction, long height) { this.chain = chain; this.transaction = transaction; this.height = height; + chain.getLogger().info("TxHash: {}", transaction.getHash().toHex()); } @Override @@ -45,7 +47,7 @@ public void run() { } do { Transaction processTx = chain.isExistVerifierChangeTx(transaction); - if(processTx != null){ + if (processTx != null) { VerifierChangeData processTxData = new VerifierChangeData(); try { processTxData.parse(processTx.getTxData(), 0); @@ -126,20 +128,20 @@ private VerifierChangeData mergeVerifierChangeTx(VerifierChangeData txData, Veri * Determine whether the current validator change transaction needs to be split. If the number of exiting nodes is greater than or equal to the current number of nodes30%Then it needs to be split * Judge whether the current verifier's change transaction needs to be split. If the number of exiting nodes is greater than or equal to 30% of the current number of nodes, it needs to be split */ - private void verifierSplitHandle(Chain chain, Transaction transaction,long height, VerifierChangeData txData, boolean txChanged){ + private void verifierSplitHandle(Chain chain, Transaction transaction, long height, VerifierChangeData txData, boolean txChanged) { boolean needSplit = false; int maxCount = 0; int cancelCount = 0; - if(txData.getCancelAgentList() != null && !txData.getCancelAgentList().isEmpty() && txData.getCancelAgentList().size() > 1){ + if (txData.getCancelAgentList() != null && !txData.getCancelAgentList().isEmpty() && txData.getCancelAgentList().size() > 1) { maxCount = chain.getVerifierList().size() * NulsCrossChainConstant.VERIFIER_CANCEL_MAX_RATE / NulsCrossChainConstant.MAGIC_NUM_100; cancelCount = txData.getCancelAgentList().size(); - if(txData.getCancelAgentList().size() > maxCount){ + if (txData.getCancelAgentList().size() > maxCount) { needSplit = true; } } - if(needSplit){ + if (needSplit) { //If the transaction has changed, it has already been sorted before,Sort the validators, then split and exit the validator list - if(!txChanged){ + if (!txChanged) { txData.getCancelAgentList().sort(Comparator.naturalOrder()); } List firstCancelList = txData.getCancelAgentList().subList(0, maxCount); @@ -148,21 +150,21 @@ private void verifierSplitHandle(Chain chain, Transaction transaction,long heigh //The first transaction is prioritized, with a height of the current height, and the second transaction height is after the current height2Two heights to avoid simultaneous broadcasting during broadcasting Transaction firstTx = TxUtil.createVerifierChangeTx(txData.getRegisterAgentList(), firstCancelList, transaction.getTime(), chain.getChainId()); Transaction secondTx = TxUtil.createVerifierChangeTx(new ArrayList<>(), secondCancelList, transaction.getTime(), chain.getChainId()); - chain.getLogger().info("The exit node of the transaction changed by the verifier is greater than 30% of the current node, which is divided into two transactions,firstTx:{},secondTx:{}",firstTx.getHash().toHex(),secondTx.getHash().toHex()); + chain.getLogger().info("The exit node of the transaction changed by the verifier is greater than 30% of the current node, which is divided into two transactions,firstTx:{},secondTx:{}", firstTx.getHash().toHex(), secondTx.getHash().toHex()); chain.getCrossTxThreadPool().execute(new VerifierChangeTxHandler(chain, firstTx, height)); try { TimeUnit.SECONDS.sleep(1); - }catch (InterruptedException e){ + } catch (InterruptedException e) { chain.getLogger().error(e); } chain.getCrossTxThreadPool().execute(new VerifierChangeTxHandler(chain, secondTx, height + 2)); - }catch (IOException e){ + } catch (IOException e) { chain.getLogger().error(e); } - }else{ + } else { try { transaction.setTxData(txData.serialize()); - }catch (IOException e){ + } catch (IOException e) { chain.getLogger().error(e); return; } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/GetCtxStateHandler.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/GetCtxStateHandler.java index e0695fbc6..7eb1611fd 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/GetCtxStateHandler.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/GetCtxStateHandler.java @@ -21,6 +21,7 @@ public void run() { while (chain.getGetCtxStateQueue() != null) { try { UntreatedMessage untreatedMessage = chain.getGetCtxStateQueue().take(); + chain.getLogger().info("TxHash: {}",untreatedMessage.getCacheHash().toHex()); TxUtil.getCtxState(chain, untreatedMessage.getCacheHash()); } catch (Exception e) { chain.getLogger().error(e); diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/HashMessageHandler.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/HashMessageHandler.java index 5a54c02b5..94b5ec4bc 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/HashMessageHandler.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/HashMessageHandler.java @@ -22,7 +22,7 @@ public void run() { try { UntreatedMessage untreatedMessage = chain.getHashMessageQueue().take(); String nativeHex = untreatedMessage.getCacheHash().toHex(); - chain.getLogger().debug("Start processing other chain nodes{}Cross chain transactions broadcasted overHashnews,Hash:{}", untreatedMessage.getNodeId(), nativeHex); + chain.getLogger().info("Start processing other chain nodes{}Cross chain transactions broadcasted overHashnews,Hash:{}", untreatedMessage.getNodeId(), nativeHex); MessageUtil.handleNewHashMessage(chain, untreatedMessage.getCacheHash(), untreatedMessage.getChainId(), untreatedMessage.getNodeId(),nativeHex); }catch (Exception e){ chain.getLogger().error(e); diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/OtherCtxMessageHandler.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/OtherCtxMessageHandler.java index 00c01d876..5d218607d 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/OtherCtxMessageHandler.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/OtherCtxMessageHandler.java @@ -34,12 +34,12 @@ public void run() { otherHash = untreatedMessage.getCacheHash(); String otherHex = otherHash.toHex(); int fromChainId = untreatedMessage.getChainId(); - chain.getLogger().debug("Start processing other chain nodes:{}Cross chain transactions sent,Hash:{}", untreatedMessage.getNodeId(), otherHex); + chain.getLogger().info("Start processing other chain nodes:{}Cross chain transactions sent,Hash:{}", untreatedMessage.getNodeId(), otherHex); boolean handleResult = MessageUtil.handleOtherChainCtx(messageBody.getCtx(), chain, fromChainId); if (!handleResult && chain.getOtherHashNodeIdMap().get(otherHash) != null && !chain.getOtherHashNodeIdMap().get(otherHash).isEmpty()) { regainCtx(chain, fromChainId, otherHash, otherHex); } - chain.getLogger().debug("New transaction processing completed,Hash:{}\n\n", otherHex); + chain.getLogger().info("New transaction processing completed,Hash:{}\n\n", otherHex); } catch (Exception e) { chain.getLogger().error(e); } finally { diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/SaveCtxFullSignHandler.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/SaveCtxFullSignHandler.java new file mode 100644 index 000000000..e0aac927c --- /dev/null +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/SaveCtxFullSignHandler.java @@ -0,0 +1,137 @@ +package io.nuls.crosschain.utils.thread.handler; + +import io.nuls.base.data.NulsHash; +import io.nuls.base.data.Transaction; +import io.nuls.base.signture.P2PHKSignature; +import io.nuls.base.signture.TransactionSignature; +import io.nuls.common.NulsCoresConfig; +import io.nuls.core.constant.TxType; +import io.nuls.core.core.annotation.Autowired; +import io.nuls.core.crypto.ECKey; +import io.nuls.core.crypto.HexUtil; +import io.nuls.crosschain.base.message.CtxFullSignMessage; +import io.nuls.crosschain.base.service.ResetLocalVerifierService; +import io.nuls.crosschain.constant.ParamConstant; +import io.nuls.crosschain.model.bo.Chain; +import io.nuls.crosschain.model.bo.message.UntreatedMessage; +import io.nuls.crosschain.model.po.CtxStatusPO; +import io.nuls.crosschain.rpc.call.ConsensusCall; +import io.nuls.crosschain.srorage.ConvertCtxService; +import io.nuls.crosschain.srorage.CtxStatusService; +import io.nuls.crosschain.utils.CommonUtil; +import io.nuls.crosschain.utils.TxUtil; + +import java.util.ArrayList; +import java.util.List; + +/** + * @description TODO + * @date 2024/6/18 14:55 + * @COPYRIGHT nabox.io + */ +public class SaveCtxFullSignHandler implements Runnable { + + private Chain chain; + + private CtxStatusService ctxStatusService; + + private ResetLocalVerifierService resetLocalVerifierService; + + private ConvertCtxService convertCtxService; + + private NulsCoresConfig config; + + public SaveCtxFullSignHandler( + Chain chain, + NulsCoresConfig config, + CtxStatusService ctxStatusService, + ResetLocalVerifierService resetLocalVerifierService, + ConvertCtxService convertCtxService) { + this.ctxStatusService = ctxStatusService; + this.resetLocalVerifierService = resetLocalVerifierService; + this.config = config; + this.chain = chain; + this.convertCtxService = convertCtxService; + } + + @Override + public void run() { + while (!chain.getTxFullSignMessageQueue().isEmpty()) { + try { + UntreatedMessage untreatedMessage = chain.getTxFullSignMessageQueue().take(); + CtxFullSignMessage message = (CtxFullSignMessage) untreatedMessage.getMessage(); + chain.getLogger().info("Start storing cross-chain transaction signatures pushed by other nodes: localTxHash:{},sign:{}" + , message.getLocalTxHash().toHex() + , HexUtil.encode(message.getTransactionSignature()) + ); + + CtxStatusPO ctxStatusPO = ctxStatusService.get(message.getLocalTxHash(), chain.getChainId()); + if (ctxStatusPO == null) { + chain.getLogger().warn("No corresponding cross-chain transaction was found locally:{}", message.getLocalTxHash().toHex()); + continue; + } + + Transaction tx = ctxStatusPO.getTx(); + List packAddressList = getPackingAddressList(tx, tx.getHash(), chain); + + chain.getLogger().info("Gets the number of validators address listed:{}",packAddressList.size()); + + TransactionSignature localTxSign = new TransactionSignature(); + localTxSign.parse(tx.getTransactionSignature(),0); + chain.getLogger().debug("Gets the number of signatures for local cross-chain transactions:{}",localTxSign.getP2PHKSignatures().size()); + + TransactionSignature messageTxSign = new TransactionSignature(); + messageTxSign.parse(message.getTransactionSignature(),0); + chain.getLogger().debug("Gets the number of signatures contained in the message:{}",messageTxSign.getP2PHKSignatures().size()); + + Transaction convertCtx = ctxStatusPO.getTx(); + if (!config.isMainNet() && convertCtx.getType() == config.getCrossCtxType()) { + convertCtx = convertCtxService.get(message.getLocalTxHash(), chain.getChainId()); + } + chain.getLogger().info("Signature verification hash:{}",convertCtx.getHash().toHex()); + int signVerifyPassNumber = 0; + for (P2PHKSignature sign: messageTxSign.getP2PHKSignatures() + ) { + if (ECKey.verify(convertCtx.getHash().getBytes(), sign.getSignData().getSignBytes(), sign.getPublicKey())) { + localTxSign.getP2PHKSignatures().add(sign); + signVerifyPassNumber++; + } + } + chain.getLogger().debug("Result of verifying the signature in the message,total:{},pass:{}",messageTxSign.getP2PHKSignatures().size(),signVerifyPassNumber); + localTxSign.setP2PHKSignatures(CommonUtil.getMisMatchSigns(chain, localTxSign, packAddressList)); + chain.getLogger().debug("Number of transaction signatures after the merger:{}",localTxSign.getP2PHKSignatures().size()); + + tx.setTransactionSignature(localTxSign.serialize()); + + ctxStatusPO.setTx(tx); + + ctxStatusService.save(message.getLocalTxHash(),ctxStatusPO,chain.getChainId()); + chain.getLogger().info("Save transaction transaction signature:{}",untreatedMessage.getCacheHash().toHex()); + } catch (Exception e) { + chain.getLogger().error("An error occurred processing the full signature pushed by another node",e); + } + } + } + + private List getPackingAddressList(Transaction ctx, NulsHash realHash, Chain chain) { + List packAddressList; + //Byzantine signature saturation increase 0To avoid floating upwards + Float signCountOverflow = 0F; + if (ctx.getType() == TxType.VERIFIER_INIT) { + String txHash = realHash.toHex(); + //This is a special initialization validator transaction, where the user resets the main network validator list stored on the parallel chain + if (resetLocalVerifierService.isResetOtherVerifierTx(txHash)) { + packAddressList = chain.getVerifierList(); + //1To float up to all + signCountOverflow = 1F; + } else { + packAddressList = (List) ConsensusCall.getSeedNodeList(chain).get(ParamConstant.PARAM_PACK_ADDRESS_LIST); + } + } else { + packAddressList = chain.getVerifierList(); + } + return packAddressList; + } + + +} diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/SignMessageByzantineHandler.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/SignMessageByzantineHandler.java index 2fbec8d19..345c886c8 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/SignMessageByzantineHandler.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/thread/handler/SignMessageByzantineHandler.java @@ -1,6 +1,7 @@ package io.nuls.crosschain.utils.thread.handler; import io.nuls.crosschain.base.message.BroadCtxSignMessage; +import io.nuls.crosschain.base.utils.HashSetTimeDuplicateProcessor; import io.nuls.crosschain.model.bo.Chain; import io.nuls.crosschain.model.bo.message.UntreatedMessage; import io.nuls.crosschain.utils.MessageUtil; @@ -12,9 +13,11 @@ * 2019/8/8 */ -public class SignMessageByzantineHandler implements Runnable{ +public class SignMessageByzantineHandler implements Runnable { private Chain chain; + private HashSetTimeDuplicateProcessor processor = new HashSetTimeDuplicateProcessor(1000, 300000L); + public SignMessageByzantineHandler(Chain chain) { this.chain = chain; } @@ -24,9 +27,14 @@ public void run() { while (chain.getSignMessageByzantineQueue() != null) { try { UntreatedMessage untreatedMessage = chain.getSignMessageByzantineQueue().take(); +// if (!processor.insertAndCheck(untreatedMessage.getNodeId() + untreatedMessage.getCacheHash().toHex())) { +// chain.getLogger().info("D discard : " + untreatedMessage.getNodeId() + "," + untreatedMessage.getCacheHash().toHex()); +// continue; +// } + chain.getLogger().info("D process : " + untreatedMessage.getNodeId() + "," + untreatedMessage.getCacheHash().toHex()); String nativeHex = untreatedMessage.getCacheHash().toHex(); chain.getLogger().debug("Start monitoring nodes within the chain{}Cross chain transaction signature message broadcasted for signature Byzantine verification,Hash:{}", untreatedMessage.getNodeId(), nativeHex); - MessageUtil.handleSignMessage(chain, untreatedMessage.getCacheHash(), untreatedMessage.getChainId(), untreatedMessage.getNodeId(),(BroadCtxSignMessage)untreatedMessage.getMessage(), nativeHex); + MessageUtil.handleSignMessage(chain, untreatedMessage.getCacheHash(), untreatedMessage.getChainId(), untreatedMessage.getNodeId(), (BroadCtxSignMessage) untreatedMessage.getMessage(), nativeHex); } catch (Exception e) { chain.getLogger().error(e); } diff --git a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/validator/CrossTxValidator.java b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/validator/CrossTxValidator.java index bb34ececd..d3c420474 100644 --- a/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/validator/CrossTxValidator.java +++ b/module/nuls-cores/src/main/java/io/nuls/crosschain/utils/validator/CrossTxValidator.java @@ -79,7 +79,7 @@ public boolean validateTx(Chain chain, Transaction tx, BlockHeader blockHeader) throw new NulsException(NulsCrossChainErrorCode.TO_ADDRESS_ERROR); } } - + chain.getLogger().info("Cross chain tx : {}",tx.getHash().toHex()); if(toChainId == 0){ throw new NulsException(NulsCrossChainErrorCode.TO_ADDRESS_ERROR); } diff --git a/module/nuls-cores/src/main/java/io/nuls/ledger/rpc/cmd/AssetsRegTxCmd.java b/module/nuls-cores/src/main/java/io/nuls/ledger/rpc/cmd/AssetsRegTxCmd.java index a04510ba7..325152ce5 100644 --- a/module/nuls-cores/src/main/java/io/nuls/ledger/rpc/cmd/AssetsRegTxCmd.java +++ b/module/nuls-cores/src/main/java/io/nuls/ledger/rpc/cmd/AssetsRegTxCmd.java @@ -56,6 +56,8 @@ import java.util.HashMap; import java.util.Map; +import static io.nuls.common.CommonConstant.NORMAL_PRICE_PRE_1024_BYTES_NULS; + /** * Asset registration and management interface * @@ -89,7 +91,7 @@ CoinData getRegCoinData(BigInteger destroyAsset, byte[] address, int chainId, in coinData.addFrom(from); txSize += to.size(); txSize += from.size(); - BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize); + BigInteger fee = TransactionFeeCalculator.getNormalTxFee(txSize, NORMAL_PRICE_PRE_1024_BYTES_NULS); BigInteger fromAmount = destroyAssetTx.add(fee); if (BigIntegerUtils.isLessThan(accountState.getAvailableAmount(), fromAmount)) { throw new NulsRuntimeException(LedgerErrorCode.BALANCE_NOT_ENOUGH); diff --git a/module/nuls-cores/src/main/java/io/nuls/network/manager/MessageManager.java b/module/nuls-cores/src/main/java/io/nuls/network/manager/MessageManager.java index f862d8e30..3a46a3dc6 100644 --- a/module/nuls-cores/src/main/java/io/nuls/network/manager/MessageManager.java +++ b/module/nuls-cores/src/main/java/io/nuls/network/manager/MessageManager.java @@ -29,9 +29,12 @@ import io.netty.channel.ChannelFuture; import io.nuls.base.basic.NulsByteBuffer; import io.nuls.base.data.BaseNulsData; +import io.nuls.core.crypto.HexUtil; import io.nuls.core.crypto.Sha256Hash; +import io.nuls.core.exception.NulsException; import io.nuls.core.log.Log; import io.nuls.core.model.ByteUtils; +import io.nuls.crosschain.base.message.GetOtherCtxMessage; import io.nuls.network.constant.ManagerStatusEnum; import io.nuls.network.constant.NetworkConstant; import io.nuls.network.constant.NetworkErrorCode; @@ -46,6 +49,7 @@ import io.nuls.network.model.dto.PeerCacheMessage; import io.nuls.network.model.message.AddrMessage; import io.nuls.network.model.message.GetAddrMessage; +import io.nuls.network.model.message.VersionMessage; import io.nuls.network.model.message.base.BaseMessage; import io.nuls.network.model.message.base.MessageHeader; import io.nuls.network.utils.LoggerUtil; @@ -133,11 +137,13 @@ private boolean validate(byte[] data, long pChecksum) { public void receiveMessage(NulsByteBuffer byteBuffer, Node node) { //Unified message reception and processing + if (null == byteBuffer) { + return; + } + MessageHeader header = new MessageHeader(); + BaseMessage message = null; try { - if (null == byteBuffer) { - return; - } - MessageHeader header = new MessageHeader(); + int headerSize = header.size(); byte[] payLoad = byteBuffer.getPayload(); byte[] payLoadBody = ByteUtils.subBytes(payLoad, headerSize, payLoad.length - headerSize); @@ -148,17 +154,19 @@ public void receiveMessage(NulsByteBuffer byteBuffer, Node node) { LoggerUtil.logger(chainId).error("validate false ======================cmd:{}", header.getCommandStr()); return; } - BaseMessage message = MessageManager.getInstance().getMessageInstance(header.getCommandStr()); + message = MessageManager.getInstance().getMessageInstance(header.getCommandStr()); byteBuffer.setCursor(0); while (!byteBuffer.isFinished()) { NetworkEventResult result = null; if (null != message) { message = byteBuffer.readNulsData(message); BaseMeesageHandlerInf handler = MessageHandlerFactory.getInstance().getHandler(header.getCommandStr()); +// Log.info("RecieveMessage1 : {}, {} ,{}", header.getCommandStr(), message.getClass().getTypeName(), handler.getClass().getTypeName()); result = handler.recieve(message, node); } else { //External messages, converting to external interfaces OtherModuleMessageHandler handler = MessageHandlerFactory.getInstance().getOtherModuleHandler(); +// Log.info("RecieveMessage2 : {}, {}˚", header.getCommandStr(), handler.getClass().getTypeName()); result = handler.recieve(header, payLoadBody, node); byteBuffer.setCursor(payLoad.length); } @@ -167,11 +175,16 @@ public void receiveMessage(NulsByteBuffer byteBuffer, Node node) { } } } catch (Exception e) { - Log.error("node={},{}", node.getId(), e); + if (null != message) { + Log.error("node==={} , {} , {} , {}", node.getId(), HexUtil.encode(byteBuffer.getPayload()), header.getCommandStr(), message.getClass().getTypeName()); + } else { + Log.error("node==={} , {} , {}", node.getId(), HexUtil.encode(byteBuffer.getPayload()), header.getCommandStr()); + } + Log.error("", e); + } } - public NetworkEventResult broadcastSelfAddrToAllNode(Collection connectNodes, IpAddressShare ipAddress, boolean isCrossAddress, boolean asyn) { for (Node connectNode : connectNodes) { List addressesList = new ArrayList<>(); @@ -237,7 +250,7 @@ public void sendGetCrossAddressMessage(NodeGroup connectNodeGroup, NodeGroup mes for (Node node : nodes) { if (NodeConnectStatusEnum.AVAILABLE == node.getConnectStatus()) { GetAddrMessage getAddrMessage = MessageFactory.getInstance() - .buildGetAddrMessage(messageNodeGroup.getChainId(),connectNodeGroup.getMagicNumber(), isCrossAddress); + .buildGetAddrMessage(messageNodeGroup.getChainId(), connectNodeGroup.getMagicNumber(), isCrossAddress); sendHandlerMsg(getAddrMessage, node, asyn); } } diff --git a/module/nuls-cores/src/main/java/io/nuls/network/model/message/base/MessageHeader.java b/module/nuls-cores/src/main/java/io/nuls/network/model/message/base/MessageHeader.java index 9fc611b6b..771924844 100644 --- a/module/nuls-cores/src/main/java/io/nuls/network/model/message/base/MessageHeader.java +++ b/module/nuls-cores/src/main/java/io/nuls/network/model/message/base/MessageHeader.java @@ -28,6 +28,8 @@ import io.nuls.base.basic.NulsByteBuffer; import io.nuls.base.basic.NulsOutputStreamBuffer; import io.nuls.base.data.BaseNulsData; +import io.nuls.contract.util.Log; +import io.nuls.core.crypto.HexUtil; import io.nuls.core.exception.NulsException; import io.nuls.core.parse.SerializeUtils; @@ -134,6 +136,7 @@ public void parse(NulsByteBuffer buffer) throws NulsException { command = buffer.readBytes(12); checksum = buffer.readUint32(); } catch (Exception e) { + Log.error("Message error: {}", HexUtil.encode(buffer.getPayload())); throw new NulsException(e); } } diff --git a/module/nuls-cores/src/main/java/io/nuls/network/model/message/body/VersionMessageBody.java b/module/nuls-cores/src/main/java/io/nuls/network/model/message/body/VersionMessageBody.java index 3da08c62b..0a2ebf1bb 100644 --- a/module/nuls-cores/src/main/java/io/nuls/network/model/message/body/VersionMessageBody.java +++ b/module/nuls-cores/src/main/java/io/nuls/network/model/message/body/VersionMessageBody.java @@ -86,6 +86,9 @@ public void parse(NulsByteBuffer buffer) throws NulsException { blockHeight = buffer.readUint32(); blockHash = buffer.readString(); extend = buffer.readString(); + if(!buffer.isFinished()){ + buffer.readByte(); + } } catch (Exception e) { throw new NulsException(e); } diff --git a/module/nuls-cores/src/main/java/io/nuls/network/rpc/cmd/MessageRpc.java b/module/nuls-cores/src/main/java/io/nuls/network/rpc/cmd/MessageRpc.java index e0007b9a8..9a71b1b36 100644 --- a/module/nuls-cores/src/main/java/io/nuls/network/rpc/cmd/MessageRpc.java +++ b/module/nuls-cores/src/main/java/io/nuls/network/rpc/cmd/MessageRpc.java @@ -149,7 +149,7 @@ public Response broadcast(Map params) { MessageManager messageManager = MessageManager.getInstance(); NodeGroup nodeGroup = NodeGroupManager.getInstance().getNodeGroupByChainId(chainId); if (null == nodeGroup) { - LoggerUtil.logger(chainId).error("chain is not exist!"); +// LoggerUtil.logger(chainId).error("chain is not exist!"); return failed(NetworkErrorCode.PARAMETER_ERROR); } long magicNumber = nodeGroup.getMagicNumber(); diff --git a/module/nuls-cores/src/main/java/io/nuls/transaction/service/impl/TxServiceImpl.java b/module/nuls-cores/src/main/java/io/nuls/transaction/service/impl/TxServiceImpl.java index d2ecd7388..3f18f00f5 100644 --- a/module/nuls-cores/src/main/java/io/nuls/transaction/service/impl/TxServiceImpl.java +++ b/module/nuls-cores/src/main/java/io/nuls/transaction/service/impl/TxServiceImpl.java @@ -33,6 +33,7 @@ import io.nuls.base.protocol.TxRegisterDetail; import io.nuls.base.signture.MultiSignTxSignature; import io.nuls.base.signture.SignatureUtil; +import io.nuls.contract.config.ContractContext; import io.nuls.core.constant.BaseConstant; import io.nuls.core.constant.ErrorCode; import io.nuls.core.constant.TxStatusEnum; @@ -767,25 +768,53 @@ private void validateFee(Chain chain, int type, int txSize, CoinData coinData, T //When initiating a chain for cross chain transactions and not for transactions,Calculate the main assets of the main network as transaction feesNULS feeAssetChainId = txConfig.getMainChainId(); feeAssetId = txConfig.getMainAssetId(); + BigInteger fee = coinData.getFeeByAsset(feeAssetChainId, feeAssetId); + if (BigIntegerUtils.isEqualOrLessThan(fee, BigInteger.ZERO)) { + throw new NulsException(TxErrorCode.INSUFFICIENT_FEE); + } + //根据交易大小重新计算手续费,用来验证实际手续费 + BigInteger targetFee; + if (TxManager.isCrossTx(type)) { + targetFee = TransactionFeeCalculator.getCrossTxFee(txSize); + } else { + targetFee = TransactionFeeCalculator.getNormalTxFee(txSize, chain.getConfig().getFeeUnit(feeAssetChainId, feeAssetId)); + } + if (BigIntegerUtils.isLessThan(fee, targetFee)) { + throw new NulsException(TxErrorCode.INSUFFICIENT_FEE); + } } else { - //Calculate the main asset as a handling fee - feeAssetChainId = chain.getConfig().getChainId(); - feeAssetId = chain.getConfig().getAssetId(); - } - BigInteger fee = coinData.getFeeByAsset(feeAssetChainId, feeAssetId); - if (BigIntegerUtils.isEqualOrLessThan(fee, BigInteger.ZERO)) { - throw new NulsException(TxErrorCode.INSUFFICIENT_FEE); - } + boolean result = false; + Set set = chain.getConfig().getFeeAssetsSet(); + for (String tokenId : set) { + String[] arr = tokenId.split("-"); + //Calculate the main asset as a handling fee + feeAssetChainId = Integer.parseInt(arr[0]); + feeAssetId = Integer.parseInt(arr[1]); + if (feeAssetId != 1 && ProtocolGroupManager.getCurrentVersion(chain.getChainId()) < ContractContext.PROTOCOL_20) { + continue; + } + BigInteger fee = coinData.getFeeByAsset(feeAssetChainId, feeAssetId); + if (BigIntegerUtils.isEqualOrLessThan(fee, BigInteger.ZERO)) { + continue; + } //Recalculate transaction fees based on transaction size to verify actual transaction fees - BigInteger targetFee; - if (TxManager.isCrossTx(type)) { - targetFee = TransactionFeeCalculator.getCrossTxFee(txSize); - } else { - targetFee = TransactionFeeCalculator.getNormalTxFee(txSize); - } - if (BigIntegerUtils.isLessThan(fee, targetFee)) { - throw new NulsException(TxErrorCode.INSUFFICIENT_FEE); + BigInteger targetFee; + if (TxManager.isCrossTx(type)) { + targetFee = TransactionFeeCalculator.getCrossTxFee(txSize); + } else { + targetFee = TransactionFeeCalculator.getNormalTxFee(txSize, chain.getConfig().getFeeUnit(feeAssetChainId, feeAssetId)); + } + if (BigIntegerUtils.isLessThan(fee, targetFee)) { + continue; + } + result = true; + break; + } + if (!result) { + throw new NulsException(TxErrorCode.INSUFFICIENT_FEE); + } } + } /** diff --git a/module/nuls-cores/src/main/resources/protocol-config.json b/module/nuls-cores/src/main/resources/protocol-config.json index 72fa8c63c..8aabe1a86 100644 --- a/module/nuls-cores/src/main/resources/protocol-config.json +++ b/module/nuls-cores/src/main/resources/protocol-config.json @@ -1,4 +1,28 @@ [ + { + "version": "20", + "extend": "19", + "validTxs": [ + { + "type": "15", + "systemTx": false, + "unlockTx": false, + "verifySignature": true, + "verifyFee": true, + "handler": "CreateContractProcessorV20" + }, + { + "type": "16", + "systemTx": false, + "unlockTx": false, + "verifySignature": true, + "verifyFee": true, + "handler": "CallContractProcessorV20" + }], + "validMsgs": [], + "invalidTxs": "", + "invalidMsgs": "" + }, { "version": "19", "extend": "18", @@ -819,4 +843,4 @@ "invalidTxs": "", "invalidMsgs": "" } -] +] \ No newline at end of file diff --git a/module/nuls-cores/src/main/resources/protocol/versions.json b/module/nuls-cores/src/main/resources/protocol/versions.json index 6b5ecff50..7567e0ca4 100644 --- a/module/nuls-cores/src/main/resources/protocol/versions.json +++ b/module/nuls-cores/src/main/resources/protocol/versions.json @@ -93,5 +93,10 @@ "version": "19", "effectiveRatio": "80", "continuousIntervalCount": "10" + }, + { + "version": "20", + "effectiveRatio": "80", + "continuousIntervalCount": "10" } -] +] \ No newline at end of file diff --git a/module/nuls-cores/src/test/java/io/nuls/contract/tx/multyasset/ContractMultyAssetTest.java b/module/nuls-cores/src/test/java/io/nuls/contract/tx/multyasset/ContractMultyAssetTest.java index 3e6b75139..8ca65960f 100644 --- a/module/nuls-cores/src/test/java/io/nuls/contract/tx/multyasset/ContractMultyAssetTest.java +++ b/module/nuls-cores/src/test/java/io/nuls/contract/tx/multyasset/ContractMultyAssetTest.java @@ -539,7 +539,7 @@ protected void callTxOfflineBase(List txSingers, List froms, tx.setCoinData(coinData.serialize()); tx.setTxData(callContractData.serialize()); - BigInteger txSizeFee = TransactionFeeCalculator.getNormalUnsignedTxFee(tx.getSize() + 130 * froms.size()); + BigInteger txSizeFee = TransactionFeeCalculator.getNormalUnsignedTxFee(tx.getSize() + 130 * froms.size(),100000,1); feeAccountFrom.setAmount(feeAccountFrom.getAmount().add(txSizeFee)); /*if (feeAccountBalance.getBalance().compareTo(feeValue) < 0) { // Insufficient balance diff --git a/module/nuls-cores/src/test/java/io/nuls/contract/tx/offline/ContractMultyAssetOfflineTest.java b/module/nuls-cores/src/test/java/io/nuls/contract/tx/offline/ContractMultyAssetOfflineTest.java index 5072fd26c..34d4b9fe3 100644 --- a/module/nuls-cores/src/test/java/io/nuls/contract/tx/offline/ContractMultyAssetOfflineTest.java +++ b/module/nuls-cores/src/test/java/io/nuls/contract/tx/offline/ContractMultyAssetOfflineTest.java @@ -80,7 +80,6 @@ public class ContractMultyAssetOfflineTest { protected String apiURL = "http://beta.api.nuls.io/"; - /** * Multiple account call contracts - Transfer in */ @@ -200,7 +199,7 @@ protected void callTxOffline(String feeAccount, String feeAccountPri, BigInteger value, String contractAddress, String methodName, String methodDesc, String remark, - Object[] args, String[] argsType, ProgramMultyAssetValue[] multyAssetValues, boolean isBroadcastTx) throws Exception{ + Object[] args, String[] argsType, ProgramMultyAssetValue[] multyAssetValues, boolean isBroadcastTx) throws Exception { List txSingers = new ArrayList<>(); SignDto dto1 = new SignDto(); dto1.setAddress(contractSender); @@ -257,11 +256,11 @@ private ContractBalance getUnConfirmedBalanceAndNonce(int chainId, int assetId, * Spending the same asset on two accounts */ protected void callTxOfflineII(String feeAccount, String feeAccountPri, - String contractSender, String contractSenderPri, - BigInteger value, String contractAddress, - String methodName, String methodDesc, - String remark, - Object[] args, String[] argsType, ProgramMultyAssetValue[] multyAssetValues, boolean isBroadcastTx) throws Exception{ + String contractSender, String contractSenderPri, + BigInteger value, String contractAddress, + String methodName, String methodDesc, + String remark, + Object[] args, String[] argsType, ProgramMultyAssetValue[] multyAssetValues, boolean isBroadcastTx) throws Exception { List txSingers = new ArrayList<>(); SignDto dto1 = new SignDto(); dto1.setAddress(contractSender); @@ -322,16 +321,16 @@ protected void callTxOfflineII(String feeAccount, String feeAccountPri, protected void callTxOfflineBase(List txSingers, List froms, List tos, - String feeAccount, - String contractSender, - BigInteger value, String contractAddress, - String methodName, String methodDesc, - String remark, - Object[] args, String[] argsType, boolean isBroadcastTx) throws Exception{ + String feeAccount, + String contractSender, + BigInteger value, String contractAddress, + String methodName, String methodDesc, + String remark, + Object[] args, String[] argsType, boolean isBroadcastTx) throws Exception { // Generate a two-dimensional array of parameters String[][] finalArgs = null; if (args != null && args.length > 0) { - if(argsType == null || argsType.length != args.length) { + if (argsType == null || argsType.length != args.length) { Assert.assertTrue("size of 'argsType' array not match 'args' array", false); } finalArgs = ContractUtil.twoDimensionalArray(args, argsType); @@ -393,7 +392,7 @@ protected void callTxOfflineBase(List txSingers, List froms, tx.setCoinData(coinData.serialize()); tx.setTxData(callContractData.serialize()); - BigInteger txSizeFee = TransactionFeeCalculator.getNormalUnsignedTxFee(tx.getSize() + 130 * froms.size()); + BigInteger txSizeFee = TransactionFeeCalculator.getNormalUnsignedTxFee(tx.getSize() + 130 * froms.size(), 100000, 1); feeAccountFrom.setAmount(feeAccountFrom.getAmount().add(txSizeFee)); /*if (feeAccountBalance.getBalance().compareTo(feeValue) < 0) { // Insufficient balance diff --git a/pom.xml b/pom.xml index cbef15ed4..f1514fc01 100644 --- a/pom.xml +++ b/pom.xml @@ -139,11 +139,11 @@ maven-releases - http://nexus.nuls.io/repository/nuls-release/ + https://nexus.nuls.io/repository/nuls-release/ maven-snapshots - http://nexus.nuls.io/repository/nuls-snapshot/ + https://nexus.nuls.io/repository/nuls-snapshot/ diff --git a/version b/version index 92aa628bc..a4cc673ab 100644 --- a/version +++ b/version @@ -1 +1 @@ -2.19.0 \ No newline at end of file +2.20.0 \ No newline at end of file