Skip to content

Commit e4ebace

Browse files
committed
feat: add sawtooth-utils
Signed-off-by: Kevin O'Donnell <kevin@blockchaintp.com>
1 parent 7f9641a commit e4ebace

File tree

9 files changed

+718
-0
lines changed

9 files changed

+718
-0
lines changed

pom.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,9 @@
9090
<modules>
9191
<module>build-tools</module>
9292
<module>keymanager</module>
93+
<module>sawtooth-utils</module>
9394
</modules>
95+
9496
<build>
9597
<pluginManagement>
9698
<plugins>
@@ -300,6 +302,18 @@
300302
<artifactId>sawtooth-sdk-signing</artifactId>
301303
<version>${sawtooth.sdk.version}</version>
302304
</dependency>
305+
<dependency>
306+
<groupId>org.hyperledger.sawtooth</groupId>
307+
<artifactId>sawtooth-sdk-protos</artifactId>
308+
<version>${sawtooth.sdk.version}</version>
309+
</dependency>
310+
<dependency>
311+
<groupId>org.hyperledger.sawtooth</groupId>
312+
<artifactId>sawtooth-sdk-transaction-processor</artifactId>
313+
<version>${sawtooth.sdk.version}</version>
314+
</dependency>
315+
316+
<!-- Protobuf and related -->
303317
<dependency>
304318
<groupId>com.google.protobuf</groupId>
305319
<artifactId>protobuf-java</artifactId>

