diff --git a/src/main/java/com/webank/wecross/stub/web3/Web3BaseStubFactory.java b/src/main/java/com/webank/wecross/stub/web3/Web3BaseStubFactory.java index bf312af..e7e06ff 100644 --- a/src/main/java/com/webank/wecross/stub/web3/Web3BaseStubFactory.java +++ b/src/main/java/com/webank/wecross/stub/web3/Web3BaseStubFactory.java @@ -7,6 +7,8 @@ import com.webank.wecross.stub.WeCrossContext; import com.webank.wecross.stub.web3.account.Web3AccountFactory; import com.webank.wecross.stub.web3.common.Web3Constant; +import com.webank.wecross.stub.web3.custom.CommandHandlerDispatcher; +import com.webank.wecross.stub.web3.custom.RegisterResourceHandler; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,7 +21,10 @@ public void init(WeCrossContext weCrossContext) {} @Override public Driver newDriver() { - return new Web3Driver(); + CommandHandlerDispatcher commandHandlerDispatcher = new CommandHandlerDispatcher(); + commandHandlerDispatcher.registerCommandHandler( + Web3Constant.CUSTOM_COMMAND_REGISTER, new RegisterResourceHandler()); + return new Web3Driver(commandHandlerDispatcher); } @Override 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 6f617ff..5b459e3 100644 --- a/src/main/java/com/webank/wecross/stub/web3/Web3Connection.java +++ b/src/main/java/com/webank/wecross/stub/web3/Web3Connection.java @@ -2,7 +2,6 @@ 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; @@ -20,19 +19,13 @@ import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.HashMap; 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 java.util.concurrent.ConcurrentHashMap; 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; @@ -46,53 +39,18 @@ public class Web3Connection implements Connection { public static final String RECEIPT_SUCCESS = "0x1"; private final ObjectMapper objectMapper = ObjectMapperFactory.getObjectMapper(); - private List resourceInfoList = new ArrayList<>(); + private final List resourceInfoList = new ArrayList<>(); private ConnectionEventHandler eventHandler; - private final Map properties = new HashMap<>(); + private final Map properties = new ConcurrentHashMap<>(); private final ClientWrapper clientWrapper; private final BigInteger chainId; private final String stubConfigFilePath; - private long stubConfigFileLastModified; - public Web3Connection(ClientWrapper clientWrapper, Web3StubConfig web3StubConfig) - throws IOException { + public Web3Connection(ClientWrapper clientWrapper, String web3StubConfigPath) 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); + this.stubConfigFilePath = web3StubConfigPath; } @Override @@ -336,9 +294,16 @@ private void handleAsyncTransactionRequest(Request request, Callback callback) { } } - private synchronized void refreshStubConfig(Web3StubConfig web3StubConfig) { - this.resourceInfoList = web3StubConfig.convertToResourceInfos(); + public synchronized void refreshStubConfig(Web3StubConfig web3StubConfig) { + // update local + if (!resourceInfoList.isEmpty()) { + resourceInfoList.clear(); + } + resourceInfoList.addAll(web3StubConfig.convertToResourceInfos()); + if (!properties.isEmpty()) { + properties.clear(); + } 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()); @@ -352,6 +317,11 @@ private synchronized void refreshStubConfig(Web3StubConfig web3StubConfig) { this.addAbi(name, resource.getAbi()); } } + + // update remote + if (Objects.nonNull(eventHandler)) { + eventHandler.onResourcesChange(resourceInfoList); + } } public boolean hasProxyDeployed() { @@ -389,4 +359,12 @@ public ClientWrapper getClientWrapper() { public BigInteger getChainId() { return chainId; } + + public String getStubConfigFilePath() { + return stubConfigFilePath; + } + + public ConnectionEventHandler getEventHandler() { + return eventHandler; + } } 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 64865fa..e22ff99 100644 --- a/src/main/java/com/webank/wecross/stub/web3/Web3ConnectionFactory.java +++ b/src/main/java/com/webank/wecross/stub/web3/Web3ConnectionFactory.java @@ -14,13 +14,18 @@ public class Web3ConnectionFactory { public static Web3Connection build(String stubConfigPath, String configName) throws Exception { Web3StubConfigParser web3StubConfigParser = new Web3StubConfigParser(stubConfigPath, configName); + String configPath = web3StubConfigParser.getConfigPath(); Web3StubConfig web3StubConfig = web3StubConfigParser.loadConfig(); - return build(web3StubConfig); + return build(web3StubConfig, configPath); } - public static Web3Connection build(Web3StubConfig web3StubConfig) throws IOException { + public static Web3Connection build(Web3StubConfig web3StubConfig, String configPath) + throws IOException { logger.info("web3StubConfig: {}", web3StubConfig); ClientWrapper clientWrapper = ClientWrapperFactory.createClientWrapperInstance(web3StubConfig); - return new Web3Connection(clientWrapper, web3StubConfig); + Web3Connection web3Connection = new Web3Connection(clientWrapper, configPath); + // init + web3Connection.refreshStubConfig(web3StubConfig); + return web3Connection; } } diff --git a/src/main/java/com/webank/wecross/stub/web3/Web3Driver.java b/src/main/java/com/webank/wecross/stub/web3/Web3Driver.java index bb396ce..362610c 100644 --- a/src/main/java/com/webank/wecross/stub/web3/Web3Driver.java +++ b/src/main/java/com/webank/wecross/stub/web3/Web3Driver.java @@ -21,6 +21,8 @@ import com.webank.wecross.stub.web3.common.Web3StatusCode; import com.webank.wecross.stub.web3.common.Web3StubException; import com.webank.wecross.stub.web3.contract.BlockUtility; +import com.webank.wecross.stub.web3.custom.CommandHandler; +import com.webank.wecross.stub.web3.custom.CommandHandlerDispatcher; import com.webank.wecross.stub.web3.protocol.request.TransactionParams; import com.webank.wecross.stub.web3.protocol.response.TransactionPair; import com.webank.wecross.stub.web3.uaproof.Signer; @@ -57,12 +59,14 @@ public class Web3Driver implements Driver { private final ABICodecJsonWrapper codecJsonWrapper; private final ABICodec abiCodec; private final ABIDefinitionFactory abiDefinitionFactory; + private final CommandHandlerDispatcher commandHandlerDispatcher; - public Web3Driver() { + public Web3Driver(CommandHandlerDispatcher commandHandlerDispatcher) { CryptoSuite cryptoSuite = new CryptoSuite(CryptoType.ECDSA_TYPE); this.codecJsonWrapper = new ABICodecJsonWrapper(true); this.abiCodec = new ABICodec(cryptoSuite, true); this.abiDefinitionFactory = new ABIDefinitionFactory(cryptoSuite); + this.commandHandlerDispatcher = commandHandlerDispatcher; } @Override @@ -402,7 +406,14 @@ public void asyncCustomCommand( Account account, BlockManager blockManager, Connection connection, - CustomCommandCallback callback) {} + CustomCommandCallback callback) { + CommandHandler commandHandler = commandHandlerDispatcher.matchCommandHandler(command); + if (Objects.isNull(commandHandler)) { + callback.onResponse(new Exception("command not supported: " + command), null); + return; + } + commandHandler.handle(path, args, account, blockManager, connection, callback); + } @Override public byte[] accountSign(Account account, byte[] message) { diff --git a/src/main/java/com/webank/wecross/stub/web3/common/Web3Constant.java b/src/main/java/com/webank/wecross/stub/web3/common/Web3Constant.java index 3eed4a2..9d780d3 100644 --- a/src/main/java/com/webank/wecross/stub/web3/common/Web3Constant.java +++ b/src/main/java/com/webank/wecross/stub/web3/common/Web3Constant.java @@ -7,6 +7,7 @@ public interface Web3Constant { String STUB_TOML_NAME = "stub.toml"; String ACCOUNT_TOML_NAME = "account.toml"; String WEB3_STUB_TYPE = "WEB3"; + String WEB3_CONTRACT_TYPE = "WEB3_CONTRACT"; String WEB3_PROXY_NAME = StubConstant.PROXY_NAME; String WEB3_HUB_NAME = StubConstant.HUB_NAME; @@ -15,4 +16,6 @@ public interface Web3Constant { String WEB3_PROPERTY_CHAIN_ID = "WEB3_PROPERTY_CHAIN_ID"; String WEB3_PROPERTY_STUB_TYPE = "WEB3_PROPERTY_STUB_TYPE"; String WEB3_PROPERTY_CHAIN_URL = "WEB3_PROPERTY_CHAIN_URL"; + + String CUSTOM_COMMAND_REGISTER = "register"; } 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 28b81e9..6a291e3 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,8 +8,6 @@ public class Web3AccountConfig { private Account account; - private String accountConfigPath; - public static class Account { private String type; private String accountFile; @@ -63,22 +61,8 @@ 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 - + ", accountConfigPath='" - + accountConfigPath - + '\'' - + '}'; + return "Web3AccountConfig{" + "account=" + account + '}'; } } 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 954555d..41aa49b 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,8 +18,6 @@ public Web3AccountConfigParser(String configPath, String configName) { public Web3AccountConfig loadConfig() throws IOException { Web3Toml web3Toml = new Web3Toml(getConfigPath()); Toml toml = web3Toml.getToml(); - Web3AccountConfig web3AccountConfig = toml.to(Web3AccountConfig.class); - web3AccountConfig.setAccountConfigPath(getConfigPath()); - return web3AccountConfig; + return toml.to(Web3AccountConfig.class); } } 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 4f4908f..44a746b 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,8 +15,6 @@ public class Web3StubConfig { private Service service; private List resources; - private String stubConfigPath; - public List convertToResourceInfos() { List resourceInfos = new ArrayList<>(); for (Resource resource : this.getResources()) { @@ -71,8 +69,8 @@ public void setUrl(String url) { } public static class Resource { - private String type; private String name; + private String type; private String address; private String abi; @@ -151,14 +149,6 @@ 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{" @@ -168,9 +158,6 @@ 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 fcac873..cd24d94 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,8 +18,6 @@ public Web3StubConfigParser(String configPath, String configName) { public Web3StubConfig loadConfig() throws IOException { Web3Toml web3Toml = new Web3Toml(getConfigPath()); Toml toml = web3Toml.getToml(); - Web3StubConfig web3StubConfig = toml.to(Web3StubConfig.class); - web3StubConfig.setStubConfigPath(getConfigPath()); - return web3StubConfig; + return toml.to(Web3StubConfig.class); } } diff --git a/src/main/java/com/webank/wecross/stub/web3/custom/CommandHandler.java b/src/main/java/com/webank/wecross/stub/web3/custom/CommandHandler.java new file mode 100644 index 0000000..05f167f --- /dev/null +++ b/src/main/java/com/webank/wecross/stub/web3/custom/CommandHandler.java @@ -0,0 +1,27 @@ +package com.webank.wecross.stub.web3.custom; + +import com.webank.wecross.stub.Account; +import com.webank.wecross.stub.BlockManager; +import com.webank.wecross.stub.Connection; +import com.webank.wecross.stub.Driver; +import com.webank.wecross.stub.Path; + +public interface CommandHandler { + /** + * handle custom command + * + * @param path rule id + * @param args command args + * @param account if needs to sign + * @param blockManager if needs to verify transaction + * @param connection chain connection + * @param callback callback + */ + void handle( + Path path, + Object[] args, + Account account, + BlockManager blockManager, + Connection connection, + Driver.CustomCommandCallback callback); +} diff --git a/src/main/java/com/webank/wecross/stub/web3/custom/CommandHandlerDispatcher.java b/src/main/java/com/webank/wecross/stub/web3/custom/CommandHandlerDispatcher.java new file mode 100644 index 0000000..612a8df --- /dev/null +++ b/src/main/java/com/webank/wecross/stub/web3/custom/CommandHandlerDispatcher.java @@ -0,0 +1,25 @@ +package com.webank.wecross.stub.web3.custom; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CommandHandlerDispatcher { + private static final Logger logger = LoggerFactory.getLogger(CommandHandlerDispatcher.class); + + private final Map commandMapper = new HashMap<>(); + + public void registerCommandHandler(String command, CommandHandler commandHandler) { + commandMapper.putIfAbsent(command, commandHandler); + } + + public CommandHandler matchCommandHandler(String command) { + CommandHandler commandHandler = commandMapper.get(command); + if (Objects.isNull(commandHandler)) { + logger.warn(" Unsupported command: {}", command); + } + return commandHandler; + } +} diff --git a/src/main/java/com/webank/wecross/stub/web3/custom/RegisterResourceHandler.java b/src/main/java/com/webank/wecross/stub/web3/custom/RegisterResourceHandler.java new file mode 100644 index 0000000..6df0ce0 --- /dev/null +++ b/src/main/java/com/webank/wecross/stub/web3/custom/RegisterResourceHandler.java @@ -0,0 +1,101 @@ +package com.webank.wecross.stub.web3.custom; + +import com.moandjiezana.toml.Toml; +import com.moandjiezana.toml.TomlWriter; +import com.webank.wecross.stub.Account; +import com.webank.wecross.stub.BlockManager; +import com.webank.wecross.stub.Connection; +import com.webank.wecross.stub.Driver; +import com.webank.wecross.stub.Path; +import com.webank.wecross.stub.TransactionException; +import com.webank.wecross.stub.web3.Web3Connection; +import com.webank.wecross.stub.web3.common.Web3Constant; +import com.webank.wecross.stub.web3.common.Web3StatusCode; +import com.webank.wecross.stub.web3.config.Web3StubConfig; +import java.util.List; +import java.util.Objects; +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; + +public class RegisterResourceHandler implements CommandHandler { + private static final Logger logger = LoggerFactory.getLogger(RegisterResourceHandler.class); + + private static final TomlWriter tomlWriter = + new TomlWriter.Builder().indentValuesBy(4).padArrayDelimitersBy(1).build(); + + @Override + public synchronized void handle( + Path path, + Object[] args, + Account account, + BlockManager blockManager, + Connection connection, + Driver.CustomCommandCallback callback) { + try { + if (!(connection instanceof Web3Connection)) { + callback.onResponse( + new TransactionException( + Web3StatusCode.RegisterContractFailed, "connection not instanceof web3"), + null); + return; + } + if (Objects.isNull(args) || args.length < 3) { + callback.onResponse( + new TransactionException(Web3StatusCode.RegisterContractFailed, "incomplete args"), + null); + return; + } + Web3Connection web3Connection = (Web3Connection) connection; + String contractName = (String) args[0]; + String contractAddress = (String) args[1]; + String contractABI = (String) args[2]; + if (StringUtils.isAnyBlank(contractName, contractAddress, contractABI)) { + callback.onResponse( + new TransactionException(Web3StatusCode.RegisterContractFailed, "hava blank args"), + null); + return; + } + + String stubConfigFilePath = web3Connection.getStubConfigFilePath(); + PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); + Resource stubConfigResource = resolver.getResource(stubConfigFilePath); + Web3StubConfig web3StubConfig = + new Toml().read(stubConfigResource.getInputStream()).to(Web3StubConfig.class); + + List resources = web3StubConfig.getResources(); + + boolean existResource = false; + for (Web3StubConfig.Resource resource : resources) { + if (Objects.equals(contractName, resource.getName())) { + existResource = true; + resource.setAbi(contractABI); + resource.setAddress(contractAddress); + } + } + if (!existResource) { + Web3StubConfig.Resource resource = new Web3StubConfig.Resource(); + resource.setName(contractName); + resource.setType(Web3Constant.WEB3_CONTRACT_TYPE); + resource.setAddress(contractAddress); + resource.setAbi(contractABI); + resources.add(resource); + } + // update config file + tomlWriter.write(web3StubConfig, stubConfigResource.getFile()); + + // update local and remote + web3Connection.refreshStubConfig(web3StubConfig); + + callback.onResponse(null, Web3StatusCode.getStatusMessage(Web3StatusCode.Success)); + } catch (Exception e) { + logger.error(" register contract error", e); + callback.onResponse( + new TransactionException( + Web3StatusCode.RegisterContractFailed, "register contract error"), + null); + } + } +} diff --git a/src/main/java/com/webank/wecross/stub/web3/protocol/request/TransactionParams.java b/src/main/java/com/webank/wecross/stub/web3/protocol/request/TransactionParams.java index 8fce4bc..26280bb 100644 --- a/src/main/java/com/webank/wecross/stub/web3/protocol/request/TransactionParams.java +++ b/src/main/java/com/webank/wecross/stub/web3/protocol/request/TransactionParams.java @@ -38,8 +38,6 @@ public TransactionParams( } public enum SUB_TYPE { - SEND_TX_BY_PROXY, - CALL_BY_PROXY, SEND_TX, CALL }