From f0b92a1fd4f4cebde4d3f8a6f1a48dd43931ada9 Mon Sep 17 00:00:00 2001 From: yangfang2 Date: Tue, 6 Aug 2024 15:10:30 +0800 Subject: [PATCH] (connection): refresh stub config --- .../wecross/stub/web3/Web3Connection.java | 96 +++++- .../stub/web3/Web3ConnectionFactory.java | 33 +- .../stub/web3/config/Web3AccountConfig.java | 18 +- .../web3/config/Web3AccountConfigParser.java | 4 +- .../stub/web3/config/Web3StubConfig.java | 13 + .../web3/config/Web3StubConfigParser.java | 4 +- .../stub/web3/utils/FunctionUtility.java | 307 ------------------ 7 files changed, 119 insertions(+), 356 deletions(-) delete mode 100644 src/main/java/com/webank/wecross/stub/web3/utils/FunctionUtility.java diff --git a/src/main/java/com/webank/wecross/stub/web3/Web3Connection.java b/src/main/java/com/webank/wecross/stub/web3/Web3Connection.java index 2088d92..f61145c 100644 --- a/src/main/java/com/webank/wecross/stub/web3/Web3Connection.java +++ b/src/main/java/com/webank/wecross/stub/web3/Web3Connection.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.moandjiezana.toml.Toml; import com.webank.wecross.stub.Connection; import com.webank.wecross.stub.Request; import com.webank.wecross.stub.ResourceInfo; @@ -12,8 +13,10 @@ import com.webank.wecross.stub.web3.common.Web3Constant; import com.webank.wecross.stub.web3.common.Web3RequestType; import com.webank.wecross.stub.web3.common.Web3StatusCode; +import com.webank.wecross.stub.web3.config.Web3StubConfig; import com.webank.wecross.stub.web3.protocol.request.TransactionParams; import com.webank.wecross.stub.web3.protocol.response.TransactionPair; +import java.io.IOException; import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -21,9 +24,15 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.scheduling.concurrent.CustomizableThreadFactory; import org.web3j.crypto.RawTransaction; import org.web3j.crypto.TransactionDecoder; import org.web3j.protocol.core.methods.response.EthBlock; @@ -41,10 +50,49 @@ public class Web3Connection implements Connection { private ConnectionEventHandler eventHandler; private final Map properties = new HashMap<>(); private final ClientWrapper clientWrapper; + private final BigInteger chainId; + private final String stubConfigFilePath; + private long stubConfigFileLastModified; - public Web3Connection(ClientWrapper clientWrapper) { + public Web3Connection(ClientWrapper clientWrapper, Web3StubConfig web3StubConfig) + throws IOException { this.objectMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS); this.clientWrapper = clientWrapper; + this.chainId = clientWrapper.ethChainId(); + this.stubConfigFilePath = web3StubConfig.getStubConfigPath(); + // init + refreshStubConfig(web3StubConfig); + + // refresh + ScheduledExecutorService executorService = + new ScheduledThreadPoolExecutor(1, new CustomizableThreadFactory("refreshStubConfig-")); + executorService.scheduleAtFixedRate( + () -> { + try { + PathMatchingResourcePatternResolver resolver = + new PathMatchingResourcePatternResolver(); + Resource resource = resolver.getResource(stubConfigFilePath); + long lastModified = resource.getFile().lastModified(); + if (Objects.equals(stubConfigFileLastModified, lastModified)) { + return; + } + Web3StubConfig newWeb3StubConfig = + new Toml().read(resource.getInputStream()).to(Web3StubConfig.class); + newWeb3StubConfig.setStubConfigPath(stubConfigFilePath); + // changed + refreshStubConfig(newWeb3StubConfig); + if (Objects.nonNull(eventHandler)) { + // refresh remote resource + eventHandler.onResourcesChange(resourceInfoList); + } + this.stubConfigFileLastModified = lastModified; + } catch (IOException e) { + logger.error("refreshStubConfig Exception:", e); + } + }, + 30000, + 30000, + TimeUnit.MILLISECONDS); } @Override @@ -75,6 +123,16 @@ public void asyncSend(Request request, Callback callback) { } } + @Override + public Map getProperties() { + return properties; + } + + @Override + public void setConnectionEventHandler(ConnectionEventHandler eventHandler) { + this.eventHandler = eventHandler; + } + private void handleAsyncGetTransaction(Request request, Callback callback) { Response response = new Response(); response.setErrorCode(Web3StatusCode.Success); @@ -279,6 +337,24 @@ private void handleAsyncTransactionRequest(Request request, Callback callback) { } } + private synchronized void refreshStubConfig(Web3StubConfig web3StubConfig) throws IOException { + this.resourceInfoList = web3StubConfig.convertToResourceInfos(); + + addProperty(Web3Constant.WEB3_PROPERTY_CHAIN_ID, chainId.toString()); + addProperty(Web3Constant.WEB3_PROPERTY_STUB_TYPE, web3StubConfig.getCommon().getType()); + addProperty(Web3Constant.WEB3_PROPERTY_CHAIN_URL, web3StubConfig.getService().getUrl()); + List resources = web3StubConfig.getResources(); + if (!resources.isEmpty()) { + for (Web3StubConfig.Resource resource : resources) { + String name = resource.getName(); + // name->address + this.addProperty(name, resource.getAddress()); + // name+ABI->abi + this.addAbi(name, resource.getAbi()); + } + } + } + public boolean hasProxyDeployed() { return getProperties().containsKey(Web3Constant.WEB3_PROXY_NAME); } @@ -291,20 +367,6 @@ public List getResourceInfoList() { return resourceInfoList; } - public void setResourceInfoList(List resourceInfoList) { - this.resourceInfoList = resourceInfoList; - } - - @Override - public Map getProperties() { - return properties; - } - - @Override - public void setConnectionEventHandler(ConnectionEventHandler eventHandler) { - this.eventHandler = eventHandler; - } - public void addProperty(String key, String value) { this.properties.put(key, value); } @@ -324,4 +386,8 @@ public String getAbi(String key) { public ClientWrapper getClientWrapper() { return clientWrapper; } + + public BigInteger getChainId() { + return chainId; + } } diff --git a/src/main/java/com/webank/wecross/stub/web3/Web3ConnectionFactory.java b/src/main/java/com/webank/wecross/stub/web3/Web3ConnectionFactory.java index 0521b5c..64865fa 100644 --- a/src/main/java/com/webank/wecross/stub/web3/Web3ConnectionFactory.java +++ b/src/main/java/com/webank/wecross/stub/web3/Web3ConnectionFactory.java @@ -2,12 +2,9 @@ import com.webank.wecross.stub.web3.client.ClientWrapper; import com.webank.wecross.stub.web3.client.ClientWrapperFactory; -import com.webank.wecross.stub.web3.common.Web3Constant; import com.webank.wecross.stub.web3.config.Web3StubConfig; import com.webank.wecross.stub.web3.config.Web3StubConfigParser; import java.io.IOException; -import java.math.BigInteger; -import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -22,34 +19,8 @@ public static Web3Connection build(String stubConfigPath, String configName) thr } public static Web3Connection build(Web3StubConfig web3StubConfig) throws IOException { - ClientWrapper clientWrapper = ClientWrapperFactory.createClientWrapperInstance(web3StubConfig); - return build(web3StubConfig, clientWrapper); - } - - public static Web3Connection build(Web3StubConfig web3StubConfig, ClientWrapper clientWrapper) - throws IOException { logger.info("web3StubConfig: {}", web3StubConfig); - BigInteger chainId = clientWrapper.ethChainId(); - - Web3Connection connection = new Web3Connection(clientWrapper); - connection.setResourceInfoList(web3StubConfig.convertToResourceInfos()); - connection.addProperty(Web3Constant.WEB3_PROPERTY_CHAIN_ID, chainId.toString()); - connection.addProperty( - Web3Constant.WEB3_PROPERTY_STUB_TYPE, web3StubConfig.getCommon().getType()); - connection.addProperty( - Web3Constant.WEB3_PROPERTY_CHAIN_URL, web3StubConfig.getService().getUrl()); - // from config build resources - List resources = web3StubConfig.getResources(); - if (!resources.isEmpty()) { - // addProperty - for (Web3StubConfig.Resource resource : resources) { - String name = resource.getName(); - // name->address - connection.addProperty(name, resource.getAddress()); - // name+ABI->abi - connection.addAbi(name, resource.getAbi()); - } - } - return connection; + ClientWrapper clientWrapper = ClientWrapperFactory.createClientWrapperInstance(web3StubConfig); + return new Web3Connection(clientWrapper, web3StubConfig); } } diff --git a/src/main/java/com/webank/wecross/stub/web3/config/Web3AccountConfig.java b/src/main/java/com/webank/wecross/stub/web3/config/Web3AccountConfig.java index 6a291e3..28b81e9 100644 --- a/src/main/java/com/webank/wecross/stub/web3/config/Web3AccountConfig.java +++ b/src/main/java/com/webank/wecross/stub/web3/config/Web3AccountConfig.java @@ -8,6 +8,8 @@ public class Web3AccountConfig { private Account account; + private String accountConfigPath; + public static class Account { private String type; private String accountFile; @@ -61,8 +63,22 @@ public void setAccount(Account account) { this.account = account; } + public String getAccountConfigPath() { + return accountConfigPath; + } + + public void setAccountConfigPath(String accountConfigPath) { + this.accountConfigPath = accountConfigPath; + } + @Override public String toString() { - return "Web3AccountConfig{" + "account=" + account + '}'; + return "Web3AccountConfig{" + + "account=" + + account + + ", accountConfigPath='" + + accountConfigPath + + '\'' + + '}'; } } diff --git a/src/main/java/com/webank/wecross/stub/web3/config/Web3AccountConfigParser.java b/src/main/java/com/webank/wecross/stub/web3/config/Web3AccountConfigParser.java index 41aa49b..954555d 100644 --- a/src/main/java/com/webank/wecross/stub/web3/config/Web3AccountConfigParser.java +++ b/src/main/java/com/webank/wecross/stub/web3/config/Web3AccountConfigParser.java @@ -18,6 +18,8 @@ public Web3AccountConfigParser(String configPath, String configName) { public Web3AccountConfig loadConfig() throws IOException { Web3Toml web3Toml = new Web3Toml(getConfigPath()); Toml toml = web3Toml.getToml(); - return toml.to(Web3AccountConfig.class); + Web3AccountConfig web3AccountConfig = toml.to(Web3AccountConfig.class); + web3AccountConfig.setAccountConfigPath(getConfigPath()); + return web3AccountConfig; } } diff --git a/src/main/java/com/webank/wecross/stub/web3/config/Web3StubConfig.java b/src/main/java/com/webank/wecross/stub/web3/config/Web3StubConfig.java index cea9731..4f4908f 100644 --- a/src/main/java/com/webank/wecross/stub/web3/config/Web3StubConfig.java +++ b/src/main/java/com/webank/wecross/stub/web3/config/Web3StubConfig.java @@ -15,6 +15,8 @@ public class Web3StubConfig { private Service service; private List resources; + private String stubConfigPath; + public List convertToResourceInfos() { List resourceInfos = new ArrayList<>(); for (Resource resource : this.getResources()) { @@ -149,6 +151,14 @@ public void setResources(List resources) { this.resources = resources; } + public String getStubConfigPath() { + return stubConfigPath; + } + + public void setStubConfigPath(String stubConfigPath) { + this.stubConfigPath = stubConfigPath; + } + @Override public String toString() { return "Web3StubConfig{" @@ -158,6 +168,9 @@ public String toString() { + service + ", resources=" + resources + + ", stubConfigPath='" + + stubConfigPath + + '\'' + '}'; } } diff --git a/src/main/java/com/webank/wecross/stub/web3/config/Web3StubConfigParser.java b/src/main/java/com/webank/wecross/stub/web3/config/Web3StubConfigParser.java index cd24d94..fcac873 100644 --- a/src/main/java/com/webank/wecross/stub/web3/config/Web3StubConfigParser.java +++ b/src/main/java/com/webank/wecross/stub/web3/config/Web3StubConfigParser.java @@ -18,6 +18,8 @@ public Web3StubConfigParser(String configPath, String configName) { public Web3StubConfig loadConfig() throws IOException { Web3Toml web3Toml = new Web3Toml(getConfigPath()); Toml toml = web3Toml.getToml(); - return toml.to(Web3StubConfig.class); + Web3StubConfig web3StubConfig = toml.to(Web3StubConfig.class); + web3StubConfig.setStubConfigPath(getConfigPath()); + return web3StubConfig; } } diff --git a/src/main/java/com/webank/wecross/stub/web3/utils/FunctionUtility.java b/src/main/java/com/webank/wecross/stub/web3/utils/FunctionUtility.java deleted file mode 100644 index e4bbef0..0000000 --- a/src/main/java/com/webank/wecross/stub/web3/utils/FunctionUtility.java +++ /dev/null @@ -1,307 +0,0 @@ -package com.webank.wecross.stub.web3.utils; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Objects; -import org.web3j.abi.FunctionReturnDecoder; -import org.web3j.abi.TypeReference; -import org.web3j.abi.Utils; -import org.web3j.abi.datatypes.Address; -import org.web3j.abi.datatypes.DynamicArray; -import org.web3j.abi.datatypes.DynamicBytes; -import org.web3j.abi.datatypes.Function; -import org.web3j.abi.datatypes.Type; -import org.web3j.abi.datatypes.Utf8String; -import org.web3j.abi.datatypes.generated.Uint256; -import org.web3j.crypto.Hash; -import org.web3j.tuples.generated.Tuple2; -import org.web3j.tuples.generated.Tuple3; -import org.web3j.tuples.generated.Tuple4; -import org.web3j.tuples.generated.Tuple6; -import org.web3j.utils.Numeric; - -@SuppressWarnings("rawtypes") -public class FunctionUtility { - - public static final int MethodIDLength = 8; - public static final int MethodIDWithHexPrefixLength = MethodIDLength + 2; - - public static final String ProxySendTXMethod = "sendTransaction(string,string,bytes)"; - public static final String ProxySendTXMethodName = "sendTransaction"; - - public static final String ProxySendTransactionTXMethod = - "sendTransactionWithXa(string,string,uint256,string,string,bytes)"; - public static final String ProxySendTransactionTXMethodName = "sendTransactionWithXa"; - - public static final String ProxyCallMethod = "constantCall(string,bytes)"; - public static final String ProxyCallMethodName = "constantCall"; - - public static final String ProxyCallWithTransactionIdMethod = - "constantCallWithXa(string,string,string,bytes)"; - public static final String ProxyCallWithTransactionIdMethodName = "constantCallWithXa"; - - public static final String ProxyRegisterCNSMethod = "registerCNS(string,address)"; - public static final String ProxyRegisterCNSMethodName = "registerCNS"; - - public static final String ProxyGetResourcesMethod = "getResources()"; - public static final String ProxyGetResourcesMethodName = "getResources"; - - public static final List> abiTypeReferenceOutputs = - Collections.singletonList(new TypeReference>() {}); - - /** Get the function object used to encode and decode the abi parameters */ - public static Function newDefaultFunction(String funcName, String[] params) { - - if (Objects.isNull(params)) { - // public func() returns(string[]) - return new Function(funcName, Collections.emptyList(), abiTypeReferenceOutputs); - } - - // public func(string[]) returns(string[]) - return new Function( - funcName, - Collections.singletonList( - (0 == params.length) - ? new DynamicArray<>(Utf8String.class, Collections.emptyList()) - : new DynamicArray<>( - Utf8String.class, Utils.typeMap(Arrays.asList(params), Utf8String.class))), - abiTypeReferenceOutputs); - } - - /** - * WeCrossProxy constantCallWithXa function constantCallWithXa(string memory _XATransactionID, - * string memory _path, string memory _func, bytes memory _args) public returns (bytes memory) - */ - public static Function newConstantCallProxyFunction( - String id, String path, String methodSignature, byte[] abi) { - return new Function( - ProxyCallWithTransactionIdMethodName, - Arrays.asList( - new Utf8String(id), - new Utf8String(path), - new Utf8String(methodSignature), - new DynamicBytes(abi)), - Collections.emptyList()); - } - - /** - * WeCrossProxy constantCall function constantCall(string memory _name, bytes memory - * _argsWithMethodId) public returns (bytes memory) - */ - public static Function newConstantCallProxyFunction( - String name, String methodSignature, byte[] abi) throws IOException { - String methodId = buildMethodId(methodSignature); - ByteArrayOutputStream params = new ByteArrayOutputStream(); - params.write(Numeric.hexStringToByteArray(methodId)); - if (abi != null && abi.length != 0) { - params.write(abi); - } - return new Function( - ProxyCallMethodName, - Arrays.asList(new Utf8String(name), new DynamicBytes(params.toByteArray())), - Collections.emptyList()); - } - - /** - * WeCrossProxy sendTransactionWithXa function sendTransactionWithXa(string memory _uid, string - * memory _XATransactionID, uint256 _XATransactionSeq, string memory _path, string memory _func, - * bytes memory _args) public returns (bytes memory) - */ - public static Function newSendTransactionProxyFunction( - String uid, String tid, long seq, String path, String methodSignature, byte[] abi) { - return new Function( - ProxySendTransactionTXMethodName, - Arrays.asList( - new Utf8String(uid), - new Utf8String(tid), - new Uint256(seq), - new Utf8String(path), - new Utf8String(methodSignature), - new DynamicBytes(abi)), - Collections.emptyList()); - } - - /** - * WeCrossProxy sendTransaction function sendTransaction(string memory _uid, string memory - * _name,bytes memory _argsWithMethodId) public returns (bytes memory) - */ - public static Function newSendTransactionProxyFunction( - String uid, String name, String methodSignature, byte[] abi) throws IOException { - String methodId = buildMethodId(methodSignature); - ByteArrayOutputStream params = new ByteArrayOutputStream(); - params.write(Numeric.hexStringToByteArray(methodId)); - if (abi != null && abi.length != 0) { - params.write(abi); - } - return new Function( - ProxySendTXMethodName, - Arrays.asList( - new Utf8String(uid), new Utf8String(name), new DynamicBytes(params.toByteArray())), - Collections.emptyList()); - } - - /** WeCrossProxy registerCNS function registerCNS(string memory _path, address _addr) public */ - public static Function newRegisterCNSProxyFunction(String path, String address) { - return new Function( - ProxyRegisterCNSMethodName, - Arrays.asList(new Utf8String(path), new Address(address)), - Collections.emptyList()); - } - - /** decode WeCrossProxy constantCall input */ - public static Tuple4 getConstantCallProxyFunctionInput( - String input) { - String data = input.substring(Numeric.containsHexPrefix(input) ? 10 : 8); - final Function function = - new Function( - ProxyCallWithTransactionIdMethodName, - Collections.emptyList(), - Arrays.asList( - new TypeReference() {}, - new TypeReference() {}, - new TypeReference() {}, - new TypeReference() {})); - List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); - - return new Tuple4<>( - (String) results.get(0).getValue(), - (String) results.get(1).getValue(), - (String) results.get(2).getValue(), - (byte[]) results.get(3).getValue()); - } - - /** decode WeCrossProxy constantCall input */ - public static Tuple2 getConstantCallFunctionInput(String input) { - String data = input.substring(Numeric.containsHexPrefix(input) ? 10 : 8); - final Function function = - new Function( - ProxyCallMethodName, - Collections.emptyList(), - Arrays.asList( - new TypeReference() {}, new TypeReference() {})); - List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); - - return new Tuple2<>((String) results.get(0).getValue(), (byte[]) results.get(1).getValue()); - } - - /** decode WeCrossProxy sendTransaction input */ - public static Tuple6 - getSendTransactionProxyFunctionInput(String input) { - String data = input.substring(Numeric.containsHexPrefix(input) ? 10 : 8); - - final Function function = - new Function( - ProxySendTransactionTXMethodName, - Collections.emptyList(), - Arrays.asList( - new TypeReference() {}, - new TypeReference() {}, - new TypeReference() {}, - new TypeReference() {}, - new TypeReference() {}, - new TypeReference() {})); - List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); - - return new Tuple6<>( - (String) results.get(0).getValue(), - (String) results.get(1).getValue(), - (BigInteger) results.get(2).getValue(), - (String) results.get(3).getValue(), - (String) results.get(4).getValue(), - (byte[]) results.get(5).getValue()); - } - - public static byte[] decodeProxyBytesOutput(String output) { - List> outputParameters = - Collections.singletonList(new TypeReference() {}); - List results = FunctionReturnDecoder.decode(output, Utils.convert(outputParameters)); - - return (byte[]) results.get(0).getValue(); - } - - /** decode WeCrossProxy sendTransaction input */ - public static Tuple3 getSendTransactionProxyWithoutTxIdFunctionInput( - String input) { - String data = input.substring(Numeric.containsHexPrefix(input) ? 10 : 8); - - final Function function = - new Function( - ProxySendTXMethodName, - Collections.emptyList(), - Arrays.asList( - new TypeReference() {}, - new TypeReference() {}, - new TypeReference() {})); - List results = FunctionReturnDecoder.decode(data, function.getOutputParameters()); - - return new Tuple3<>( - (String) results.get(0).getValue(), - (String) results.get(1).getValue(), - (byte[]) results.get(2).getValue()); - } - - public static List convertToStringList(List typeList) { - List stringList = new ArrayList<>(); - if (!typeList.isEmpty()) { - @SuppressWarnings("unchecked") - List utf8StringList = ((DynamicArray) typeList.get(0)).getValue(); - for (Utf8String utf8String : utf8StringList) { - stringList.add(utf8String.getValue()); - } - } - return stringList; - } - - /** decode default input */ - public static String[] decodeDefaultInput(String input) { - if (Objects.isNull(input) || input.length() < MethodIDLength) { - return null; - } - - // function funcName() public returns(string[]) - if (input.length() == MethodIDLength) { - return new String[0]; - } - - return decodeDefaultOutput(input.substring(MethodIDLength)); - } - - /** decode default output */ - public static String[] decodeDefaultOutput(String output) { - if (Objects.isNull(output) || output.length() < MethodIDLength) { - return null; - } - - List outputTypes = - FunctionReturnDecoder.decode( - output, Utils.convert(FunctionUtility.abiTypeReferenceOutputs)); - List outputArgs = FunctionUtility.convertToStringList(outputTypes); - return outputArgs.toArray(new String[0]); - } - - public static String decodeOutputAsString(String output) { - if (Objects.isNull(output) || output.length() < MethodIDLength) { - return null; - } - - List outputTypes = - FunctionReturnDecoder.decode( - output, Utils.convert(Collections.singletonList(new TypeReference() {}))); - if (Objects.isNull(outputTypes) || outputTypes.isEmpty()) { - return null; - } - - return (String) outputTypes.get(0).getValue(); - } - - private static String buildMethodId(String methodSignature) { - byte[] input = methodSignature.getBytes(); - byte[] hash = Hash.sha3(input); - return Numeric.toHexString(hash).substring(0, 10); - } -}