sawtooth-utils/.factorypath

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<factorypath>
2+
<factorypathentry kind="VARJAR" id="M2_REPO/org/ow2/asm/asm/6.2/asm-6.2.jar" enabled="true" runInBatchMode="false"/>
3+
<factorypathentry kind="VARJAR" id="M2_REPO/com/puppycrawl/tools/checkstyle/8.34/checkstyle-8.34.jar" enabled="true" runInBatchMode="false"/>
4+
<factorypathentry kind="VARJAR" id="M2_REPO/info/picocli/picocli/4.3.2/picocli-4.3.2.jar" enabled="true" runInBatchMode="false"/>
5+
<factorypathentry kind="VARJAR" id="M2_REPO/antlr/antlr/2.7.7/antlr-2.7.7.jar" enabled="true" runInBatchMode="false"/>
6+
<factorypathentry kind="VARJAR" id="M2_REPO/org/antlr/antlr4-runtime/4.8-1/antlr4-runtime-4.8-1.jar" enabled="true" runInBatchMode="false"/>
7+
<factorypathentry kind="VARJAR" id="M2_REPO/commons-beanutils/commons-beanutils/1.9.4/commons-beanutils-1.9.4.jar" enabled="true" runInBatchMode="false"/>
8+
<factorypathentry kind="VARJAR" id="M2_REPO/commons-logging/commons-logging/1.2/commons-logging-1.2.jar" enabled="true" runInBatchMode="false"/>
9+
<factorypathentry kind="VARJAR" id="M2_REPO/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar" enabled="true" runInBatchMode="false"/>
10+
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/guava/guava/29.0-jre/guava-29.0-jre.jar" enabled="true" runInBatchMode="false"/>
11+
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar" enabled="true" runInBatchMode="false"/>
12+
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar" enabled="true" runInBatchMode="false"/>
13+
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar" enabled="true" runInBatchMode="false"/>
14+
<factorypathentry kind="VARJAR" id="M2_REPO/org/checkerframework/checker-qual/2.11.1/checker-qual-2.11.1.jar" enabled="true" runInBatchMode="false"/>
15+
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/errorprone/error_prone_annotations/2.3.4/error_prone_annotations-2.3.4.jar" enabled="true" runInBatchMode="false"/>
16+
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar" enabled="true" runInBatchMode="false"/>
17+
<factorypathentry kind="VARJAR" id="M2_REPO/net/sf/saxon/Saxon-HE/9.9.1-7/Saxon-HE-9.9.1-7.jar" enabled="true" runInBatchMode="false"/>
18+
<factorypathentry kind="VARJAR" id="M2_REPO/org/slf4j/slf4j-api/1.8.0-beta4/slf4j-api-1.8.0-beta4.jar" enabled="true" runInBatchMode="false"/>
19+
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-core/2.14.1/log4j-core-2.14.1.jar" enabled="true" runInBatchMode="false"/>
20+
<factorypathentry kind="VARJAR" id="M2_REPO/org/apache/logging/log4j/log4j-api/2.13.0/log4j-api-2.13.0.jar" enabled="true" runInBatchMode="false"/>
21+
<factorypathentry kind="VARJAR" id="M2_REPO/org/hyperledger/sawtooth/sawtooth-sdk-signing/v0.1.3/sawtooth-sdk-signing-v0.1.3.jar" enabled="true" runInBatchMode="false"/>
22+
<factorypathentry kind="VARJAR" id="M2_REPO/org/bitcoinj/bitcoinj-core/0.14.4/bitcoinj-core-0.14.4.jar" enabled="true" runInBatchMode="false"/>
23+
<factorypathentry kind="VARJAR" id="M2_REPO/com/madgag/spongycastle/core/1.51.0.0/core-1.51.0.0.jar" enabled="true" runInBatchMode="false"/>
24+
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/guava/guava/24.0-jre/guava-24.0-jre.jar" enabled="true" runInBatchMode="false"/>
25+
<factorypathentry kind="VARJAR" id="M2_REPO/org/checkerframework/checker-compat-qual/2.0.0/checker-compat-qual-2.0.0.jar" enabled="true" runInBatchMode="false"/>
26+
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/errorprone/error_prone_annotations/2.1.3/error_prone_annotations-2.1.3.jar" enabled="true" runInBatchMode="false"/>
27+
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar" enabled="true" runInBatchMode="false"/>
28+
<factorypathentry kind="VARJAR" id="M2_REPO/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.jar" enabled="true" runInBatchMode="false"/>
29+
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/code/findbugs/jsr305/2.0.1/jsr305-2.0.1.jar" enabled="true" runInBatchMode="false"/>
30+
<factorypathentry kind="VARJAR" id="M2_REPO/net/jcip/jcip-annotations/1.0/jcip-annotations-1.0.jar" enabled="true" runInBatchMode="false"/>
31+
<factorypathentry kind="VARJAR" id="M2_REPO/org/bitcoinj/orchid/1.2.1/orchid-1.2.1.jar" enabled="true" runInBatchMode="false"/>
32+
<factorypathentry kind="VARJAR" id="M2_REPO/com/squareup/okhttp/okhttp/2.7.2/okhttp-2.7.2.jar" enabled="true" runInBatchMode="false"/>
33+
<factorypathentry kind="VARJAR" id="M2_REPO/com/squareup/okio/okio/1.6.0/okio-1.6.0.jar" enabled="true" runInBatchMode="false"/>
34+
<factorypathentry kind="VARJAR" id="M2_REPO/org/hyperledger/sawtooth/sawtooth-sdk-transaction-processor/v0.1.3/sawtooth-sdk-transaction-processor-v0.1.3.jar" enabled="true" runInBatchMode="false"/>
35+
<factorypathentry kind="VARJAR" id="M2_REPO/org/zeromq/jeromq/0.3.6/jeromq-0.3.6.jar" enabled="true" runInBatchMode="false"/>
36+
<factorypathentry kind="VARJAR" id="M2_REPO/javax/xml/bind/jaxb-api/2.3.1/jaxb-api-2.3.1.jar" enabled="true" runInBatchMode="false"/>
37+
<factorypathentry kind="VARJAR" id="M2_REPO/javax/activation/javax.activation-api/1.2.0/javax.activation-api-1.2.0.jar" enabled="true" runInBatchMode="false"/>
38+
<factorypathentry kind="VARJAR" id="M2_REPO/org/hyperledger/sawtooth/sawtooth-sdk-protos/v0.1.3/sawtooth-sdk-protos-v0.1.3.jar" enabled="true" runInBatchMode="false"/>
39+
<factorypathentry kind="VARJAR" id="M2_REPO/com/google/protobuf/protobuf-java/3.10.0/protobuf-java-3.10.0.jar" enabled="true" runInBatchMode="false"/>
40+
</factorypath>

