Um, use nodejs para escrever contratos inteligentes
Etapa 1: Crie uma nova pasta fishcc no diretório chaincode e inicie o nome você mesmo;
Etapa 2: Entre na pasta fishcc e execute o npm init
comando;
Etapa 3: Instale o fabric-shim;
npm install --save fabric-shim
Etapa 4: Crie um novo arquivo app.js e especifique você mesmo o nome do arquivo.
Etapa 5: redija o contrato de acordo com o modelo a seguir.
const shim = require('fabric-shim');
const util = require('util');
let Chaincode = class {
async Init(stub) {
console.info('execute Init method...');
return shim.success('');
}
async Invoke(stub) {
let ret = stub.getFunctionAndParameters();
let method = this[ret.fcn];
if (!method) {
let errMsg = ret.fcn + ' method does not exist';
throw new Error(errMsg);
}
try {
let payload = await method(stub, ret.params);
return shim.success(payload);
} catch (err) {
console.log(err);
return shim.error(err);
}
}
async xxx(stub, args) {
console.info('调用智能合约方法,xxx方法名根据实际自己指定');
}
}
shim.start(new Chaincode());
O código completo do contrato é o seguinte:
const shim = require('fabric-shim');
const util = require('util');
let Chaincode = class {
async Init(stub) {
return shim.success('');
}
async Invoke(stub) {
let ret = stub.getFunctionAndParameters();
let method = this[ret.fcn];
if (!method) {
throw new Error(ret.fcn + ' method does not exist.');
}
try {
let payload = await method(stub, ret.params);
return shim.success(payload);
} catch (err) {
console.log(err);
return shim.error(err);
}
}
async initLedger(stub, args) {
let fishes = [];
fishes.push({
vessel: "Fish001",
location: "67.0006, -70.5476",
timestamp: "1504054225",
holder: "zhang"
});
fishes.push({
vessel: "Fish002",
location: "57.9006, -78.3478",
timestamp: "1504054666",
holder: "li"
});
fishes.push({
vessel: "Fish003",
location: "77.9034, -75.3455",
timestamp: "1504054888",
holder: "wang"
});
for (let i = 0; i < fishes.length; i++) {
await stub.putState('FISH' + i, Buffer.from(JSON.stringify(fishes[i])));
console.info('Added <--> ',fishes[i]);
}
}
async queryFish(stub, args) {
if (args.length != 1) {
throw new Error('args length is not equals 1.');
}
let fishNumber = args[0];
let fishAsBytes = await stub.getState(fishNumber);
if (!fishAsBytes || fishAsBytes.toString().length <= 0) {
throw new Error('no data found.');
}
console.log(fishAsBytes.toString());
return fishAsBytes;
}
async recordFish(stub, args) {
if (args.length != 5) {
throw new Error('Args length is not equals 5.');
}
var fish = {
vessel: args[1],
location: args[2],
timestamp: args[3],
holder: args[4]
};
await stub.putState(args[0], Buffer.from(JSON.stringify(fish)));
}
async queryAllFish(stub, args) {
let startKey = 'FISH0';
let endKey = 'FISH999';
let iterator = await stub.getStateByRange(startKey, endKey);
let allResults = [];
while (true) {
let res = await iterator.next();
if (res.value && res.value.value.toString()) {
let jsonRes = {
};
console.log(res.value.value.toString('utf8'));
jsonRes.Key = res.value.key;
try {
jsonRes.Record = JSON.parse(res.value.value.toString('utf8'));
} catch (err) {
console.log(err);
jsonRes.Record = res.value.value.toString('utf8');
}
allResults.push(jsonRes);
}
if (res.done) {
console.log('end of data');
await iterator.close();
console.info(allResults);
return Buffer.from(JSON.stringify(allResults));
}
}
}
async changeFishHolder(stub, args) {
if (args.length != 2) {
throw new Error('Args length is not equals 2.');
}
let fishAsBytes = await stub.getState(args[0]);
let fish = JSON.parse(fishAsBytes);
fish.holder = args[1];
await stub.putState(args[0], Buffer.from(JSON.stringify(fish)));
}
}
shim.start(new Chaincode());
Etapa 6: Modifique o arquivo package.json e adicione o comando start nos scripts;
"scripts": {
"start": "node app.js"
},
Até agora, o contrato inteligente está escrito.
2. Depurar contratos inteligentes no modo de desenvolvedor de desenvolvimento
Os contratos inteligentes do Hyperledge Fabric são iniciados e mantidos por cada nó. No entanto, após usar o modo de desenvolvedor, a compilação e a inicialização do contrato inteligente são deixadas para o usuário. Na fase de desenvolvimento de contratos inteligentes, é muito útil usar o modo de desenvolvedor para escrever, compilar e executar contratos inteligentes.
Iniciar o modo de desenvolvedor é muito simples, desligamos a função tls de todos os nós.
- CORE_PEER_TLS_ENABLED=false
Modifique o comando command do nó peer e inclua o parâmetro -peer-chaincodedev = true após o comando peer node start.
command: peer node start --peer-chaincodedev=true
Configure a porta 7052 para todos os nós de mesmo nível. Comunicação GRPC entre nós de usuário na porta 7052.
Por fim, seguimos as etapas abaixo para testar.
A primeira etapa: iniciar todos os nós;
docker-compose up -d
Etapa 2: Depois que a inicialização for concluída, vá para o diretório de scripts do contêiner de nó de mesmo nível e execute o script start.sh.
#!/bin/bash
rm -f ../channel-artifacts/mychannel.block
printf "start create channel...\n"
peer channel create -o orderer.example.com:7050 -c mychannel -f ../channel-artifacts/channel.tx
printf "end create channel...\n"
mv mychannel.block ../channel-artifacts
printf "peer0.org1.example.com start join channel...\n"
peer channel join -b ../channel-artifacts/mychannel.block
printf "peer0.org1.example.com end join channel...\n"
printf "peer0.org1.example.com start install chaincode...\n"
peer chaincode install -n fishcc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/fishcc
printf "peer0.org1.example.com end install chaincode...\n"
printf "start packaging chaincode...\n"
peer chaincode package -n fishcc -p /opt/gopath/src/github.com/chaincode/fishcc -v 1.0 fishcc.1.0.out -l node
printf "end packaging chaincode"
mv fishcc.1.0.out ../channel-artifacts
export CORE_PEER_ADDRESS=peer1.org1.example.com:7051
export CORE_PEER_LOCALMSPID=Org1MSP
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/server.key
printf "peer1.org1.example.com start join channel...\n"
peer channel join -b ../channel-artifacts/mychannel.block
printf "peer1.org1.example.com end join channel...\n"
printf "peer1.org1.example.com start install chaincode...\n"
peer chaincode install ../channel-artifacts/fishcc.1.0.out
printf "peer1.org1.example.com end install chaincode...\n"
export CORE_PEER_ADDRESS=peer0.org2.example.com:7051
export CORE_PEER_LOCALMSPID=Org2MSP
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.key
printf "peer0.org2.example.com start join channel...\n"
peer channel join -b ../channel-artifacts/mychannel.block
printf "peer0.org2.example.com end join channel...\n"
printf "peer0.org2.example.com start install chaincode...\n"
peer chaincode install ../channel-artifacts/fishcc.1.0.out
printf "peer0.org2.example.com end install chaincode...\n"
export CORE_PEER_ADDRESS=peer1.org2.example.com:7051
export CORE_PEER_LOCALMSPID=Org2MSP
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/server.key
printf "peer1.org2.example.com start join channel...\n"
peer channel join -b ../channel-artifacts/mychannel.block
printf "peer1.org2.example.com end join channel...\n"
printf "peer1.org2.example.com start install chaincode...\n"
peer chaincode install ../channel-artifacts/fishcc.1.0.out
printf "peer1.org2.example.com end install chaincode...\n"
O script de shell acima executa tarefas como criar canais, adicionar canais e criar códigos em cadeia.
Etapa 3: Abra outra janela de shell, entre no diretório chaincode / fishcc e execute a execução.A npm start --peer.address grpc://localhost:7052 --chaincode-id-name fishcc:1.0
interface após a execução bem-sucedida é a seguinte:
Etapa 4: Instancie o contrato.
peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n fishcc -l node -v 1.0 -c '{"Args":[""]}' -P "AND('Org1MSP.member')"
Depois de executar a instanciação, você pode ver a janela do contrato em execução da seguinte forma:
Podemos ver as informações do resultado do contrato instanciado na janela do contrato.
Etapa 5: teste.
# 初始化
peer chaincode invoke -C mychannel -n fishcc -c '{"Args":["initLedger"]}' -o orderer.example.com:7050
# 查询
peer chaincode invoke -C mychannel -n fishcc -c '{"Args":["queryFish","FISH0"]}'
Três, configure o couchDB
O Hyperledge Fabric oferece suporte a dois modos de banco de dados de estado:
- levelDB: armazenamento de arquivos, não é fácil de visualizar e gerenciar
- couchDB: banco de dados de contêiner independente, fornecendo funções de consulta ricas
3.1 Configurar o couchDB
A primeira etapa: baixar a imagem hyperledger / fabric-couchdb, a
segunda etapa: configurar o serviço couchDB no arquivo de configuração docker-compose;
couchdb:
container_name: couchdb
image: hyperledger/fabric-couchdb
environment:
- COUCHDB_USER=admin
- COUCHDB_PASSWORD=123456
ports:
- 5984:5984
networks:
- byfn
O COUCHDB_USER e COUCHDB_PASSWORD acima especificam respectivamente o nome de login e a senha de login da plataforma de gerenciamento do couchDB.
Etapa 3: Adicionar as informações de configuração do couchDB na configuração do ambiente do nó do par;
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=123456
Etapa 4: Especifique a sequência de inicialização dos nós de mesmo nível;
depends_on:
- orderer.example.com
- couchdb
3.2 Simples e prático de couchDB
A primeira etapa: iniciar o contêiner do docker; a
segunda etapa: http://localhost:5984/_utils
entrar no console no navegador ; a
terceira etapa: inserir o nome de usuário e a senha. Depois que o login for bem-sucedido, se o contrato inteligente tiver sido inicializado, você pode ver o contrato implementado no lado direito da coluna Bancos de dados.
O mychannel_fishcc acima é o contrato que implantamos. Depois de clicar em, você pode ver que existem três dados, a saber, FISH0, FISH1 e FISH2.