Blockchain 由于状态根哈希不匹配Hyperledger锯齿,TP在块被拒绝后未接收事务

Blockchain 由于状态根哈希不匹配Hyperledger锯齿,TP在块被拒绝后未接收事务,blockchain,hyperledger,hyperledger-sawtooth,Blockchain,Hyperledger,Hyperledger Sawtooth,我已经从锯齿文档中设置了Hyperlder锯齿网络,您可以在这里找到docker compose.yaml我用于设置网络: 事务处理器代码: const{TransactionHandler}=require('sawtooth-sdk/processor/handler'); const{InvalidTransaction}=require('sawtooth-sdk/处理器/异常'); const{TextEncoder,TextDecoder}=require('text-encodi

我已经从
锯齿文档
中设置了
Hyperlder锯齿网络
,您可以在这里找到
docker compose.yaml
我用于设置网络:

事务处理器代码:

const{TransactionHandler}=require('sawtooth-sdk/processor/handler');
const{InvalidTransaction}=require('sawtooth-sdk/处理器/异常');
const{TextEncoder,TextDecoder}=require('text-encoding/lib/encoding');
const crypto=require('crypto');
常量散列=(x)=>{
返回crypto.createHash('sha512').update(x).digest('hex').toLowerCase();
}
常量编码器=新的文本编码器('utf8');
const decoder=新的文本解码器('utf8');
const TP_FAMILY=‘杂货店’;
const TP_NAMESPACE=_hash(TP_FAMILY).substring(0,6);
类GroceryHandler扩展了TransactionHandler{
构造函数(){
超级(TP_系列,['1.0.0'],[TP_命名空间];
这是超时=500;
}
应用(请求、上下文){
log('Transaction Processor Called!');
这._context=context;
这个._请求=请求;
常量操作=['createOrder'];
试一试{
让payload=JSON.parse(decoder.decode(request.payload));
让动作=payload.action
如果(!action | |!actions.includes(action)){
抛出新的InvalidTransaction(`Upsupported action“${action}”!`);
}
试一试{
返回此[操作](有效载荷.数据);
}捕获(e){
控制台日志(e);
}
}捕获(e){
抛出新的InvalidTransaction('传递有效的json字符串');
}
}
createOrder(有效负载){
log('Creating order!');
让数据={
id:payload.id,
状态:payload.status,
创建位置:Math.floor((新日期()).getTime()/1000)
};
返回此._setEntry(此._makeAddress(payload.id),数据);
}    
_setEntry(地址、有效负载){
让dataBytes=encoder.encode(JSON.stringify(payload));
让条目={
[地址]:数据字节
}
返回此._context.setState(条目);
}
_生成地址(id){
返回TP_名称空间+_散列(id).substr(0,64);
}
}
const transactionProcessor=新的transactionProcessor('tcp://validator:4004');
addHandler(新的GroceryHandler());
transactionProcessor.start();
客户端代码:

const{createContext,CryptoFactory}=require('sawtooth-sdk/signing');
const{protobuf}=require('sawtooth-sdk');
const{textcodector}=require('text-encoding/lib/encoding');
const request=require('request');
const crypto=require('crypto');
常量编码器=新的文本编码器('utf8');
常量散列=(x)=>{
返回crypto.createHash('sha512').update(x).digest('hex').toLowerCase();
}
const TP_FAMILY=‘杂货店’;
const TP_NAMESPACE=_hash(TP_FAMILY).substr(0,6);
const context=createContext('secp256k1');
const privateKey=context.newRandomPrivateKey();
const signer=新加密工厂(上下文).newSigner(私钥);
让有效载荷={
操作:“创建订单”,
数据:{
id:'1'
}
};
const address=TP_NAMESPACE+_hash(payload.id).substr(0,64);
const payloadBytes=encoder.encode(JSON.stringify(payload));
const transactionHeaderBytes=protobuf.TransactionHeader.encode({
家族名称:TP_家族,
家庭版本:“1.0.0”,
输入:[地址],
输出:[地址],
signerPublicKey:signer.getPublicKey().asHex(),
batcherPublicKey:signer.getPublicKey().asHex(),
依赖项:[],
payloadSha512:_散列(payloadBytes)
}).finish();
const transactionHeaderSignature=signer.sign(transactionHeaderBytes);
const transaction=protobuf.transaction.create({
标题:transactionHeaderBytes,
headerSignature:transactionHeaderSignature,
有效载荷:payloadBytes
});
const transactions=[事务]
常量batchHeaderBytes=protobuf.BatchHeader.encode({
signerPublicKey:signer.getPublicKey().asHex(),
TransactionId:transactions.map((txn)=>txn.headerSignature),
}).finish();
常量batchHeaderSignature=signer.sign(batchHeaderBytes)
const batch=protobuf.batch.create({
标题:batchHeaderBytes,
headerSignature:batchHeaderSignature,
交易:交易
});
const batchListBytes=protobuf.BatchList.encode({
批次:[批次]
}).finish();
请寄({
网址:'http://localhost:8008/batches',
正文:batchListBytes,
标题:{“内容类型”:“应用程序/八位字节流”}
},(错误,响应)=>{
如果(错误){
返回console.log(err);
}
console.log(response.body);
});
验证程序日志:

事务处理器日志:

在验证程序日志中的以下条目之后,我没有收到任何发送给处理器的事务

[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

当sawtooth处理一个事务时,它会多次将它发送到TP,然后比较多个调用之间的哈希值,以确保返回相同的结果。如果在TP中,您正在生成不同的地址或存储在某个地址的数据变体,则事务将失败

sawtooth中的一句名言是,TP对于每个事务都必须是确定性的,换句话说,它类似于函数编程中的规则:使用相同事务调用相同的TP应该产生相同的结果

注意事项:

  • 小心不要构造包含时间戳元素、增量计数或其他随机信息位的地址
  • 小心不要对存储在某个地址的数据执行相同的操作

  • 这不是诗人的问题吗?若否,问题是否已解决??如果你想自己回答这个问题,那么其他人可能会受益。@FrankC。不,这不是诗人的问题,这是验证和提交之间的状态变化,如果你能将其作为答案发布,我将接受并标记为answ
    [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