sawtooth-utils/pom.xml

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
* Copyright 2019 Blockchain Technology Partners
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
-->
17+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
18+
<modelVersion>4.0.0</modelVersion>
19+
<parent>
20+
<groupId>com.blockchaintp</groupId>
21+
<artifactId>paralos-java</artifactId>
22+
<version>${revision}</version>
23+
</parent>
24+
<artifactId>sawtooth-utils</artifactId>
25+
<name>sawtooth-utils</name>
26+
<description>Common libraries and utilities for Sawtooth</description>
27+
28+
<properties>
29+
<proto.directory>src/main/protos</proto.directory>
30+
</properties>
31+
32+
<build>
33+
<plugins>
34+
<plugin>
35+
<groupId>org.apache.maven.plugins</groupId>
36+
<artifactId>maven-checkstyle-plugin</artifactId>
37+
</plugin>
38+
<plugin>
39+
<groupId>org.xolstice.maven.plugins</groupId>
40+
<artifactId>protobuf-maven-plugin</artifactId>
41+
</plugin>
42+
<plugin>
43+
<groupId>org.codehaus.mojo</groupId>
44+
<artifactId>build-helper-maven-plugin</artifactId>
45+
<version>3.0.0</version>
46+
<executions>
47+
<execution>
48+
<id>add-source</id>
49+
<phase>generate-sources</phase>
50+
<goals>
51+
<goal>add-source</goal>
52+
</goals>
53+
<configuration>
54+
<sources>
55+
<source>${project.build.directory}target/generated-sources/protobuf/java</source>
56+
</sources>
57+
</configuration>
58+
</execution>
59+
</executions>
60+
</plugin>
61+
</plugins>
62+
</build>
63+
64+
<dependencies>
65+
<dependency>
66+
<groupId>org.slf4j</groupId>
67+
<artifactId>slf4j-api</artifactId>
68+
</dependency>
69+
<dependency>
70+
<groupId>org.apache.logging.log4j</groupId>
71+
<artifactId>log4j-core</artifactId>
72+
</dependency>
73+
<dependency>
74+
<groupId>org.apache.logging.log4j</groupId>
75+
<artifactId>log4j-api</artifactId>
76+
</dependency>
77+
78+
<!-- BTP -->
79+
<dependency>
80+
<groupId>com.blockchaintp</groupId>
81+
<artifactId>keymanager</artifactId>
82+
<version>${project.parent.version}</version>
83+
</dependency>
84+
85+
<!-- Hyperledger Sawtooth -->
86+
<dependency>
87+
<groupId>org.hyperledger.sawtooth</groupId>
88+
<artifactId>sawtooth-sdk-transaction-processor</artifactId>
89+
</dependency>
90+
<dependency>
91+
<groupId>org.hyperledger.sawtooth</groupId>
92+
<artifactId>sawtooth-sdk-protos</artifactId>
93+
</dependency>
94+
<dependency>
95+
<groupId>com.google.protobuf</groupId>
96+
<artifactId>protobuf-java</artifactId>
97+
</dependency>
98+
99+
</dependencies>
100+
</project>
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
/*
2+
* Copyright 2019 Blockchain Technology Partners Licensed under the Apache License, Version 2.0 (the
3+
* "License"); you may not use this file except in compliance with the License. You may obtain a
4+
* copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
5+
* law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
6+
* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
7+
* for the specific language governing permissions and limitations under the License.
8+
* ------------------------------------------------------------------------------
9+
*/
10+
package com.blockchaintp.sawtooth;
11+
12+
import static org.bitcoinj.core.Utils.HEX;
13+
import static sawtooth.sdk.processor.Utils.hash512;
14+
15+
import java.nio.charset.StandardCharsets;
16+
import java.security.SecureRandom;
17+
import java.util.Collection;
18+
19+
import com.blockchaintp.keymanager.KeyManager;
20+
import com.blockchaintp.utils.VersionedEnvelopeUtils;
21+
import com.google.protobuf.ByteString;
22+
23+
import org.slf4j.Logger;
24+
import org.slf4j.LoggerFactory;
25+
26+
import sawtooth.sdk.messaging.Future;
27+
import sawtooth.sdk.messaging.Stream;
28+
import sawtooth.sdk.protobuf.Batch;
29+
import sawtooth.sdk.protobuf.BatchHeader;
30+
import sawtooth.sdk.protobuf.ClientBatchSubmitRequest;
31+
import sawtooth.sdk.protobuf.Message;
32+
import sawtooth.sdk.protobuf.Transaction;
33+
import sawtooth.sdk.protobuf.TransactionHeader;
34+
35+
/**
36+
* Utility methods and constants useful for interacting with Sawtooth as a
37+
* client.
38+
*/
39+
public final class SawtoothClientUtils {
40+
41+
42+
private SawtoothClientUtils() {
43+
}
44+
45+
/**
46+
* A SecureRandom for use in creating batches.
47+
*/
48+
private static SecureRandom secureRandom;
49+
private static int randomBytesGenerated;
50+
51+
private static final Logger LOGGER = LoggerFactory.getLogger(SawtoothClientUtils.class);
52+
53+
private static final int MAX_BYTES_PER_SEED = 10 * 1024 * 1024;
54+
55+
/**
56+
* Create a batch. Transaction passed are specified to be processed in order.
57+
*
58+
* @param keyManager A key manager handling the identity to be used for signing
59+
* etc.
60+
* @param txns a collection of transactions
61+
* @return the assembled batch
62+
*/
63+
public static Batch makeSawtoothBatch(final KeyManager keyManager, final Collection<Transaction> txns) {
64+
BatchHeader.Builder batchHeaderBldr = BatchHeader.newBuilder().clearSignerPublicKey()
65+
.setSignerPublicKey(keyManager.getPublicKeyInHex());
66+
for (Transaction tx : txns) {
67+
batchHeaderBldr.addTransactionIds(tx.getHeaderSignature());
68+
}
69+
var batchHeader = batchHeaderBldr.build();
70+
String signedHeader = keyManager.sign(batchHeader.toByteArray());
71+
return Batch.newBuilder().setHeader(batchHeader.toByteString()).setHeaderSignature(signedHeader)
72+
.addAllTransactions(txns).build();
73+
}
74+
75+
/**
76+
* Make a sawtooth transaction based on the provided parameters.
77+
*
78+
* @param keyManager a keymanager to provide the necessary identity
79+
* info
80+
* @param familyName the family name
81+
* @param familyVersion the family version
82+
* @param inputAddresses state addresses required for input to this
83+
* transaction
84+
* @param outputAddresses state addresses this transaction will output
85+
* to
86+
* @param dependentTransactionIds transaction ids this transaction is dependent
87+
* upon
88+
* @param payload the ByteString payload of this transaction
89+
* @return the transaction
90+
*/
91+
public static Transaction makeSawtoothTransaction(final KeyManager keyManager, final String familyName,
92+
final String familyVersion, final Collection<String> inputAddresses, final Collection<String> outputAddresses,
93+
final Collection<String> dependentTransactionIds, final ByteString payload) {
94+
ByteString wrappedPayload = VersionedEnvelopeUtils.wrap(payload);
95+
String payloadHash = hash512(wrappedPayload.toByteArray());
96+
TransactionHeader.Builder txnHeaderBldr = TransactionHeader.newBuilder().setFamilyName(familyName)
97+
.setFamilyVersion(familyVersion).clearBatcherPublicKey().setBatcherPublicKey(keyManager.getPublicKeyInHex())
98+
.setNonce(SawtoothClientUtils.generateNonce()).setPayloadSha512(payloadHash).addAllInputs(inputAddresses)
99+
.addAllOutputs(outputAddresses).addAllDependencies(dependentTransactionIds)
100+
.setSignerPublicKey(keyManager.getPublicKeyInHex());
101+
TransactionHeader txnHeader = txnHeaderBldr.build();
102+
103+
String signedHeader = keyManager.sign(txnHeader.toByteArray());
104+
return Transaction.newBuilder().setHeader(txnHeader.toByteString()).setHeaderSignature(signedHeader)
105+
.setPayload(wrappedPayload).build();
106+
}
107+
108+
/**
109+
* Generate a random nonce.
110+
*
111+
* @return the nonce
112+
*/
113+
public static String generateNonce() {
114+
final var seedByteCount = 20;
115+
synchronized (SawtoothClientUtils.class) {
116+
if (null == secureRandom) {
117+
LOGGER.debug("Generating nonce - acquiring SecureRandom");
118+
secureRandom = new SecureRandom();
119+
randomBytesGenerated = -1;
120+
}
121+
if (randomBytesGenerated == -1) {
122+
LOGGER.debug("Generating nonce - regenerating seed");
123+
secureRandom.setSeed(secureRandom.generateSeed(seedByteCount));
124+
randomBytesGenerated = seedByteCount;
125+
} else {
126+
randomBytesGenerated += seedByteCount;
127+
}
128+
if (randomBytesGenerated > MAX_BYTES_PER_SEED) {
129+
randomBytesGenerated = -1;
130+
}
131+
}
132+
133+
var nonceBytes = new byte[seedByteCount];
134+
LOGGER.debug("Generating nonce - generating nonce");
135+
secureRandom.nextBytes(nonceBytes);
136+
LOGGER.debug("Generating nonce - nonce generated");
137+
return HEX.encode(nonceBytes);
138+
}
139+
140+
/**
141+
* For a given string return its sha512, transform the encoding problems into
142+
* RuntimeErrors.
143+
*
144+
* @param arg a string
145+
* @return the hash512 of the string
146+
*/
147+
public static String getHash(final String arg) {
148+
byte[] data = arg.getBytes(StandardCharsets.UTF_8);
149+
return hash512(data);
150+
}
151+
152+
/**
153+
* Subit the Batch to the sawtooth Stream.
154+
*
155+
* @param batch the batch to submit
156+
* @param stream the stream to submit to
157+
* @return a Future upon which to wait
158+
*/
159+
public static Future submitBatch(final Batch batch, final Stream stream) {
160+
final ClientBatchSubmitRequest cbsReq = ClientBatchSubmitRequest.newBuilder().addBatches(batch).build();
161+
return stream.send(Message.MessageType.CLIENT_BATCH_SUBMIT_REQUEST, cbsReq.toByteString());
162+
}
163+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/* Copyright 2019 Blockchain Technology Partners
2+
Licensed under the Apache License, Version 2.0 (the "License");
3+
you may not use this file except in compliance with the License.
4+
You may obtain a copy of the License at
5+
http://www.apache.org/licenses/LICENSE-2.0
6+
Unless required by applicable law or agreed to in writing, software
7+
distributed under the License is distributed on an "AS IS" BASIS,
8+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9+
See the License for the specific language governing permissions and
10+
limitations under the License.
11+
------------------------------------------------------------------------------*/
12+
/**
13+
* Utility classes for the sawtooth in general.
14+
*/
15+
package com.blockchaintp.sawtooth;

0 commit comments

Comments
 (0)