diff --git a/.ci/check_rare_string.sh b/.ci/check_rare_string.sh new file mode 100644 index 00000000..1707abee --- /dev/null +++ b/.ci/check_rare_string.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +concatenatedString=$1 + +function LOG_ERROR() +{ + local content=${1} + echo -e "\033[31m"${content}"\033[0m" +} + +function LOG_INFO() +{ + local content=${1} + echo -e "\033[32m"${content}"\033[0m" +} + +get_md5sum_cmd() { + local md5sum_cmd="md5sum" + if [ "$(uname)" == "Darwin" ]; then + md5sum_cmd="md5" + fi + echo "$md5sum_cmd" +} + +function checkConcatenatedRareString() { + local contract_address=${1} + md5sum_cmd=$(get_md5sum_cmd) + + md5_concatenatedString=$(echo -n "$concatenatedString" | $md5sum_cmd | awk '{print $1}') + + local set_output=$(./dist/console.sh call HelloWorld "${contract_address}" set "${concatenatedString}") + eventLogsFromSet=$(echo "set_output" | grep -o 'Event: {}' | sed 's/Event: {\(.*\)}/\1/') + if [ ! -z "$eventLogsFromSet" ]; then + echo "eventLogsFromSet=${eventLogsFromSet}" + md5_eventLogsFromSet=$(echo -n "$eventLogsFromSet" | $md5sum_cmd | awk '{print $1}') + if [ "$md5_concatenatedString" != "$md5_eventLogsFromSet" ]; then + LOG_ERROR "error: check failed, the md5 values of rareString and eventLogsFromSet are not equal, fail concatenatedString: ${concatenatedString}" + exit 1 + fi + fi + + # compare rare string and stringFromGet + get_output=$(./dist/console.sh call HelloWorld "${contract_address}" get) + stringFromGet=$(echo "$get_output" | grep "Return values" | sed 's/Return values:\(.*\)/\1/' | tr -d '()') + md5_stringFromGet=$(echo -n "$stringFromGet" | $md5sum_cmd | awk '{print $1}') + if [ "$md5_concatenatedString" != "$md5_stringFromGet" ]; then + LOG_ERROR "error: check failed, the md5 values of rareString and stringFromGet are not equal, fail concatenatedString: ${concatenatedString}" + exit 1 + else + LOG_INFO "check success, concatenatedString: ${concatenatedString}" + fi +} + +main() { + LOG_INFO "check rare string start, concatenatedString: ${concatenatedString}" + + # deploy HelloWorld contract + console_output=$(./dist/console.sh deploy HelloWorld) + contract_address=$(echo "$console_output" | grep -oE 'contract address: 0x[0-9a-fA-F]+' | sed 's/contract address: //') + if [ -z "$contract_address" ]; then + LOG_ERROR "deploy HelloWorld contract failed, contract_address: ${contract_address}" + exit 1 + fi + + checkConcatenatedRareString $contract_address + LOG_INFO "check rare string finished!" +} + +main "$@" diff --git a/.ci/ci_check.sh b/.ci/ci_check.sh index a8d8fddc..42efcdb8 100755 --- a/.ci/ci_check.sh +++ b/.ci/ci_check.sh @@ -1,6 +1,10 @@ #!/bin/bash set -e + +rare_str_range_names=("CJKUnifiedIdeographs" "CJKCompatibilityIdeographs" "CJKCompatibilityIdeographsSupplement" "KangxiRadicals" "CJKRadicalsSupplement" "IdeographicDescriptionCharacters" "Bopomofo" "BopomofoExtended" "CJKStrokes" "CJKSymbolsandPunctuation" "CJKCompatibilityForms" "CJKCompatibility" "EnclosedCJKLettersandMonths" "CJKUnifiedIdeographsExtensionA" "CJKUnifiedIdeographsExtensionB" "CJKUnifiedIdeographsExtensionC" "CJKUnifiedIdeographsExtensionD" "CJKUnifiedIdeographsExtensionE" "CJKUnifiedIdeographsExtensionF") +rare_str_range_values=("19968,40959" "63744,64255" "194560,195103" "12032,12255" "11904,12031" "12272,12287" "12544,12591" "12704,12735" "12736,12783" "12288,12351" "65072,65103" "13056,13311" "12800,13055" "13312,19903" "131072,173791" "173824,177977" "177984,178205" "178208,183969" "183984,191456") + LOG_INFO() { local content=${1} echo -e "\033[32m ${content}\033[0m" @@ -28,6 +32,11 @@ get_sed_cmd() echo "$sed_cmd" } +download_rare_string_jar() { + LOG_INFO "----- Downloading get-rare-string-with-unicode.jar -------" + curl -LO "https://github.com/FISCO-BCOS/LargeFiles/raw/master/binaries/jar/get-rare-string-with-unicode.jar" +} + download_build_chain() { local tag="${1}" @@ -83,6 +92,51 @@ clean_node() fi } +getRangeValues() { + local rangeValue=$1 + IFS=',' read -r startValue endValue <<<"$rangeValue" + + echo "$startValue $endValue" +} + +getConcatenatedRareStringWithRange() { + local startUnicode=${1} + local endUnicode=${2} + + # concatenate strings with begin middle end + local concatenatedString=$(java -cp './get-rare-string-with-unicode.jar' org.example.Main ${startUnicode}) + local midUnicode=$((($startUnicode + $endUnicode) / 2)) + for ((i = midUnicode; i <= midUnicode + 5; i++)); do + local currentRareString=$(java -cp './get-rare-string-with-unicode.jar' org.example.Main ${i}) + concatenatedString+="$currentRareString" + done + local endRareString=$(java -cp './get-rare-string-with-unicode.jar' org.example.Main ${endUnicode}) + concatenatedString+="$endRareString" + echo "$concatenatedString" +} + +check_rare_string() { + download_rare_string_jar + bash gradlew assemble + cp ./src/integration-test/resources/config.toml ./dist/conf/config.toml + cp -r ./nodes/127.0.0.1/sdk/* ./dist/conf/ + export LC_ALL=en_US.UTF-8 + export LANG=en_US.UTF-8 + export LANGUAGE=en_US.UTF-8 + + finalConcatenatedInputString="" + for ((i = 0; i < ${#rare_str_range_names[@]}; i++)); do + rangeName="${rare_str_range_names[$i]}" + rangeValue="${rare_str_range_values[$i]}" + + read -r startValue endValue <<<$(getRangeValues "$rangeValue") + concatenatedString=$(getConcatenatedRareStringWithRange $startValue $endValue) + finalConcatenatedInputString+="$concatenatedString" + done + + bash -x .ci/check_rare_string.sh ${finalConcatenatedInputString} +} + check_standard_node() { build_node ${@:2} @@ -90,6 +144,8 @@ check_standard_node() ## run integration test bash gradlew test --info bash gradlew integrationTest --info + LOG_INFO "------ standard_node check_rare_string---------" + check_rare_string clean_node "${1}" } @@ -100,6 +156,8 @@ check_sm_node() ## run integration test bash gradlew test --info bash gradlew integrationTest --info + LOG_INFO "------ standard_node check_rare_string---------" + check_rare_string clean_node "${1}" } diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index f226f62d..2e4455e2 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -29,7 +29,7 @@ jobs: uses: actions/setup-java@v3 with: distribution: 'zulu' - java-version: '8.0.345' + java-version: '8.0.382' - name: run build test if: runner.os == 'Windows' run: ./gradlew.bat build @@ -51,12 +51,12 @@ jobs: with: fetch-depth: 5 - name: install CentOS dependencies - run: yum install -y epel-release centos-release-scl which git openssl-devel openssl wget + run: yum install -y epel-release centos-release-scl which git openssl-devel openssl wget - name: Set up JDK 1.8 uses: actions/setup-java@v3 with: distribution: 'zulu' - java-version: '8.0.345' + java-version: '8.0.382' - name: run integration testing run: /bin/bash -x .ci/ci_check.sh - name: upload coverage diff --git a/.gitignore b/.gitignore index b34ef949..746392e9 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,4 @@ bin/** /account /build_chain.sh /deploylog.txt +/bin/ diff --git a/build.gradle b/build.gradle index ede5592a..beeb9f16 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,9 @@ plugins { id 'com.github.sherter.google-java-format' version '0.8' + id 'java-library' + id 'java' } -apply plugin: 'maven' +apply plugin: 'maven-publish' apply plugin: 'java' apply plugin: 'eclipse' @@ -13,7 +15,7 @@ targetCompatibility = 1.8 repositories { mavenCentral() - maven { url "http://maven.aliyun.com/nexus/content/groups/public/" } + maven { url "https://maven.aliyun.com/nexus/content/groups/public/" } maven { url "https://oss.sonatype.org/service/local/staging/deploy/maven2" } maven { url "https://oss.sonatype.org/content/repositories/snapshots" } } @@ -34,32 +36,32 @@ List logger = [ // In this section you declare the dependencies for your production and test code dependencies { - compile logger - //compile 'org.fisco-bcos:solcJ:0.4.25.1' - //compile 'org.fisco-bcos:solcJ:0.6.10.1' - //compile 'org.fisco-bcos:solcJ:0.5.2.1' - compile 'org.fisco-bcos:solcJ:0.8.11.1' + implementation logger + //implementation 'org.fisco-bcos:solcJ:0.4.25.1' + //implementation 'org.fisco-bcos:solcJ:0.6.10.1' + //implementation 'org.fisco-bcos:solcJ:0.5.2.1' + implementation 'org.fisco-bcos:solcJ:0.8.11.1' - compile('org.fisco-bcos.java-sdk:fisco-bcos-java-sdk:3.5.0') { + implementation ('org.fisco-bcos.java-sdk:fisco-bcos-java-sdk:3.6.0-SNAPSHOT') { exclude group: "org.slf4j" } - compile('org.fisco-bcos:evm-static-analysis:1.0.0') { - exclude group: "org.slf4j" + implementation('org.fisco-bcos:evm-static-analysis:1.0.0') { + exclude group: "org.slf4j" } - compile('commons-cli:commons-cli:1.5.0') - compile('org.jline:jline:3.21.0') - compile('io.bretty:console-table-builder:1.2') - compile('com.github.jsqlparser:jsqlparser:2.0') - compile('org.fisco-bcos.code-generator:bcos-code-generator:1.2.0') { + implementation('commons-cli:commons-cli:1.5.0') + implementation('org.jline:jline:3.21.0') + implementation('io.bretty:console-table-builder:1.2') + implementation('com.github.jsqlparser:jsqlparser:2.0') + implementation('org.fisco-bcos.code-generator:bcos-code-generator:1.3.0-SNAPSHOT') { exclude group: "org.fisco-bcos.java-sdk" exclude group: "org.slf4j" } - compile ('com.fasterxml.jackson.core:jackson-databind:2.14.3'){ + implementation ('com.fasterxml.jackson.core:jackson-databind:2.14.3'){ force true } - testCompile('com.github.stefanbirkner:system-rules:1.19.0') - testCompile('junit:junit:4.13.2') + testImplementation('com.github.stefanbirkner:system-rules:1.19.0') + testImplementation('junit:junit:4.13.2') } configurations.all { @@ -88,7 +90,7 @@ sourceSets { } } configurations { - integrationTestCompile.extendsFrom testCompile + integrationTestCompile.extendsFrom testImplementation integrationTestRuntime.extendsFrom testRuntime } @@ -99,7 +101,7 @@ task integrationTest(type: Test) { jar { destinationDir file('dist/apps') - archiveName project.name + '.jar' + archiveFileName=project.name + '.jar' exclude '**/*.xml' exclude '**/*.properties' exclude '**/*.crt' @@ -107,7 +109,7 @@ jar { doLast { copy { - from configurations.runtime + from configurations.runtimeClasspath into 'dist/lib' } copy { diff --git a/release_note.txt b/release_note.txt index c0c4025d..130165bc 100644 --- a/release_note.txt +++ b/release_note.txt @@ -1 +1 @@ -v3.5.0 +v3.6.0 diff --git a/src/integration-test/java/console/ConsoleClientTest.java b/src/integration-test/java/console/ConsoleClientTest.java index 18298a3b..aa3c325c 100644 --- a/src/integration-test/java/console/ConsoleClientTest.java +++ b/src/integration-test/java/console/ConsoleClientTest.java @@ -184,10 +184,10 @@ public void clientWithParamsTest() throws Exception { String[] txHashParams = {"", transactionHash}; // tx consoleClientFace.getTransactionByHash(txHashParams); - Assert.assertTrue(log.getLog().contains("hash='" + transactionHash + "'")); + Assert.assertTrue(log.getLog().contains(transactionHash)); log.clearLog(); consoleClientFace.getTransactionByHashWithProof(txHashParams); - Assert.assertTrue(log.getLog().contains("hash='" + transactionHash + "'")); + Assert.assertTrue(log.getLog().contains(transactionHash)); log.clearLog(); // receipt diff --git a/src/main/java/console/Console.java b/src/main/java/console/Console.java index 37e4b756..ac34fa1e 100644 --- a/src/main/java/console/Console.java +++ b/src/main/java/console/Console.java @@ -53,7 +53,7 @@ public static void main(String[] args) { } consoleInitializer.setLineReader(lineReader); } catch (Exception e) { - e.printStackTrace(); + System.out.println("Failed to initialize console, msg: " + e.getMessage()); logger.error(" message: {}", e.getMessage(), e); System.exit(-1); } diff --git a/src/main/java/console/ConsoleInitializer.java b/src/main/java/console/ConsoleInitializer.java index 3a8920e3..af7a03aa 100644 --- a/src/main/java/console/ConsoleInitializer.java +++ b/src/main/java/console/ConsoleInitializer.java @@ -45,6 +45,7 @@ public class ConsoleInitializer { private CollaborationFace collaborationFace; private boolean disableAutoCompleter = false; private LineReader lineReader; + private boolean useV1TxService; public LineReader getLineReader() { return lineReader; @@ -69,9 +70,14 @@ public void init(String[] args) throws ConfigException { accountInfo = loadConfig(args); loadAccountInfo(accountInfo, groupID); + + if (args.length > 3 && "-v1".equals(args[3])) { + // use v1 transaction service + useV1TxService = true; + } this.consoleClientFace = new ConsoleClientImpl(client); this.precompiledFace = new PrecompiledImpl(client); - this.consoleContractFace = new ConsoleContractImpl(client); + this.consoleContractFace = new ConsoleContractImpl(client, useV1TxService); this.collaborationFace = new CollaborationImpl(client); this.authFace = new AuthImpl(client); } @@ -140,7 +146,7 @@ private AccountInfo loadConfig(String[] args) throws ConfigException { return new AccountInfo("HSM", "", ""); } - if (args.length == 3) { + if (args.length >= 3) { return loadAccount(bcosSDK, args); } } catch (NumberFormatException e) { @@ -165,25 +171,31 @@ private void loadAccountInfo(AccountInfo accountInfo, String groupID) { .getConfig() .getAccountConfig() .isAccountConfigured()) { - accountInfo = loadAccountRandomly(bcosSDK, client); - if (accountInfo != null) { + // load key from account dir + AccountInfo newAccountInfo = loadAccountRandomly(bcosSDK, client); + if (newAccountInfo != null) { this.client .getCryptoSuite() .loadAccount( - accountInfo.accountFileFormat, - accountInfo.accountFile, - accountInfo.password); + newAccountInfo.accountFileFormat, + newAccountInfo.accountFile, + newAccountInfo.password); } - if (accountInfo == null) { + if (newAccountInfo == null) { + // still not found key, use client crypto key pair // save the keyPair client.getCryptoSuite().getCryptoKeyPair().storeKeyPairWithPemFormat(); } } } catch (LoadKeyStoreException e) { - logger.warn( + logger.error( "loadAccountRandomly failed, try to generate and load the random account, error info: {}", e.getMessage(), e); + System.out.println( + "Failed to load the account from the keyStoreDir, error info: " + + e.getMessage()); + System.exit(0); } catch (Exception e) { System.out.println( "Failed to create BcosSDK failed! Please check the node status and the console configuration, error info: " @@ -231,12 +243,12 @@ private AccountInfo loadAccount(BcosSDK bcosSDK, String[] params) { System.out.println("Invalid param " + params[1] + ", must be -pem or -p12"); System.exit(0); } - if (params[1].compareToIgnoreCase("-pem") == 0 && params.length != 3) { + if (params[1].compareToIgnoreCase("-pem") == 0 && params.length < 3) { System.out.println( "Load account from the pem file failed! Please specified the pem file path"); System.exit(0); } - if (params[1].compareToIgnoreCase("-p12") == 0 && params.length != 3) { + if (params[1].compareToIgnoreCase("-p12") == 0 && params.length < 3) { System.out.println( "Load account from the p12 file failed! Please specified the p12 file path"); System.exit(0); @@ -271,7 +283,7 @@ public void switchGroup(String[] params) { } this.consoleClientFace = new ConsoleClientImpl(client); this.precompiledFace = new PrecompiledImpl(client); - this.consoleContractFace = new ConsoleContractImpl(client); + this.consoleContractFace = new ConsoleContractImpl(client, useV1TxService); this.collaborationFace = new CollaborationImpl(client); this.authFace = new AuthImpl(client); JlineUtils.switchGroup(client); @@ -345,7 +357,7 @@ public void loadAccount(String[] params) { cryptoSuite.loadAccount(accountFormat, accountPath, accountPassword); this.consoleClientFace = new ConsoleClientImpl(client); this.precompiledFace = new PrecompiledImpl(client); - this.consoleContractFace = new ConsoleContractImpl(client); + this.consoleContractFace = new ConsoleContractImpl(client, useV1TxService); this.collaborationFace = new CollaborationImpl(client); this.authFace = new AuthImpl(client); System.out.println("Load account " + params[1] + " success!"); diff --git a/src/main/java/console/auth/AuthImpl.java b/src/main/java/console/auth/AuthImpl.java index 0ee66f14..d9431d29 100644 --- a/src/main/java/console/auth/AuthImpl.java +++ b/src/main/java/console/auth/AuthImpl.java @@ -2,6 +2,7 @@ import console.ConsoleInitializer; import console.common.ConsoleUtils; +import java.math.BigDecimal; import java.math.BigInteger; import java.util.Arrays; import java.util.List; @@ -22,6 +23,7 @@ import org.fisco.bcos.sdk.v3.transaction.codec.decode.ReceiptParser; import org.fisco.bcos.sdk.v3.transaction.model.exception.ContractException; import org.fisco.bcos.sdk.v3.transaction.model.exception.TransactionException; +import org.fisco.bcos.sdk.v3.transaction.tools.Convert; import org.fisco.bcos.sdk.v3.utils.AddressUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -222,6 +224,11 @@ public void createSetSysConfigProposal(ConsoleInitializer consoleInitializer, St throws Exception { String key = params[1]; String value = params[2]; + if (params.length > 3 && key.equals(SystemConfigService.TX_GAS_PRICE)) { + Convert.Unit unit = Convert.Unit.fromString(params[3]); + BigDecimal weiValue = Convert.toWei(value, unit); + value = weiValue.toBigIntegerExact().toString(); + } BigInteger proposalId = authManager.createSetSysConfigProposal(key, value); System.out.println("Set system config proposal created, ID is: " + proposalId); @@ -312,6 +319,14 @@ public void getProposalInfoList(String[] params) throws Exception { params[2], BigInteger.ONE, BigInteger.valueOf(Integer.MAX_VALUE)); + if (from.compareTo(to) > 0) { + System.out.println("Query From should be less than To."); + return; + } + if (to.subtract(from).compareTo(BigInteger.valueOf(100)) > 0) { + System.out.println("Query range should be less than 100."); + return; + } List proposalInfoList = authManager.getProposalInfoList(from, to); int showFrom = from.intValue(); for (ProposalInfo proposalInfo : proposalInfoList) { diff --git a/src/main/java/console/command/JlineUtils.java b/src/main/java/console/command/JlineUtils.java index 459d04f0..aa870f02 100644 --- a/src/main/java/console/command/JlineUtils.java +++ b/src/main/java/console/command/JlineUtils.java @@ -196,6 +196,11 @@ private static List generateComplters(Client client) { new StringsCompleter(command), new StringsCompleter(SystemConfigService.TX_GAS_LIMIT), new StringsCompleterIgnoreCase())); + completers.add( + new ArgumentCompleter( + new StringsCompleter(command), + new StringsCompleter(SystemConfigService.TX_GAS_PRICE), + new StringsCompleterIgnoreCase())); completers.add( new ArgumentCompleter( new StringsCompleter(command), diff --git a/src/main/java/console/command/SupportedCommand.java b/src/main/java/console/command/SupportedCommand.java index d9eda798..89deba85 100644 --- a/src/main/java/console/command/SupportedCommand.java +++ b/src/main/java/console/command/SupportedCommand.java @@ -15,6 +15,7 @@ import console.command.category.AccountOpCommand; import console.command.category.AuthOpCommand; +import console.command.category.BalanceOpCommand; import console.command.category.BasicCommand; import console.command.category.BfsCommand; import console.command.category.ConsensusOpCommand; @@ -59,6 +60,7 @@ public static void setIsWasm(boolean wasm) { public static final AuthOpCommand authOpCommand = new AuthOpCommand(); public static final AccountOpCommand accountOpCommand = new AccountOpCommand(); public static final ShardingCommand shardingCommand = new ShardingCommand(); + public static final BalanceOpCommand balanceOpCommand = new BalanceOpCommand(); /// FIXME: not supported now // public static CollaborationOpCommand collaborationOpCommand = new CollaborationOpCommand(); diff --git a/src/main/java/console/command/category/AuthOpCommand.java b/src/main/java/console/command/category/AuthOpCommand.java index cd22bc49..79c4924e 100644 --- a/src/main/java/console/command/category/AuthOpCommand.java +++ b/src/main/java/console/command/category/AuthOpCommand.java @@ -187,7 +187,7 @@ public Map getAllCommandInfo(boolean isWasm) { .getAuthFace() .createSetSysConfigProposal(consoleInitializer, params), 2, - 2, + 3, false, false, true); diff --git a/src/main/java/console/command/category/BalanceOpCommand.java b/src/main/java/console/command/category/BalanceOpCommand.java new file mode 100644 index 00000000..c71a4a6a --- /dev/null +++ b/src/main/java/console/command/category/BalanceOpCommand.java @@ -0,0 +1,132 @@ +package console.command.category; + +import console.command.model.BasicCategoryCommand; +import console.command.model.CommandInfo; +import console.command.model.CommandType; +import console.command.model.HelpInfo; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class BalanceOpCommand extends BasicCategoryCommand { + public static final CommandInfo ADD_BALANCE = + new CommandInfo( + "addBalance", + "Add balance to account. Only balanceGovernor can use it.", + HelpInfo::addBalanceHelp, + (consoleInitializer, params, pwd) -> + consoleInitializer.getPrecompiledFace().addBalance(params), + 2, + 3); + public static final CommandInfo SUB_BALANCE = + new CommandInfo( + "subBalance", + "Sub balance from account. Only balanceGovernor can use it", + HelpInfo::subBalanceHelp, + (consoleInitializer, params, pwd) -> + consoleInitializer.getPrecompiledFace().subBalance(params), + 2, + 3); + public static final CommandInfo TRANSFER_FROM = + new CommandInfo( + "transferBalance", + "Transfer balance from one account to another. Only balanceGovernor can use it", + HelpInfo::transferBalanceHelp, + (consoleInitializer, params, pwd) -> + consoleInitializer.getPrecompiledFace().transferBalance(params), + 3, + 4); + public static final CommandInfo REGISTER_CALLER = + new CommandInfo( + "registerBalanceGovernor", + "Register an account as balanceGovernor. Only Governor accounts can use it.", + HelpInfo::registerBalanceGovernorHelp, + (consoleInitializer, params, pwd) -> + consoleInitializer.getPrecompiledFace().registerBalanceGovernor(params), + 1, + 1); + public static final CommandInfo UNREGISTER_CALLER = + new CommandInfo( + "unregisterBalanceGovernor", + "Unregister an account from balanceGovernor. Only governor account can use it", + HelpInfo::unregisterBalanceGovernorHelp, + (consoleInitializer, params, pwd) -> + consoleInitializer + .getPrecompiledFace() + .unregisterBalanceGovernor(params), + 1, + 1); + + public static final CommandInfo GET_BALANCE = + new CommandInfo( + "getBalance", + "Get balance of the account", + HelpInfo::getBalanceHelp, + (consoleInitializer, params, pwd) -> + consoleInitializer.getPrecompiledFace().getBalance(params), + 1, + 1); + protected static final Map commandToCommandInfo = new HashMap<>(); + + public BalanceOpCommand() { + super(CommandType.BALANCE_PRECOMPILED_OP); + } + + @Override + public CommandInfo getCommandInfo(String command) { + if (commandToCommandInfo.containsKey(command)) { + return commandToCommandInfo.get(command); + } + return null; + } + + @Override + public List getAllCommand(boolean isWasm, boolean isAuthOpen) { + return commandToCommandInfo + .keySet() + .stream() + .filter( + key -> + !(isWasm && !commandToCommandInfo.get(key).isWasmSupport() + || (!isAuthOpen + && commandToCommandInfo.get(key).isNeedAuthOpen()))) + .collect(Collectors.toList()); + } + + @Override + public Map getAllCommandInfo(boolean isWasm) { + return commandToCommandInfo; + } + + public static final CommandInfo LIST_CALLER = + new CommandInfo( + "listBalanceGovernor", + "List all registered balanceGovernor", + HelpInfo::listBalanceGovernorHelp, + (consoleInitializer, params, pwd) -> + consoleInitializer.getPrecompiledFace().listBalanceGovernor(), + 0, + 0); + + static { + Field[] fields = BalanceOpCommand.class.getDeclaredFields(); + for (Field field : fields) { + if (field.getType().equals(CommandInfo.class)) { + try { + CommandInfo constantCommandInfo = (CommandInfo) field.get(null); + commandToCommandInfo.put(constantCommandInfo.getCommand(), constantCommandInfo); + if (constantCommandInfo.getOptionCommand() != null) { + List subCommandList = constantCommandInfo.getOptionCommand(); + for (String s : subCommandList) { + commandToCommandInfo.put(s, constantCommandInfo); + } + } + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + } +} diff --git a/src/main/java/console/command/category/ContractOpCommand.java b/src/main/java/console/command/category/ContractOpCommand.java index 9480c216..ae13f6d9 100644 --- a/src/main/java/console/command/category/ContractOpCommand.java +++ b/src/main/java/console/command/category/ContractOpCommand.java @@ -118,6 +118,19 @@ public static void setIsWasm(boolean wasm) { 2, true); + public static final CommandInfo TRANSFER = + new CommandInfo( + "transfer", + "Transfer token to a specified address", + HelpInfo::transferHelp, + (consoleInitializer, params, pwd) -> + consoleInitializer + .getConsoleContractFace() + .transfer(consoleInitializer, params), + 2, + 3, + true); + static { Field[] fields = ContractOpCommand.class.getDeclaredFields(); for (Field field : fields) { diff --git a/src/main/java/console/command/category/StatusQueryCommand.java b/src/main/java/console/command/category/StatusQueryCommand.java index 0847b6d4..103d4a16 100644 --- a/src/main/java/console/command/category/StatusQueryCommand.java +++ b/src/main/java/console/command/category/StatusQueryCommand.java @@ -191,7 +191,7 @@ public Map getAllCommandInfo(boolean isWasm) { .getPrecompiledFace() .setSystemConfigByKey(consoleInitializer, params), 2, - 2); + 3); public static final CommandInfo GET_SYSTEM_CONFIG_BY_KEY = new CommandInfo( diff --git a/src/main/java/console/command/model/CommandType.java b/src/main/java/console/command/model/CommandType.java index 558aa0c2..bf40cb06 100644 --- a/src/main/java/console/command/model/CommandType.java +++ b/src/main/java/console/command/model/CommandType.java @@ -11,7 +11,8 @@ public enum CommandType { AUTH_OP, ACCOUNT_OP, COLLABORATE_OP, - SHARDING_OP; + SHARDING_OP, + BALANCE_PRECOMPILED_OP; @Override public String toString() { @@ -38,6 +39,8 @@ public String toString() { return "Wasm Collaboration Operation"; case SHARDING_OP: return "Sharding Operation"; + case BALANCE_PRECOMPILED_OP: + return "Balance Precompiled Operation"; default: return "Unknown Command"; } diff --git a/src/main/java/console/command/model/HelpInfo.java b/src/main/java/console/command/model/HelpInfo.java index abb33fcc..c9e35424 100644 --- a/src/main/java/console/command/model/HelpInfo.java +++ b/src/main/java/console/command/model/HelpInfo.java @@ -381,6 +381,10 @@ public static void systemConfigHelper() { " -- the value of tx_gas_limit " + Common.TX_GAS_LIMIT_RANGE + "(default 3000000000)."); + System.out.println( + " -- the value of tx_gas_price " + + Common.TX_GAS_PRICE_RANGE + + "(Users can specify the unit of gasPrice. The default unit is wei. support \"wei\", \"kwei\", \"mwei\", \"gwei\", \"szabo\", \"finney\", \"ether\", \"kether\", \"mether\", \"gether\")."); System.out.println( " -- the value of " + SystemConfigService.CONSENSUS_PERIOD @@ -456,6 +460,83 @@ public static void listDeployContractAddressHelp() { "recordNumber -- (optional) The number of deployed contract records, (default 20)."); } + public static void transferHelp() { + System.out.println("Transfer token to a specified address"); + System.out.println("Usage: \ntransfer toAddress amount [unit]"); + System.out.println("* toAddress -- The address of the receiver."); + System.out.println("* amount -- The amount of token to transfer."); + System.out.println( + "* unit -- (optional) The unit of amount, default is wei, support \"wei\", \"kwei\", \"mwei\", \"gwei\", \"szabo\", \"finney\", \"ether\", \"kether\", \"mether\", \"gether\"."); + System.out.println( + "[Note]: 1 ether = 10^18 wei = 10^15 kwei = 10^12 mwei = 10^9 gwei = 10^6 szabo = 10^3 finney"); + } + + public static void getBalanceHelp() { + System.out.println("Query the balance of the specified account"); + System.out.println("Usage: \ngetBalance accountAddress"); + System.out.println("* accountAddress -- The address of the account."); + } + + public static void addBalanceHelp() { + System.out.println("Add balance to the specified account"); + System.out.println( + "Usage: \nOnly balanceGovernor can use it, addBalance accountAddress amount [unit]."); + System.out.println("* accountAddress -- The address of the account."); + System.out.println("* amount -- The amount of token to add."); + System.out.println( + "* unit -- (optional) The unit of amount, default is wei, support \"wei\", \"kwei\", \"mwei\", \"gwei\", \"szabo\", \"finney\", \"ether\", \"kether\", \"mether\", \"gether\"."); + System.out.println( + "[Note]: 1 ether = 10^18 wei = 10^15 kwei = 10^12 mwei = 10^9 gwei = 10^6 szabo = 10^3 finney"); + } + + public static void subBalanceHelp() { + System.out.println("Sub balance from the specified account"); + System.out.println( + "Usage: \nOnly balanceGovernor can use it, subBalance accountAddress amount [unit]."); + System.out.println("* accountAddress -- The address of the account."); + System.out.println("* amount -- The amount of token to sub."); + System.out.println( + "* unit -- (optional) The unit of amount, default is wei, support \"wei\", \"kwei\", \"mwei\", \"gwei\", \"szabo\", \"finney\", \"ether\", \"kether\", \"mether\", \"gether\"."); + System.out.println( + "[Note]: 1 ether = 10^18 wei = 10^15 kwei = 10^12 mwei = 10^9 gwei = 10^6 szabo = 10^3 finney"); + } + + public static void transferBalanceHelp() { + System.out.println("Transfer token from address A to address B"); + System.out.println( + "Usage: \nOnly balanceGovernor can use it, transferBalance fromAddress toAddress amount [unit]."); + System.out.println("* fromAddress -- The address of the sender."); + System.out.println("* toAddress -- The address of the receiver."); + System.out.println("* amount -- The amount of token to transfer."); + System.out.println( + "* unit -- (optional) The unit of amount, default is wei, support \"wei\", \"kwei\", \"mwei\", \"gwei\", \"szabo\", \"finney\", \"ether\", \"kether\", \"mether\", \"gether\"."); + System.out.println( + "[Note]: 1 ether = 10^18 wei = 10^15 kwei = 10^12 mwei = 10^9 gwei = 10^6 szabo = 10^3 finney"); + } + + public static void registerBalanceGovernorHelp() { + System.out.println("Register the specified account to balanceGovernor"); + System.out.println( + "Usage: \nOnly governor account can use it, registerBalanceGovernor accountAddress."); + System.out.println("* accountAddress -- The address of the account."); + System.out.println("[Note]: The caller must be a contract address."); + System.out.println("[Note]: The request initiator account must be governor."); + } + + public static void unregisterBalanceGovernorHelp() { + System.out.println("Unregister the specified account from balanceGovernor"); + System.out.println( + "Usage: \nOnly governor account can use it, unregisterBalanceGovernor to accountAddress."); + System.out.println("* accountAddress -- The address of the account."); + System.out.println("[Note]: The caller must be a contract address."); + System.out.println("[Note]: The request initiator account must be governor."); + } + + public static void listBalanceGovernorHelp() { + System.out.println("List all registered balanceGovernor."); + System.out.println("Usage: listBalanceGovernor"); + } + public static void startHelp() { System.out.println("Please provide one of the following ways to start the console."); System.out.println("Usage: "); diff --git a/src/main/java/console/common/Common.java b/src/main/java/console/common/Common.java index 717d3cb6..03a34cea 100644 --- a/src/main/java/console/common/Common.java +++ b/src/main/java/console/common/Common.java @@ -16,6 +16,7 @@ private Common() {} // SystemConfig key public static final String TX_COUNT_LIMIT = "tx_count_limit"; public static final String TX_GAS_LIMIT = "tx_gas_limit"; + public static final String TX_GAS_PRICE = "tx_gas_price"; public static final String CONSENSUS_LEADER_PERIOD = "consensus_leader_period"; public static final String COMPATIBILITY_VERSION = "compatibility_version"; public static final String AUTH_CHECK_STATUS = "auth_check_status"; @@ -25,6 +26,7 @@ private Common() {} Arrays.asList( SystemConfigService.TX_COUNT_LIMIT, SystemConfigService.TX_GAS_LIMIT, + SystemConfigService.TX_GAS_PRICE, SystemConfigService.CONSENSUS_PERIOD, SystemConfigService.COMPATIBILITY_VERSION, SystemConfigService.AUTH_STATUS)); @@ -44,6 +46,7 @@ private Common() {} public static final String DEPLOY_LOG_INTEGER_RANGE = "from 1 to 100"; public static final String TX_GAS_LIMIT_RANGE = "must be greater than 100000"; public static final String SYS_CONFIG_RANGE = "must be greater or equal to 1"; + public static final String TX_GAS_PRICE_RANGE = "must be >= 0"; public static final String AUTH_CHECK_DESC = "means whether to check auth when deploy/call contract, if value>0, check auth, otherwise not check auth."; public static final String COMPATIBILITY_VERSION_DESC = diff --git a/src/main/java/console/common/ConsoleUtils.java b/src/main/java/console/common/ConsoleUtils.java index d24dd526..1676f787 100644 --- a/src/main/java/console/common/ConsoleUtils.java +++ b/src/main/java/console/common/ConsoleUtils.java @@ -138,6 +138,10 @@ public static boolean isInvalidHash(String hash) { } } + public static boolean isValidNumber(String number) { + return number.matches("^-?\\d+$") || number.matches("^0[xX][0-9a-fA-F]+$"); + } + public static String[] fixedBfsParams(String[] params, String pwd) throws Exception { String[] fixedParams = new String[params.length]; fixedParams[0] = params[0]; @@ -314,7 +318,8 @@ public static void compileSolToJava( String librariesOption, String specifyContract, boolean isContractParallelAnalysis, - boolean enableAsyncCall) + boolean enableAsyncCall, + String transactionVersion) throws IOException, CompileContractException { String contractName = solFile.getName().split("\\.")[0]; @@ -356,6 +361,10 @@ public static void compileSolToJava( if (enableAsyncCall) { args.add("-e"); } + if (!transactionVersion.equals("V0")) { + args.add("-t"); + args.add(transactionVersion); + } CodeGenMain.main(args.toArray(new String[0])); System.out.println( "*** Convert solidity to java for " + solFile.getName() + " success ***\n"); @@ -368,7 +377,8 @@ public static void compileAllSolToJava( String abiDir, String binDir, boolean isContractParallelAnalysis, - boolean enableAsyncCall) + boolean enableAsyncCall, + String transactionVersion) throws IOException { File[] solFiles = solFileList.listFiles(); if (solFiles.length == 0) { @@ -393,7 +403,8 @@ public static void compileAllSolToJava( null, null, isContractParallelAnalysis, - enableAsyncCall); + enableAsyncCall, + transactionVersion); } catch (Exception e) { System.out.println( "ERROR:convert solidity to java for " @@ -838,7 +849,16 @@ public static void main(String[] args) { String NO_ANALYSIS_OPTION = "no-analysis"; String ENABLE_ASYNC_CALL_OPTION = "enable-async-call"; + String TRANSACTION_VERSION = "transaction-version"; + Option transactionVersion = + new Option( + "t", + TRANSACTION_VERSION, + true, + "[Optional] Specify transaction version interface, default is 0; If you want to use the latest transaction interface, please specify 1."); + transactionVersion.setRequired(false); + options.addOption(transactionVersion); if (mode.equals("solidity")) { Option solidityFilePathOption = new Option( @@ -930,6 +950,7 @@ public static void main(String[] args) { String pkgName = cmd.getOptionValue(PACKAGE_OPTION, DEFAULT_PACKAGE); String javaDir = cmd.getOptionValue(OUTPUT_OPTION, DEFAULT_OUTPUT); + String transactionVersionStr = "V" + cmd.getOptionValue(TRANSACTION_VERSION, "0"); if (mode.equals("solidity")) { String solPathOrDir = cmd.getOptionValue(SOL_OPTION, DEFAULT_SOL); String librariesOption = cmd.getOptionValue(LIBS_OPTION, ""); @@ -959,7 +980,8 @@ public static void main(String[] args) { librariesOption, specifyContract, useDagAnalysis, - enableAsyncCall); + enableAsyncCall, + transactionVersionStr); } else { // input dir compileAllSolToJava( fullJavaDir, @@ -968,7 +990,8 @@ public static void main(String[] args) { ABI_PATH, BIN_PATH, useDagAnalysis, - enableAsyncCall); + enableAsyncCall, + transactionVersionStr); } } catch (IOException | CompileContractException e) { System.out.print(e.getMessage()); @@ -981,15 +1004,20 @@ public static void main(String[] args) { String abiFile = cmd.getOptionValue(ABI_OPTION); String binFile = cmd.getOptionValue(BIN_OPTION); String smBinFile = cmd.getOptionValue(SM_BIN_OPTION); - CodeGenMain.main( - Arrays.asList( + List params = + new ArrayList<>( + Arrays.asList( "-v", "V3", "-a", abiFile, "-b", binFile, "-s", smBinFile, "-p", pkgName, - "-o", javaDir) - .toArray(new String[0])); + "-o", javaDir)); + if (!transactionVersionStr.equals("0")) { + params.add("-t"); + params.add(transactionVersionStr); + } + CodeGenMain.main(params.toArray(new String[0])); } } } diff --git a/src/main/java/console/common/ConsoleVersion.java b/src/main/java/console/common/ConsoleVersion.java index d373e0d3..c1adf690 100644 --- a/src/main/java/console/common/ConsoleVersion.java +++ b/src/main/java/console/common/ConsoleVersion.java @@ -2,7 +2,7 @@ public class ConsoleVersion { - public static final String Version = "3.5.0"; + public static final String Version = "3.6.0"; public static void main(String[] args) { System.out.println("console version: " + Version); diff --git a/src/main/java/console/contract/ConsoleContractFace.java b/src/main/java/console/contract/ConsoleContractFace.java index ab4ca5f8..9cad3332 100644 --- a/src/main/java/console/contract/ConsoleContractFace.java +++ b/src/main/java/console/contract/ConsoleContractFace.java @@ -14,4 +14,6 @@ void listAbi(ConsoleInitializer consoleInitializer, String[] params, String pwd) void listDeployContractAddress(ConsoleInitializer consoleInitializer, String[] params) throws Exception; + + void transfer(ConsoleInitializer consoleInitializer, String[] params) throws Exception; } diff --git a/src/main/java/console/contract/ConsoleContractImpl.java b/src/main/java/console/contract/ConsoleContractImpl.java index 6d05175b..e4ea0898 100644 --- a/src/main/java/console/contract/ConsoleContractImpl.java +++ b/src/main/java/console/contract/ConsoleContractImpl.java @@ -21,6 +21,7 @@ import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; +import java.math.BigDecimal; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -36,6 +37,7 @@ import org.apache.commons.io.FilenameUtils; import org.fisco.bcos.codegen.v3.exceptions.CodeGenException; import org.fisco.bcos.codegen.v3.utils.CodeGenUtils; +import org.fisco.bcos.sdk.jni.common.JniException; import org.fisco.bcos.sdk.v3.client.Client; import org.fisco.bcos.sdk.v3.client.exceptions.ClientException; import org.fisco.bcos.sdk.v3.client.protocol.response.Abi; @@ -52,12 +54,21 @@ import org.fisco.bcos.sdk.v3.model.EnumNodeVersion; import org.fisco.bcos.sdk.v3.model.PrecompiledRetCode; import org.fisco.bcos.sdk.v3.model.RetCode; +import org.fisco.bcos.sdk.v3.model.TransactionReceipt; +import org.fisco.bcos.sdk.v3.transaction.codec.decode.RevertMessageParser; import org.fisco.bcos.sdk.v3.transaction.manager.AssembleTransactionProcessorInterface; import org.fisco.bcos.sdk.v3.transaction.manager.TransactionProcessorFactory; +import org.fisco.bcos.sdk.v3.transaction.manager.transactionv1.AssembleTransactionService; +import org.fisco.bcos.sdk.v3.transaction.manager.transactionv1.ProxySignTransactionManager; +import org.fisco.bcos.sdk.v3.transaction.manager.transactionv1.TransferTransactionService; +import org.fisco.bcos.sdk.v3.transaction.manager.transactionv1.dto.DeployTransactionRequestWithStringParams; +import org.fisco.bcos.sdk.v3.transaction.manager.transactionv1.dto.TransactionRequestWithStringParams; +import org.fisco.bcos.sdk.v3.transaction.manager.transactionv1.utils.TransactionRequestBuilder; import org.fisco.bcos.sdk.v3.transaction.model.dto.CallResponse; import org.fisco.bcos.sdk.v3.transaction.model.dto.TransactionResponse; import org.fisco.bcos.sdk.v3.transaction.model.exception.ContractException; import org.fisco.bcos.sdk.v3.transaction.model.exception.TransactionBaseException; +import org.fisco.bcos.sdk.v3.transaction.tools.Convert; import org.fisco.bcos.sdk.v3.utils.AddressUtils; import org.fisco.bcos.sdk.v3.utils.Hex; import org.fisco.bcos.sdk.v3.utils.Numeric; @@ -73,8 +84,13 @@ public class ConsoleContractImpl implements ConsoleContractFace { private final Client client; private final AssembleTransactionProcessorInterface assembleTransactionProcessor; + // new version tx v2 + private AssembleTransactionService assembleTransactionService = null; + private final TransferTransactionService transferTransactionService; private final BFSService bfsService; + private boolean useTransactionV1 = false; + public ConsoleContractImpl(Client client) { this.client = client; CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().getCryptoKeyPair(); @@ -82,6 +98,23 @@ public ConsoleContractImpl(Client client) { TransactionProcessorFactory.createAssembleTransactionProcessor( client, cryptoKeyPair); this.bfsService = new BFSService(client, cryptoKeyPair); + ProxySignTransactionManager proxySignTransactionManager = + new ProxySignTransactionManager(client); + transferTransactionService = new TransferTransactionService(proxySignTransactionManager); + } + + public ConsoleContractImpl(Client client, boolean useTransactionV1) { + this(client); + this.useTransactionV1 = useTransactionV1; + if (useTransactionV1) { + int negotiatedProtocol = client.getNegotiatedProtocol(); + // if protocol version < 2, it means client connect to old version node, not support + if ((negotiatedProtocol >> 16) < 2) { + throw new UnsupportedOperationException( + "The node version is too low, incompatible with v1 params, please upgrade the node to 3.6.0 or higher"); + } + assembleTransactionService = new AssembleTransactionService(client); + } } @Override @@ -231,9 +264,17 @@ public TransactionResponse deploySolidity( if (sm) { bin = abiAndBin.getSmBin(); } - TransactionResponse response = - this.assembleTransactionProcessor.deployAndGetResponseWithStringParams( - abiAndBin.getAbi(), bin, tempInputParams, null); + TransactionResponse response; + if (useTransactionV1) { + DeployTransactionRequestWithStringParams request = + new TransactionRequestBuilder(abiAndBin.getAbi(), bin) + .buildDeployStringParamsRequest(tempInputParams); + response = assembleTransactionService.deployContract(request); + } else { + response = + this.assembleTransactionProcessor.deployAndGetResponseWithStringParams( + abiAndBin.getAbi(), bin, tempInputParams, null); + } if (response.getReturnCode() != PrecompiledRetCode.CODE_SUCCESS.getCode()) { System.out.println("deploy contract for " + contractName + " failed!"); System.out.println("return message: " + response.getReturnMessage()); @@ -261,6 +302,8 @@ public TransactionResponse deploySolidity( } catch (ClientException | CompileContractException | IOException + | ContractException + | JniException | ContractCodecException e) { throw new ConsoleMessageException("deploy contract failed for " + e.getMessage(), e); } @@ -285,9 +328,18 @@ public TransactionResponse deployWasm( String binStr = Hex.toHexString(bin); File abiFile = new File(abiPath); String abi = FileUtils.readFileToString(abiFile); - TransactionResponse response = - this.assembleTransactionProcessor.deployAndGetResponseWithStringParams( - abi, binStr, inputParams, path); + TransactionResponse response; + if (useTransactionV1) { + DeployTransactionRequestWithStringParams request = + new TransactionRequestBuilder(abi, binStr) + .setTo(path) + .buildDeployStringParamsRequest(inputParams); + response = assembleTransactionService.deployContract(request); + } else { + response = + this.assembleTransactionProcessor.deployAndGetResponseWithStringParams( + abi, binStr, inputParams, path); + } if (response.getReturnCode() != PrecompiledRetCode.CODE_SUCCESS.getCode()) { System.out.println("deploy contract for " + path + " failed!"); System.out.println("return message: " + response.getReturnMessage()); @@ -321,7 +373,11 @@ public TransactionResponse deployWasm( ContractCompiler.saveAbiAndBin( client.getGroup(), abiAndBin, contractName, contractAddress); return response; - } catch (ClientException | IOException | ContractCodecException e) { + } catch (ClientException + | IOException + | JniException + | ContractException + | ContractCodecException e) { throw new ConsoleMessageException("deploy contract failed due to:" + e.getMessage(), e); } } @@ -682,6 +738,10 @@ protected void callContract( + errorMessage + ", please refer to " + StatusCodeLink.txReceiptStatusLink); + } catch (JniException | ContractException e) { + System.out.println( + "call for " + contractName + " failed, contractAddress: " + contractAddress); + System.out.println(e.getMessage()); } } @@ -692,7 +752,8 @@ private void sendTransaction( String functionName, List callParams, ABIDefinition abiDefinition) - throws ContractCodecException, TransactionBaseException { + throws ContractCodecException, TransactionBaseException, ContractException, + JniException { if (logger.isTraceEnabled()) { logger.trace( "sendTransactionAndGetResponse request, params: {}, contractAddress: {}, contractName: {}, functionName: {}, paramSize:{}, abiDefinition: {}", @@ -703,9 +764,17 @@ private void sendTransaction( callParams.size(), abiDefinition); } - TransactionResponse response = - assembleTransactionProcessor.sendTransactionWithStringParamsAndGetResponse( - contractAddress, abiAndBin.getAbi(), functionName, callParams); + TransactionResponse response; + if (useTransactionV1) { + TransactionRequestWithStringParams request = + new TransactionRequestBuilder(abiAndBin.getAbi(), functionName, contractAddress) + .buildStringParamsRequest(callParams); + response = assembleTransactionService.sendTransaction(request); + } else { + response = + assembleTransactionProcessor.sendTransactionWithStringParamsAndGetResponse( + contractAddress, abiAndBin.getAbi(), functionName, callParams); + } System.out.println( "transaction hash: " + response.getTransactionReceipt().getTransactionHash()); ConsoleUtils.singleLine(); @@ -732,7 +801,8 @@ private void sendCall( String contractAddress, String functionName, List callParams) - throws TransactionBaseException, ContractCodecException { + throws TransactionBaseException, ContractCodecException, JniException, + ContractException { if (logger.isDebugEnabled()) { logger.debug( "sendCall request, params: {}, contractAddress: {}, contractName: {}, functionName:{}, paramSize: {}", @@ -743,14 +813,21 @@ private void sendCall( callParams.size()); } CryptoKeyPair cryptoKeyPair = client.getCryptoSuite().getCryptoKeyPair(); - CallResponse response = - assembleTransactionProcessor.sendCallWithSignWithStringParams( - cryptoKeyPair.getAddress(), - contractAddress, - abiAndBin.getAbi(), - functionName, - callParams); - + CallResponse response; + if (useTransactionV1) { + TransactionRequestWithStringParams request = + new TransactionRequestBuilder(abiAndBin.getAbi(), functionName, contractAddress) + .buildStringParamsRequest(callParams); + response = assembleTransactionService.sendCall(request); + } else { + response = + assembleTransactionProcessor.sendCallWithSignWithStringParams( + cryptoKeyPair.getAddress(), + contractAddress, + abiAndBin.getAbi(), + functionName, + callParams); + } ConsoleUtils.singleLine(); System.out.println("Return code: " + response.getReturnCode()); if (response.getReturnCode() == PrecompiledRetCode.CODE_SUCCESS.getCode()) { @@ -888,6 +965,61 @@ public void listDeployContractAddress(ConsoleInitializer consoleInitializer, Str } } + @Override + public void transfer(ConsoleInitializer consoleInitializer, String[] params) throws Exception { + + int negotiatedProtocol = consoleInitializer.getClient().getNegotiatedProtocol(); + if ((negotiatedProtocol >> 16) < 2) { + throw new UnsupportedOperationException( + "The node version is too low, please upgrade the node to 3.6.0 or higher"); + } + String address = params[1]; + String amount = params[2]; + + Convert.Unit unit = Convert.Unit.WEI; + if (params.length == 4) { + String unitStr = params[3]; + unit = Convert.Unit.fromString(unitStr); + } + if (!AddressUtils.isValidAddress(address)) { + System.out.println("Invalid contract address: " + address); + return; + } + if (!ConsoleUtils.isValidNumber(amount)) { + System.out.println("Invalid amount: " + amount); + return; + } + BigDecimal value = new BigDecimal(amount); + if (value.compareTo(BigDecimal.ZERO) < 0) { + System.out.println("Invalid amount: " + amount); + return; + } + if (value.compareTo(BigDecimal.ZERO) == 0) { + System.out.println("Amount is zero, no need to transfer."); + return; + } + TransactionReceipt transactionReceipt = + transferTransactionService.sendFunds(address, value, unit); + System.out.println("transaction hash: " + transactionReceipt.getTransactionHash()); + ConsoleUtils.singleLine(); + System.out.println("transaction status: " + transactionReceipt.getStatus()); + + ConsoleUtils.singleLine(); + if (transactionReceipt.getStatus() == 0) { + System.out.println("description: transaction executed successfully"); + System.out.println( + transactionReceipt.getFrom() + " => " + address + ", " + amount + " " + unit); + } else { + Tuple2 revertMessage = + RevertMessageParser.tryResolveRevertMessage(transactionReceipt); + System.out.println( + "description: transfer transaction failed." + + (revertMessage.getValue1() + ? " Reason: " + revertMessage.getValue2() + : "")); + } + } + private String getSolidityAbi(String contractFileName) throws Exception { String contractFilePath = contractFileName; if (!contractFilePath.endsWith(ConsoleUtils.SOL_SUFFIX)) { diff --git a/src/main/java/console/precompiled/PrecompiledFace.java b/src/main/java/console/precompiled/PrecompiledFace.java index c203db01..045d7566 100644 --- a/src/main/java/console/precompiled/PrecompiledFace.java +++ b/src/main/java/console/precompiled/PrecompiledFace.java @@ -47,5 +47,19 @@ void setSystemConfigByKey(ConsoleInitializer consoleInitializer, String[] params void fixBFS(String[] params) throws Exception; + void getBalance(String[] params) throws Exception; + + void addBalance(String[] params) throws Exception; + + void subBalance(String[] params) throws Exception; + + void transferBalance(String[] params) throws Exception; + + void registerBalanceGovernor(String[] params) throws Exception; + + void unregisterBalanceGovernor(String[] params) throws Exception; + + void listBalanceGovernor() throws Exception; + String getPwd(); } diff --git a/src/main/java/console/precompiled/PrecompiledImpl.java b/src/main/java/console/precompiled/PrecompiledImpl.java index 5c3a3b45..827f315b 100644 --- a/src/main/java/console/precompiled/PrecompiledImpl.java +++ b/src/main/java/console/precompiled/PrecompiledImpl.java @@ -9,6 +9,7 @@ import console.precompiled.model.CRUDParseUtils; import console.precompiled.model.Table; import java.io.IOException; +import java.math.BigDecimal; import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -23,6 +24,7 @@ import org.fisco.bcos.sdk.v3.client.Client; import org.fisco.bcos.sdk.v3.client.protocol.response.Abi; import org.fisco.bcos.sdk.v3.codec.datatypes.generated.tuples.generated.Tuple2; +import org.fisco.bcos.sdk.v3.contract.precompiled.balance.BalanceService; import org.fisco.bcos.sdk.v3.contract.precompiled.bfs.BFSInfo; import org.fisco.bcos.sdk.v3.contract.precompiled.bfs.BFSPrecompiled.BfsInfo; import org.fisco.bcos.sdk.v3.contract.precompiled.bfs.BFSService; @@ -40,6 +42,7 @@ import org.fisco.bcos.sdk.v3.model.PrecompiledRetCode; import org.fisco.bcos.sdk.v3.model.RetCode; import org.fisco.bcos.sdk.v3.transaction.model.exception.ContractException; +import org.fisco.bcos.sdk.v3.transaction.tools.Convert; import org.fisco.bcos.sdk.v3.utils.AddressUtils; import org.fisco.bcos.sdk.v3.utils.Numeric; import org.fisco.bcos.sdk.v3.utils.ObjectMapperFactory; @@ -49,13 +52,13 @@ public class PrecompiledImpl implements PrecompiledFace { private static final Logger logger = LoggerFactory.getLogger(PrecompiledImpl.class); - private Client client; private ConsensusService consensusService; private SystemConfigService systemConfigService; private TableCRUDService tableCRUDService; private BFSService bfsService; private ShardingService shardingService; + private BalanceService balanceService; private String pwd = "/apps"; public PrecompiledImpl(Client client) { @@ -66,6 +69,7 @@ public PrecompiledImpl(Client client) { this.tableCRUDService = new TableCRUDService(client, cryptoKeyPair); this.bfsService = new BFSService(client, cryptoKeyPair); this.shardingService = new ShardingService(client, cryptoKeyPair); + this.balanceService = new BalanceService(client, cryptoKeyPair); } @Override @@ -117,6 +121,11 @@ public void setSystemConfigByKey(ConsoleInitializer consoleInitializer, String[] throws Exception { String key = params[1]; String value = params[2]; + if (params.length > 3 && key.equals(SystemConfigService.TX_GAS_PRICE)) { + Convert.Unit unit = Convert.Unit.fromString(params[3]); + BigDecimal weiValue = Convert.toWei(value, unit); + value = weiValue.toBigIntegerExact().toString(); + } RetCode retCode = this.systemConfigService.setValueByKey(key, value); ConsoleUtils.printJson(retCode.toString()); if (key.equals(SystemConfigService.COMPATIBILITY_VERSION) @@ -745,6 +754,194 @@ public void fixBFS(String[] params) throws Exception { ConsoleUtils.printJson(bfsService.fixBfs().toString()); } + @Override + public void getBalance(String[] params) throws Exception { + String address = params[1]; + if (!AddressUtils.isValidAddress(address)) { + System.out.println("Invalid address: " + address); + return; + } + BigInteger result = this.balanceService.getBalance(address); + System.out.println("balance: " + result + " wei"); + } + + @Override + public void addBalance(String[] params) throws Exception { + String address = params[1]; + String amount = params[2]; + Convert.Unit unit = Convert.Unit.WEI; + if (params.length > 3) { + unit = Convert.Unit.fromString(params[3]); + } + if (!AddressUtils.isValidAddress(address)) { + System.out.println("Invalid address: " + address); + return; + } + if (!ConsoleUtils.isValidNumber(amount)) { + System.out.println("Invalid amount: " + amount); + return; + } + BigDecimal value = new BigDecimal(amount); + if (value.compareTo(BigDecimal.ZERO) < 0) { + System.out.println("Invalid amount: " + amount); + return; + } + if (value.compareTo(BigDecimal.ZERO) == 0) { + System.out.println("Amount is zero, no need to addBalance."); + return; + } + RetCode retCode = this.balanceService.addBalance(address, amount, unit); + + logger.info("addBalance: {}, retCode {}", address, retCode); + // parse the result + if (retCode == PrecompiledRetCode.CODE_SUCCESS) { + System.out.println( + "transaction hash:" + retCode.getTransactionReceipt().getTransactionHash()); + System.out.println( + "add balance " + address + " success. You can use 'getBalance' to check"); + } else { + System.out.println("add balance " + address + " failed."); + ConsoleUtils.printJson(retCode.toString()); + } + } + + @Override + public void subBalance(String[] params) throws Exception { + String address = params[1]; + String amount = params[2]; + Convert.Unit unit = Convert.Unit.WEI; + if (params.length > 3) { + unit = Convert.Unit.fromString(params[3]); + } + if (!AddressUtils.isValidAddress(address)) { + System.out.println("Invalid address: " + address); + return; + } + if (!ConsoleUtils.isValidNumber(amount)) { + System.out.println("Invalid amount: " + amount); + return; + } + BigDecimal value = new BigDecimal(amount); + if (value.compareTo(BigDecimal.ZERO) < 0) { + System.out.println("Invalid amount: " + amount); + return; + } + if (value.compareTo(BigDecimal.ZERO) == 0) { + System.out.println("Amount is zero, no need to subBalance."); + return; + } + RetCode retCode = this.balanceService.subBalance(address, amount, unit); + + logger.info("subBalance: {}, retCode {}", address, retCode); + // parse the result + if (retCode == PrecompiledRetCode.CODE_SUCCESS) { + System.out.println( + "transaction hash:" + retCode.getTransactionReceipt().getTransactionHash()); + System.out.println( + "sub balance " + address + " success. You can use 'getBalance' to check"); + } else { + System.out.println("sub balance " + address + " failed. receipt."); + ConsoleUtils.printJson(retCode.toString()); + } + } + + public void transferBalance(String[] params) throws Exception { + String from = params[1]; + String to = params[2]; + String amount = params[3]; + Convert.Unit unit = Convert.Unit.WEI; + if (params.length > 4) { + unit = Convert.Unit.fromString(params[4]); + } + if (!AddressUtils.isValidAddress(from)) { + System.out.println("Invalid from address: " + from); + return; + } + if (!AddressUtils.isValidAddress(to)) { + System.out.println("Invalid to address: " + to); + return; + } + if (!ConsoleUtils.isValidNumber(amount)) { + System.out.println("Invalid amount: " + amount); + return; + } + BigDecimal value = new BigDecimal(amount); + if (value.compareTo(BigDecimal.ZERO) < 0) { + System.out.println("Invalid amount: " + amount); + return; + } + if (value.compareTo(BigDecimal.ZERO) == 0) { + System.out.println("Amount is zero, no need to transferBalance."); + return; + } + RetCode retCode = this.balanceService.transfer(from, to, amount, unit); + + logger.info("transferBalance: {}, retCode {}", from, retCode); + // parse the result + if (retCode == PrecompiledRetCode.CODE_SUCCESS) { + System.out.println( + "transaction hash:" + retCode.getTransactionReceipt().getTransactionHash()); + System.out.println( + "transfer " + + amount + + unit.toString() + + " from " + + from + + " to " + + to + + " success. You can use 'getBalance' to check"); + } else { + System.out.println("transfer " + amount + " from " + from + " to " + to + " failed."); + ConsoleUtils.printJson(retCode.toString()); + } + } + + @Override + public void registerBalanceGovernor(String[] params) throws Exception { + String address = params[1]; + if (!AddressUtils.isValidAddress(address)) { + System.out.println("Invalid address: " + address); + return; + } + RetCode retCode = this.balanceService.registerCaller(address); + + logger.info("registerBalanceGovernor: {}, retCode {}", address, retCode); + // parse the result + if (retCode == PrecompiledRetCode.CODE_SUCCESS) { + System.out.println( + "transaction hash:" + retCode.getTransactionReceipt().getTransactionHash()); + System.out.println("register balanceGovernor " + address + " success."); + } else { + System.out.println("register balanceGovernor " + address + " failed. "); + } + } + + @Override + public void unregisterBalanceGovernor(String[] params) throws Exception { + String address = params[1]; + if (!AddressUtils.isValidAddress(address)) { + System.out.println("Invalid address: " + address); + return; + } + RetCode retCode = this.balanceService.unregisterCaller(address); + + logger.info("unregisterBalanceGovernor: {}, retCode {}", address, retCode); + // parse the result + if (retCode == PrecompiledRetCode.CODE_SUCCESS) { + System.out.println( + "transaction hash:" + retCode.getTransactionReceipt().getTransactionHash()); + System.out.println("unregister balanceGovernor " + address + " success."); + } else { + System.out.println("unregister balanceGovernor " + address + " failed."); + } + } + + @Override + public void listBalanceGovernor() throws Exception { + List result = this.balanceService.listCaller(); + System.out.println("listBalanceGovernor: " + result.toString()); + } + @Override public String getPwd() { return pwd; @@ -755,7 +952,16 @@ private Tuple2 travelBfs( if (deep >= limit) return new Tuple2<>(0, 0); int dirCount = 0; int contractCount = 0; - List children = bfsService.list(absolutePath); + BigInteger offset = BigInteger.ZERO; + EnumNodeVersion.Version supportedVersion = bfsService.getCurrentVersion(); + Tuple2> fileInfoList; + if (supportedVersion.compareTo(EnumNodeVersion.BCOS_3_1_0.toVersionObj()) >= 0) { + fileInfoList = bfsService.list(absolutePath, offset, Common.LS_DEFAULT_COUNT); + } else { + fileInfoList = new Tuple2<>(BigInteger.ZERO, bfsService.list(absolutePath)); + } + BigInteger fileLeft = fileInfoList.getValue1(); + List children = fileInfoList.getValue2(); for (int i = 0; i < children.size(); i++) { String thisPrefix = ""; String nextPrefix = ""; @@ -765,7 +971,11 @@ private Tuple2 travelBfs( thisPrefix = prefix + "├─"; } else { nextPrefix = prefix + " "; - thisPrefix = prefix + "└─"; + if (fileLeft.compareTo(BigInteger.ZERO) > 0) { + thisPrefix = prefix + "├─"; + } else { + thisPrefix = prefix + "└─"; + } } System.out.println(thisPrefix + children.get(i).getFileName()); if (children.get(i).getFileType().equals(Common.BFS_TYPE_DIR)) { @@ -783,6 +993,9 @@ private Tuple2 travelBfs( } else { contractCount++; } + if (fileLeft.compareTo(BigInteger.ZERO) > 0 && i == children.size() - 1) { + System.out.println(prefix + "└─" + "... " + fileLeft + " left files..."); + } } } return new Tuple2<>(dirCount, contractCount); diff --git a/tools/download_console.sh b/tools/download_console.sh index 72c81ea5..39155a14 100755 --- a/tools/download_console.sh +++ b/tools/download_console.sh @@ -3,7 +3,7 @@ package_name="console.tar.gz" solcj_name="" solcj_default_version="solcJ-0.8.11.1.jar" only_solc_flag="" -default_version="3.5.0" +default_version="3.6.0" download_version="${default_version}" solc_download_version="3.0.0" specify_console=0