Back

Explore Courses Blog Tutorials Interview Questions
0 votes
2 views
in Blockchain by (4.1k points)

I have started playing around with Hyperledger Sawtooth recently and having trouble to submit transactions on java, while python code seems okay.

I have prepared the python code based on the API docs here and then tried to write one in java as well. Below is the code in java: 

import com.google.protobuf.ByteString;

import com.mashape.unirest.http.Unirest;

import sawtooth.sdk.processor.Utils;

import sawtooth.sdk.protobuf.*;

import java.security.KeyPair;

import java.security.KeyPairGenerator;

import java.security.Signature;

import java.security.spec.ECGenParameterSpec;

public class BatchSender {

    public static void main(String[] args) throws Exception{

        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC");

        ECGenParameterSpec parameterSpec = new ECGenParameterSpec("secp256k1");

        keyPairGenerator.initialize(parameterSpec);

        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        Signature ecdsaSign = Signature.getInstance("SHA256withECDSA");

        ecdsaSign.initSign(keyPair.getPrivate());

        byte[] publicKeyBytes = keyPair.getPublic().getEncoded();

        String publicKeyHex = Utils.hash512(publicKeyBytes);

        ByteString publicKeyByteString = ByteString.copyFrom(new String(publicKeyBytes),"UTF-8");

        String payload = "{'key':1, 'value':'value comes here'}";

        String payloadBytes = Utils.hash512(payload.getBytes());

        ByteString payloadByteString  = ByteString.copyFrom(payload.getBytes());

        TransactionHeader txnHeader = TransactionHeader.newBuilder().

                setBatcherPubkeyBytes(publicKeyByteString).

                setFamilyName("plain_info").

                setFamilyVersion("1.0").

      addInputs("1cf1266e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7").

                setNonce("1").

           addOutputs("1cf1266e282c41be5e4254d8820772c5518a2c5a8c0c7f7eda19594a7eb539453e1ed7").

                setPayloadEncoding("application/json").

                setPayloadSha512(payloadBytes).

                setSignerPubkey(publicKeyHex).build();

        ByteString txnHeaderBytes = txnHeader.toByteString();

        ecdsaSign.update(txnHeaderBytes.toByteArray());

        byte[] txnHeaderSignature = ecdsaSign.sign();

        Transaction txn = Transaction.newBuilder().setHeader(txnHeaderBytes).setPayload(payloadByteString).setHeaderSignature(Utils.hash512(txnHeaderSignature)).build();

        BatchHeader batchHeader = BatchHeader.newBuilder().setSignerPubkey(publicKeyHex).addTransactionIds(txn.getHeaderSignature()).build();

        ByteString batchHeaderBytes = batchHeader.toByteString();

        ecdsaSign.update(batchHeaderBytes.toByteArray());

        byte[] batchHeaderSignature = ecdsaSign.sign();

        Batch batch = Batch.newBuilder().setHeader(batchHeaderBytes).setHeaderSignature(Utils.hash512(batchHeaderSignature)).addTransactions(txn).build();

        BatchList batchList = BatchList.newBuilder().addBatches( batch).build();

        ByteString batchBytes = batchList.toByteString();

        String serverResponse =  Unirest.post("http://rest-api:8080/batches").header("Content-Type","application/octet-stream").body(batchBytes.toByteArray()).asString().getBody();

        System.out.println(serverResponse);

    }

}​​​​​​

Once I run it, I am getting

{

  "error": {

    "code": 30,

    "message": "The submitted BatchList was rejected by the validator. It was poorly formed, or has an invalid signature.",

    "title": "Submitted Batches Invalid"

  }

}

On the docker's logs, I can see

sawtooth-validator-default | [2017-11-21 08:20:09.842 DEBUG    interconnect] ServerThread receiving CLIENT_BATCH_SUBMIT_REQUEST message: 1242 bytes

sawtooth-validator-default | [2017-11-21 08:20:09.844 DEBUG    signature_verifier] batch failed signature validation: 30a2f4a24be3e624f5a35b17cb505b65cb8dd41600545c6dcfac7534205091552e171082922d4eb71f1bb186fe49163f349c604b631f64fa8f1cfea1c8bb2818

sawtooth-validator-default | [2017-11-21 08:20:09.844 DEBUG    interconnect] ServerThread sending CLIENT_BATCH_SUBMIT_RESPONSE to b'50b094689ac14b39'

I have checked the key sizes and verify the signature, and it seems all ok, however, I couldn't find why the batch is rejected...

Anyone had a similar error response from sawtooth before? is it the batch format or still signature issue for the code above?

1 Answer

0 votes
by (14.4k points)

The problem here is simple and easy to fix. While setting the batch header and transaction header signatures, you should make sure that these bytes are encoded as hash strings. Also, keep in mind that the sha-512 hash should not be taken off from those signatures.
 

You can find the solution to this problem by using the following code lines: 

import org.apache.commons.codec.binary.Hex;

Transaction trans = Transaction.newBuilder()

                      .setHeader(transHeaderBytes)

                      .setPayload(payloadByteString)

                      .setHeaderSignature(Hex.encodeHexString(transHeaderSignature))

                    .build();

  

Also, remember that Utils.sha512 must only be used on payload bytes.

Browse Categories

...