Hyperledger Fabri c Node.js SDK: проблема с сигнатурами автономных транзакций - PullRequest
1 голос
/ 14 января 2020

Я пытаюсь следовать этому руководству: https://hyperledger.github.io/fabric-sdk-node/release-1.4/tutorial-sign-transaction-offline.html

Я создал полную сеть Hyperledger Fabri c, используя это руководство: https://hyperledger-fabric-ca.readthedocs.io/en/latest/operations_guide.html

SDK Javascript работает хорошо, и я могу запрашивать / вызывать транзакции с помощью метода client.setUserContext ().

При попытке подписать транзакцию в автономном режиме предложение по транзакции отклоняется одноранговые узлы со следующим ответом:

{ Error: 2 UNKNOWN: access denied: channel [mychannel] creator org [org1]
      at Object.exports.createStatusError ([...]/node_modules/grpc/src/common.js:91:15)
      at Object.onReceiveStatus ([...]/node_modules/grpc/src/client_interceptors.js:1204:28)
      at InterceptingListener._callNext ([...]/node/node_modules/grpc/src/client_interceptors.js:568:42)
      at InterceptingListener.onReceiveStatus ([...]/node/node_modules/grpc/src/client_interceptors.js:618:8)
      at callback ([...]/node/node_modules/grpc/src/client_interceptors.js:845:24)
    code: 2,
    metadata: Metadata { _internal_repr: {} },
    details: 'access denied: channel [mychannel] creator org [org1]' }

В журналах одноранговых узлов я вижу следующую ошибку:

peer1-org1       | 2020-01-13 21:47:31.569 UTC [protoutils] ValidateProposalMessage -> WARN 078 channel [mychannel]: creator's signature over the proposal is not valid: The signature is invalid

Я не понимаю, почему подпись отклонена. Я внимательно следил за всеми этапами урока. Вот полный код клиента:

//
// Imports
//
var Client = require('fabric-client');
var path = require('path');
var util = require('util');
var fs = require('fs');
const crypto = require('crypto');
const elliptic = require('elliptic');
const { KEYUTIL } = require('jsrsasign');
const config = require('./config');

//
// Script configuartion variables
//
var fcn = 'set';
var args = ["a","60"];
var priv = fs.readFileSync(config.PRIV, 'utf8');
var { prvKeyHex } = KEYUTIL.getKey(priv,'passphrase'); 
var cert = fs.readFileSync(config.CERT, 'utf8');
const EC = elliptic.ec;
const ecdsaCurve = elliptic.curves['p256'];
const ecdsa = new EC(ecdsaCurve);
const signKey = ecdsa.keyFromPrivate(prvKeyHex, 'hex');


//
// Config init
//
var client = Client.loadFromConfig('network_org1.yaml');
var targets = client.getPeersForOrg('org1');

// 
// Main
// 
client.initCredentialStores()
.then((nothing) => {

channel = client.getChannel(config.CHANNEL_NAME);

// 1. Generate unsigned transaction proposal
var transaction_proposal = {
  chaincodeId: config.CHAINCODE_NAME,
  channelId: config.CHANNEL_NAME,
  fcn: fcn,
  args: args,
};

var { proposal, tx_id } = channel.generateUnsignedProposal(transaction_proposal, 'org1', cert);

// 2. Hash the transaction proposal
var proposalBytes = proposal.toBuffer();
var digest = client.getCryptoSuite().hash(proposalBytes);
//const hash = crypto.createHash('sha256');
//hash.update(proposalBytes);
//var digest = hash.digest('hex');

// 3. Calculate the signature for this transacton proposal
console.log("digest: "+digest);   
console.log("signKey: ");
console.log(util.inspect(signKey));
var sig = ecdsa.sign(Buffer.from(digest, 'hex'), signKey);
var signature = Buffer.from(sig.toDER());
var signedProposal = {
  signature,
  proposal_bytes: proposalBytes,
};

// 4. Send the signed transaction proposal
var proposal_request = {
  signedProposal,
  targets
}
channel.sendSignedProposal(proposal_request)
.then((proposalResponses) => {
    console.log('Proposal responses:');
    console.log(util.inspect(proposalResponses));

    // TODO: Understand why the proposal signature is rejected by the peers

    // 5. Generate unsigned transaction
    var transaction_request = {
      proposalResponses,
      proposal,
    };
    return channel.generateUnsignedTransaction(transaction_request);
})  
.then((commitProposal) => {

    // 6. Sign the unsigned transaction
    var transactionBytes = commitProposal.toBuffer();
    var transaction_digest = client.getCryptoSuite().hash(transactionBytes);
    var transaction_sig = ecdsa.sign(Buffer.from(transaction_digest, 'hex'), signKey);        
    var transaction_signature = Buffer.from(transaction_sig.toDER());

    var signedTransaction = {
      signedProposal: transaction_signature,
      request: transaction_request
    }

    // 7. Commit the signed transaction
    return channel.sendSignedTransaction(signedTransaction);
})
.then((response) => {
    console.log('Successfully sent transaction');
    console.log('Return code: '+response.status);
});

});

Любая помощь от любого, кто мог бы успешно подписать транзакции в автономном режиме, была бы fantasti c.

1 Ответ

0 голосов
/ 29 февраля 2020

Отвечая на мой собственный вопрос. В моем коде было 2 проблемы.

1-й был связан с фактической подписью, которую нужно сделать очень специфичным c способом в Fabri c. Мне пришлось создать эту функцию и применить ее к подписи, чтобы избежать проблемы:

function _preventMalleability(sig) {
const halfOrder = elliptic.curves.p256.n.shrn(1);
if (sig.s.cmp(halfOrder) === 1) {
    const bigNum = elliptic.curves.p256.n;
    sig.s = bigNum.sub(sig.s);
}
return sig;

2d. Одна была связана с форматированием различных структур предложений / запросов / транзакций:

transaction_request = {
  proposalResponses: proposalResponses,
  proposal: proposal,
}

signedTransactionProposal = {
    signature: transaction_signature,
    proposal_bytes: transactionBytes,
}

signedTransaction = {
  signedProposal: signedTransactionProposal,
  request: transaction_request,
}

Я создал полный (рабочий) учебник с подробными инструкциями здесь: https://gitlab.com/guillaume.goutaudier/wisekeydemo

...