我已经设置了一个Hyperlder Sawtooth Network
,Sawtooth Docs
你可以docker-compose.yaml
在这里找到我用来设置网络的地方:
https://sawtooth.hyperledger.org/docs/core/releases/1.0/app_developers_guide/sawtooth-default.yaml
事务处理器代码:
const { TransactionHandler } = require('sawtooth-sdk/processor/handler');
const { InvalidTransaction } = require('sawtooth-sdk/processor/exceptions');
const { TextEncoder, TextDecoder } = require('text-encoding/lib/encoding');
const crypto = require('crypto');
const _hash = (x) => {
return crypto.createHash('sha512').update(x).digest('hex').toLowerCase();
}
const encoder = new TextEncoder('utf8');
const decoder = new TextDecoder('utf8');
const TP_FAMILY = 'grocery';
const TP_NAMESPACE = _hash(TP_FAMILY).substring(0, 6);
class GroceryHandler extends TransactionHandler {
constructor() {
super(TP_FAMILY, ['1.0.0'], [TP_NAMESPACE]);
this.timeout = 500;
}
apply(request, context) {
console.log('Transaction Processor Called!');
this._context = context;
this._request = request;
const actions = ['createOrder'];
try {
let payload = JSON.parse(decoder.decode(request.payload));
let action = payload.action
if(!action || !actions.includes(action)) {
throw new InvalidTransaction(`Upsupported action "${action}"!`);
}
try {
return this[action](payload.data);
} catch(e) {
console.log(e);
}
} catch(e) {
throw new InvalidTransaction('Pass a valid json string.');
}
}
createOrder(payload) {
console.log('Creating order!');
let data = {
id: payload.id,
status: payload.status,
created_at: Math.floor((new Date()).getTime() / 1000)
};
return this._setEntry(this._makeAddress(payload.id), data);
}
_setEntry(address, payload) {
let dataBytes = encoder.encode(JSON.stringify(payload));
let entries = {
[address]: dataBytes
}
return this._context.setState(entries);
}
_makeAddress(id) {
return TP_NAMESPACE + _hash(id).substr(0,64);
}
}
const transactionProcessor = new TransactionProcessor('tcp://validator:4004');
transactionProcessor.addHandler(new GroceryHandler());
transactionProcessor.start();
客户端代码:
const { createContext, CryptoFactory } = require('sawtooth-sdk/signing');
const { protobuf } = require('sawtooth-sdk');
const { TextEncoder } = require('text-encoding/lib/encoding');
const request = require('request');
const crypto = require('crypto');
const encoder = new TextEncoder('utf8');
const _hash = (x) => {
return crypto.createHash('sha512').update(x).digest('hex').toLowerCase();
}
const TP_FAMILY = 'grocery';
const TP_NAMESPACE = _hash(TP_FAMILY).substr(0, 6);
const context = createContext('secp256k1');
const privateKey = context.newRandomPrivateKey();
const signer = new CryptoFactory(context).newSigner(privateKey);
let payload = {
action: 'create_order',
data: {
id: '1'
}
};
const address = TP_NAMESPACE + _hash(payload.id).substr(0, 64);
const payloadBytes = encoder.encode(JSON.stringify(payload));
const transactionHeaderBytes = protobuf.TransactionHeader.encode({
familyName: TP_FAMILY,
familyVersion: '1.0.0',
inputs: [address],
outputs: [address],
signerPublicKey: signer.getPublicKey().asHex(),
batcherPublicKey: signer.getPublicKey().asHex(),
dependencies: [],
payloadSha512: _hash(payloadBytes)
}).finish();
const transactionHeaderSignature = signer.sign(transactionHeaderBytes);
const transaction = protobuf.Transaction.create({
header: transactionHeaderBytes,
headerSignature: transactionHeaderSignature,
payload: payloadBytes
});
const transactions = [transaction]
const batchHeaderBytes = protobuf.BatchHeader.encode({
signerPublicKey: signer.getPublicKey().asHex(),
transactionIds: transactions.map((txn) => txn.headerSignature),
}).finish();
const batchHeaderSignature = signer.sign(batchHeaderBytes)
const batch = protobuf.Batch.create({
header: batchHeaderBytes,
headerSignature: batchHeaderSignature,
transactions: transactions
});
const batchListBytes = protobuf.BatchList.encode({
batches: [batch]
}).finish();
request.post({
url: 'http://localhost:8008/batches',
body: batchListBytes,
headers: { 'Content-Type': 'application/octet-stream' }
}, (err, response) => {
if (err) {
return console.log(err);
}
console.log(response.body);
});
验证者日志:https ://justpaste.it/74y5g
事务处理器日志:https ://justpaste.it/5ayn6
> grocery-tp@1.0.0 start /processor
> node index.js tcp://validator:4004
Connected to tcp://validator:4004
Registration of [grocery 1.0.0] succeeded
Transaction Processor Called!
Creating order!
Transaction Processor Called!
Creating order!
Transaction Processor Called!
Creating order!
Transaction Processor Called!
Creating order!
Transaction Processor Called!
Creating order!
Transaction Processor Called!
Creating order!
Transaction Processor Called!
Creating order!
在验证器日志中输入以下条目后,我没有收到任何发送给处理器的交易。
[2018-07-04 10:39:18.026 DEBUG block_validator] Block(c9636780f4babea6b8103665bc1fb19a59ce0ba66289494fc61972e97423a3273dd1d41e93ddf90c933809dab5350a0a83b282aaf25ebdcc6619735e25d8b337 (block_num:75, state:00704f66a517e79dc064e63586b12d677a3b60ce25363a4654fa819a59e4132c, previous_block_id:32b07cd79093aee0b7833b8924c8fef01fce798f3d58560c83c9891b2c05c02f2a4b894de43503fdcb0f129e9f365cfbdc415b798877393f7e75598195ad3c94)) rejected due to state root hash mismatch: 00704f66a517e79dc064e63586b12d677a3b60ce25363a4654fa819a59e4132c != e52737049078b9e0f149bb58fc4938473a5e889fa427536b0e862c4728df5004