diff --git a/leigh-chain-pki-pkitool/build.gradle b/leigh-chain-pki-pkitool/build.gradle index fa8ee3a8a85b29d37a41a9d32861e1f0ba9455a3..89f4dbf4007ecd63113e5f7f231b3c392219e0c6 100644 --- a/leigh-chain-pki-pkitool/build.gradle +++ b/leigh-chain-pki-pkitool/build.gradle @@ -18,4 +18,8 @@ dependencies { test { useJUnitPlatform() -} \ No newline at end of file +} + +application { + mainClass = 'leigh.chain.pki.pkitool.PKITool' +} diff --git a/leigh-chain-pki-pkitool/src/main/java/leigh/chain/pki/pkitool/PKITool.java b/leigh-chain-pki-pkitool/src/main/java/leigh/chain/pki/pkitool/PKITool.java new file mode 100644 index 0000000000000000000000000000000000000000..7901832ea48ea45871e20c8b46de4b710f4c439c --- /dev/null +++ b/leigh-chain-pki-pkitool/src/main/java/leigh/chain/pki/pkitool/PKITool.java @@ -0,0 +1,85 @@ +package leigh.chain.pki.pkitool; + +import leigh.chain.pki.PKI; +import leigh.mecha.json.JSONObject; +import leigh.mecha.log.MechaLogger; +import leigh.mecha.log.MechaLoggerFactory; +import leigh.mecha.util.UniversalJob; +import org.apache.commons.lang.StringUtils; +import org.web3j.crypto.CipherException; + +import java.io.IOException; + +/** + * The PKI tool is a low-level command-line tool for originating PKI transactions. Through + * the use of this tool it is possible to claim names, create secondaries, and issue + * burn notices. + *
+ * The following environment variables must be set to use this tool:
+ *
+ * LC_GETH_URL
- The GETH RPC URL. e.g. http://localhost:8545
+ * LC_PKI_PRIMARY_WALLET
- The path to the primary wallet file.
+ * LC_PKI_PRIMARY_PW
- The password for the primary wallet file.
+ *
+ * Upon normal operation the tool will output a JSON object to STDOUT containing relevant information. Additional
+ * information & logging may be provided to STDERR.
+ *
+ * @author C. Alexander Leigh
+ */
+public class PKITool {
+ private static final MechaLogger logger = MechaLoggerFactory.getLogger(PKITool.class);
+ public static String ENV_PRIMARY_WALLET = "LC_PKI_PRIMARY_WALLET";
+ public static String ENV_PRIMARY_PW = "LC_PKI_PRIMARY_PW";
+ public static String ENV_GETH_URL = "LC_GETH_URL";
+
+ public static void main(String[] args) throws CipherException, IOException {
+ UniversalJob.banner(logger, "PKITool");
+
+ String wallet = System.getenv(ENV_PRIMARY_WALLET);
+ String walletPw = System.getenv(ENV_PRIMARY_PW);
+ String gethUrl = System.getenv(ENV_GETH_URL);
+
+ if (StringUtils.isEmpty(wallet)) {
+ logger.error(ENV_PRIMARY_WALLET + " environment variable must be set.");
+ System.exit(UniversalJob.RET_BADENV);
+ }
+
+ if (StringUtils.isEmpty(walletPw)) {
+ logger.error(ENV_PRIMARY_PW + " environment variable must be set.");
+ System.exit(UniversalJob.RET_BADENV);
+ }
+
+ if (StringUtils.isEmpty(gethUrl)) {
+ logger.error(ENV_GETH_URL + " environment variable must be set.");
+ System.exit(UniversalJob.RET_BADENV);
+ }
+
+ if (args.length != 3) {
+ logger.info("Usage: PKITool name validityDays serviceUrl");
+ System.exit(UniversalJob.RET_BADARGS);
+ }
+
+ // PkiTool name validityPeriod serviceUrl
+ String name = args[0];
+ int validityDays = Integer.parseInt(args[1]);
+ String serviceUrl = args[2];
+
+ String txnHash = PKI.submitNameClaim(gethUrl, wallet, walletPw, name, serviceUrl, validityDays);
+
+ if (txnHash == null) {
+ logger.error("Submission failed.");
+ JSONObject jo = new JSONObject();
+ jo.put("status", "error");
+ System.out.println(jo);
+ System.exit(UniversalJob.RET_ERROR);
+ }
+
+ logger.info("Name claim submitted. [txnHash: {}] [name: {}] [validity: {}] [serviceUrl: {}]",
+ txnHash, name, validityDays, serviceUrl);
+
+ JSONObject jo = new JSONObject();
+ jo.put("txnHash", txnHash);
+ jo.put("status", "ok");
+ System.out.println(jo);
+ }
+}
diff --git a/leigh-chain-pki/src/main/java/leigh/chain/pki/NameClaim.java b/leigh-chain-pki/src/main/java/leigh/chain/pki/NameClaim.java
index 79344662ca5b3e25febe9a4d95095e8ba42e346c..aa6bc9af444de659a166133feca550b2a28d5813 100644
--- a/leigh-chain-pki/src/main/java/leigh/chain/pki/NameClaim.java
+++ b/leigh-chain-pki/src/main/java/leigh/chain/pki/NameClaim.java
@@ -9,20 +9,22 @@ import leigh.mecha.json.JSONObject;
*/
public class NameClaim {
public static String KEY_NAME = "n";
- public static String KEY_SERVICEURL = "s";
- public static String KEY_VALIDDAYS = "v";
+ public static String KEY_SERVICE_URL = "s";
+ public static String KEY_VALIDITY_DAYS = "v";
public static int MAX_VALIDITY = 31 * 6;
- private final String address;
private final String name;
- private final String serviceName;
+ private final String serviceUrl;
private final int validityDays;
- public NameClaim(String address, String name, String serviceName, int validityDays) {
- this.address = address;
+ public NameClaim(String name, String serviceUrl, int validityDays) {
this.name = name;
- this.serviceName = serviceName;
+ this.serviceUrl = serviceUrl;
this.validityDays = validityDays;
+
+ if (validityDays < 0 || validityDays > MAX_VALIDITY) {
+ throw new IllegalArgumentException("Invalid validity period.");
+ }
}
/**
@@ -34,21 +36,17 @@ public class NameClaim {
public String toJSON() {
JSONObject obj = new JSONObject();
obj.put(KEY_NAME, name);
- obj.put(KEY_SERVICEURL, serviceName);
- obj.put(KEY_VALIDDAYS, validityDays);
+ obj.put(KEY_SERVICE_URL, serviceUrl);
+ obj.put(KEY_VALIDITY_DAYS, validityDays);
return obj.toString();
}
- public String getAddress() {
- return address;
- }
-
public String getName() {
return name;
}
- public String getServiceName() {
- return serviceName;
+ public String getServiceUrl() {
+ return serviceUrl;
}
public int getValidityDays() {
diff --git a/leigh-chain-pki/src/main/java/leigh/chain/pki/PKI.java b/leigh-chain-pki/src/main/java/leigh/chain/pki/PKI.java
new file mode 100644
index 0000000000000000000000000000000000000000..47e6dc04d99a3dc3c6600108d9f0117b25394990
--- /dev/null
+++ b/leigh-chain-pki/src/main/java/leigh/chain/pki/PKI.java
@@ -0,0 +1,34 @@
+package leigh.chain.pki;
+
+import leigh.chain.LeighChain;
+import leigh.mecha.log.MechaLogger;
+import leigh.mecha.log.MechaLoggerFactory;
+import org.web3j.crypto.CipherException;
+import org.web3j.crypto.WalletUtils;
+
+import java.io.IOException;
+
+/**
+ * This class provides convenience functions for interacting with the PKI on the LeighChain.
+ *
+ * @author Alex Leigh
+ */
+public class PKI {
+ private static final MechaLogger logger = MechaLoggerFactory.getLogger(PKI.class);
+
+ /**
+ * Submit a name claim to the LeighChain.
+ *
+ * validityDays
must be valid. If it is not, an exception will be thrown.
+ */
+ public static String submitNameClaim(String gethUrl, String wallet, String walletPw,
+ String name, String serviceUrl, int validityDays) throws CipherException, IOException {
+ // This will throw if the validity period is illegal
+ NameClaim claim = new NameClaim(name, serviceUrl, validityDays);
+
+ logger.info("Is name claim addr valid: {}",
+ WalletUtils.isValidAddress(PKIAddresses.OP_NAME_CLAIM));
+
+ return LeighChain.submit(gethUrl, wallet, walletPw, PKIAddresses.OP_NAME_CLAIM, claim.toJSON());
+ }
+}
diff --git a/leigh-chain-pki/src/main/java/leigh/chain/pki/PKIAddresses.java b/leigh-chain-pki/src/main/java/leigh/chain/pki/PKIAddresses.java
index e4e807c59e7a403696c06c500ee204ffede04db9..1944b3aab3818a1cc2725284dcdcb063cef14b8d 100644
--- a/leigh-chain-pki/src/main/java/leigh/chain/pki/PKIAddresses.java
+++ b/leigh-chain-pki/src/main/java/leigh/chain/pki/PKIAddresses.java
@@ -1,10 +1,10 @@
package leigh.chain.pki;
/**
- * This class contains well known LEIGHChain addresses for various PKI transactions.
+ * This class contains well-known LEIGHChain addresses for various PKI transactions.
*
* @author Alex Leigh
*/
public class PKIAddresses {
- public static String OP_NAME_CLAIM = "0x2948FbECa204b54d733bC7298416EA2d6f8fa3A1";
+ public static String OP_NAME_CLAIM = "0x2948fbeca204b54d733bc7298416ea2d6f8fa3a1";
}
diff --git a/leigh-chain-pki/src/test/java/leigh/chain/pki/NameClaimTest.java b/leigh-chain-pki/src/test/java/leigh/chain/pki/NameClaimTest.java
index b9a08e6631241fb3a1cef5e3900a5e74afa86687..50069522a40ba18956f4c4fd425fa579e104ea5f 100644
--- a/leigh-chain-pki/src/test/java/leigh/chain/pki/NameClaimTest.java
+++ b/leigh-chain-pki/src/test/java/leigh/chain/pki/NameClaimTest.java
@@ -9,7 +9,7 @@ public class NameClaimTest {
@Test
public void testThing() {
- NameClaim claim = new NameClaim("0x0", "leigh",
+ NameClaim claim = new NameClaim("leigh",
"http://leigh-co.com/service.json", NameClaim.MAX_VALIDITY);
String json = claim.toJSON();
logger.info("Built msg: {}", json);
diff --git a/leigh-chain/src/main/java/leigh/chain/LeighChain.java b/leigh-chain/src/main/java/leigh/chain/LeighChain.java
new file mode 100644
index 0000000000000000000000000000000000000000..3fe431553df5bde3abd7d9381a7686375e070294
--- /dev/null
+++ b/leigh-chain/src/main/java/leigh/chain/LeighChain.java
@@ -0,0 +1,67 @@
+package leigh.chain;
+
+import leigh.mecha.log.MechaLogger;
+import leigh.mecha.log.MechaLoggerFactory;
+import org.web3j.crypto.*;
+import org.web3j.protocol.Web3j;
+import org.web3j.protocol.core.DefaultBlockParameterName;
+import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
+import org.web3j.protocol.core.methods.response.EthSendTransaction;
+import org.web3j.protocol.http.HttpService;
+import org.web3j.utils.Convert;
+import org.web3j.utils.Numeric;
+
+import java.io.IOException;
+import java.math.BigInteger;
+
+/**
+ * This class implements convenience methods for interacting with the LeighChain.
+ *
+ * @author Alex Leigh
+ */
+public class LeighChain {
+ private static final MechaLogger logger = MechaLoggerFactory.getLogger(LeighChain.class);
+
+ /**
+ * Submit a zero-value eth 1.0 transaction to the LeighChain via geth. The gas limit and
+ * price are set to 21,000.
+ *
+ * If successful, the transaction hash is returned. This hash can be used to monitor + * the process of the transaction to determine if it is eventually mined into a block. + */ + public static String submit(String gethUrl, String wallet, String walletPw, + String destAddr, String data) + throws CipherException, IOException { + Web3j web3 = Web3j.build(new HttpService(gethUrl)); + + Credentials credentials = WalletUtils.loadCredentials(walletPw, wallet); + + BigInteger gasLimit = BigInteger.valueOf(21000); + BigInteger gasPrice = Convert.toWei("21000", Convert.Unit.GWEI).toBigInteger(); + EthGetTransactionCount ethGetTransactionCount = web3.ethGetTransactionCount(credentials.getAddress(), + DefaultBlockParameterName.LATEST).send(); + BigInteger nonce = ethGetTransactionCount.getTransactionCount(); + + // There is basically a race here, since if something else publishes, we'll duplicate + // the nonce. There is basically nothing to be done about this. + + RawTransaction rawTransaction = RawTransaction.createTransaction( + nonce, + gasPrice, + gasLimit, + "destAddr", + BigInteger.valueOf(0), data); + + byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials); + + // Convert it to Hexadecimal String to be sent to the node + String hexValue = Numeric.toHexString(signedMessage); + EthSendTransaction ethSendTransaction = web3.ethSendRawTransaction(hexValue).send(); + + String txHash = ethSendTransaction.getTransactionHash(); + + logger.info("Transaction posted. [hash: {}]", txHash); + + return txHash; + } +} diff --git a/leigh-mecha/src/main/java/leigh/mecha/util/UniversalJob.java b/leigh-mecha/src/main/java/leigh/mecha/util/UniversalJob.java index 9c344326cfa8dfd5579e3dbe619ef8c571e20a6c..018debcb9bd0422cee84f3f2761a1e3e1468be86 100644 --- a/leigh-mecha/src/main/java/leigh/mecha/util/UniversalJob.java +++ b/leigh-mecha/src/main/java/leigh/mecha/util/UniversalJob.java @@ -29,6 +29,7 @@ public final class UniversalJob { public static final int RET_ERROR = 3; // Bad properties file public static final int RET_PROPS = 4; + public static final int RET_BADENV = 5; private static String DEFAULT_COPYRIGHT = "2004-2022 Alex Leigh";