This repository was archived by the owner on Feb 1, 2024. It is now read-only.
This repository was archived by the owner on Feb 1, 2024. It is now read-only.
Getting an Exception from the Validator when trying to make a transaction! #35
Open
Description
I tried submitting a batch with a single transaction of the intkey transaction family to a standard development Sawtooth setup. But I get the following exception from the Validator:
[2021-04-02 17:27:43.273 ERROR threadpool] (Signature) Unhandled exception during execution of task _HandlerManager.execute.<locals>.wrapped
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/sawtooth_signing/secp256k1.py", line 92, in from_hex
return Secp256k1PublicKey.from_bytes(binascii.unhexlify(hex_str))
File "/usr/lib/python3/dist-packages/sawtooth_signing/secp256k1.py", line 86, in from_bytes
public_key = secp256k1.PublicKey(byte_str, raw=True, ctx=__CTX__)
File "/usr/lib/python3/dist-packages/secp256k1/__init__.py", line 210, in __init__
self.public_key = self.deserialize(pubkey)
File "/usr/lib/python3/dist-packages/secp256k1/__init__.py", line 235, in deserialize
raise Exception("unknown public key size (expected 33 or 65)")
Exception: unknown public key size (expected 33 or 65)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/sawtooth_validator/concurrent/threadpool.py", line 83, in wrapper
return_value = fn(*args, **kwargs)
File "/usr/lib/python3/dist-packages/sawtooth_validator/networking/dispatch.py", line 444, in wrapped
return callback(self._handler.handle(connection_id, message))
File "/usr/lib/python3/dist-packages/sawtooth_validator/gossip/signature_verifier.py", line 248, in handle
if not all(map(is_valid_batch, message_content.batches)):
File "/usr/lib/python3/dist-packages/sawtooth_validator/gossip/signature_verifier.py", line 69, in is_valid_batch
public_key = Secp256k1PublicKey.from_hex(header.signer_public_key)
File "/usr/lib/python3/dist-packages/sawtooth_signing/secp256k1.py", line 94, in from_hex
raise ParseError('Unable to parse hex public key: {}'.format(e))
sawtooth_signing.core.ParseError: Unable to parse hex public key: unknown public key size (expected 33 or 65)
I am using the Sawtooth Signing SDK for creating the key pair and for signing the transaction and the batch. I found out while debugging, that the public key consists of 66 hex digits while the validator expects 33 or 65.
Here is the relevant code;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.protobuf.ByteString;
import com.storr.tp.framework.storrtpframework.transactionhandler.utils.PayloadMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.web.client.RestTemplate;
import sawtooth.sdk.processor.Utils;
import sawtooth.sdk.protobuf.*;
import sawtooth.sdk.signing.Signer;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;
public class TransactionClientImpl implements TransactionClient {
private final Signer signer;
private final PayloadMapper payloadMapper;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final ObjectMapper mapper = new ObjectMapper();
private final RestTemplate restTemplate;
private final String baseUrl;
public TransactionClientImpl(PayloadMapper payloadMapper, String baseUrl, RestTemplate restTemplate, Signer signer) {
this.payloadMapper = payloadMapper;
this.restTemplate = restTemplate;
this.baseUrl = baseUrl;
this.signer = signer;
}
public void sendTransaction(String transactionFamilyName, String transactionFamilyVersion, Collection<String> inputs, Collection<String> outputs, String action, Object payload) throws URISyntaxException {
Transaction transaction = buildTransaction(transactionFamilyName, transactionFamilyVersion, inputs, outputs, action, payload);
BatchList batchList = buildSingleBatch(transaction);
URI uri = new URI(baseUrl + "/batches");
HttpHeaders headers = new HttpHeaders();
headers.set("Content-Type", "application/octet-stream");
HttpEntity<byte[]> request = new HttpEntity<>(batchList.toByteArray(), headers);
restTemplate.postForLocation(uri, request);
}
private BatchList buildSingleBatch(Transaction transaction) {
BatchHeader batchHeader = BatchHeader.newBuilder()
.addTransactionIds(transaction.getHeaderSignature())
.build();
String batchSignature = signer.sign(batchHeader.toByteArray());
Batch batch = Batch.newBuilder()
.setHeader(batchHeader.toByteString())
.addTransactions(transaction)
.setHeaderSignature(batchSignature)
.build();
return BatchList.newBuilder()
.addBatches(batch)
.build();
}
private Transaction buildTransaction(String transactionFamilyName, String transactionFamilyVersion, Collection<String> inputs, Collection<String> outputs, String action, Object payload) {
Transaction transaction = null;
try {
Map<String, Object> payloadAsMap = mapper.convertValue(payload, new TypeReference<>() {
});
ByteString payloadBytes = payloadMapper.marshal(payloadAsMap);
String payloadHash = Utils.hash512(payloadBytes.toByteArray());
TransactionHeader transactionHeader = TransactionHeader.newBuilder()
.setSignerPublicKey(signer.getPublicKey().hex())
.setFamilyName(transactionFamilyName)
.setFamilyVersion(transactionFamilyVersion)
.addAllInputs(inputs)
.addAllOutputs(outputs)
.setPayloadSha512(payloadHash)
.setBatcherPublicKey(signer.getPublicKey().hex())
.setNonce(UUID.randomUUID().toString())
.build();
String signature = signer.sign(transactionHeader.toByteArray());
transaction = Transaction.newBuilder()
.setHeader(transactionHeader.toByteString())
.setPayload(payloadBytes)
.setHeaderSignature(signature)
.build();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
return transaction;
}
}
and the ioc configuration (I am using spring)
@Bean
public PayloadMapper payloadMapper() {
return new PayloadMapper() {
final com.fasterxml.jackson.databind.ObjectMapper objectMapper = new ObjectMapper(new CBORFactory());
@Override
public ByteString marshal(Object object) throws Exception {
return ByteString.copyFrom(objectMapper.writeValueAsBytes(object));
}
@Override
public LinkedHashMap<String, Object> unmarshal(ByteString data) throws Exception {
return objectMapper.readValue(data.toByteArray(), new TypeReference<>() {
});
}
};
}
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
@Bean
public Context context(@Value("secp256k1") String algorithm) {
return CryptoFactory.createContext(algorithm);
}
@Bean
public Signer signer(@Value("secp256k1") String algorithm) {
Context context = context(algorithm);
return new Signer(context, context.newRandomPrivateKey());
}
@Bean
public TransactionClient transactionClient(@Value("http://127.0.0.1:8008") String baseUrl, @Value("secp256k1") String algorithm) {
return new TransactionClientImpl(payloadMapper(), baseUrl, restTemplate(), signer(algorithm));
}
I think this might be a bug from the Sawtooth Signing SDK.
Metadata
Metadata
Assignees
Labels
No labels