docker-compose文件version: "2.1"volumes: poet-shared:services: shell: image: hyperledger/sawtooth-shell:chime container_name: sawtooth-shell-default entrypoint: "bash -c \"\ sawtooth keygen && \ tail -f /dev/null \ \"" validator-0: image: hyperledger/sawtooth-validator:chime container_name: sawtooth-validator-default-0 expose: - 4004 - 5050 - 8800 volumes: - poet-shared:/poet-shared command: "bash -c \"\ sawadm keygen --force && \ mkdir -p /poet-shared/validator-0 || true && \ cp -a /etc/sawtooth/keys /poet-shared/validator-0/ && \ while [ ! -f /poet-shared/poet-enclave-measurement ]; do sleep 1; done && \ while [ ! -f /poet-shared/poet-enclave-basename ]; do sleep 1; done && \ while [ ! -f /poet-shared/poet.batch ]; do sleep 1; done && \ cp /poet-shared/poet.batch / && \ sawset genesis \ -k /etc/sawtooth/keys/validator.priv \ -o config-genesis.batch && \ sawset proposal create \ -k /etc/sawtooth/keys/validator.priv \ sawtooth.consensus.algorithm.name=PoET \ sawtooth.consensus.algorithm.version=0.1 \ sawtooth.poet.report_public_key_pem=\ \\\"$$(cat /poet-shared/simulator_rk_pub.pem)\\\" \ sawtooth.poet.valid_enclave_measurements=$$(cat /poet-shared/poet-enclave-measurement) \ sawtooth.poet.valid_enclave_basenames=$$(cat /poet-shared/poet-enclave-basename) \ -o config.batch && \ sawset proposal create \ -k /etc/sawtooth/keys/validator.priv \ sawtooth.poet.target_wait_time=5 \ sawtooth.poet.initial_wait_time=25 \ sawtooth.publisher.max_batches_per_block=100 \ -o poet-settings.batch && \ sawadm genesis \ config-genesis.batch config.batch poet.batch poet-settings.batch && \ sawtooth-validator -v \ --bind network:tcp://eth0:8800 \ --bind component:tcp://eth0:4004 \ --bind consensus:tcp://eth0:5050 \ --peering static \ --endpoint tcp://validator-0:8800 \ --scheduler parallel \ --network-auth trust \"" environment: PYTHONPATH: "/project/sawtooth-core/consensus/poet/common:\ /project/sawtooth-core/consensus/poet/simulator:\ /project/sawtooth-core/consensus/poet/core" stop_signal: SIGKILL validator-1: image: hyperledger/sawtooth-validator:chime container_name: sawtooth-validator-default-1 expose: - 4004 - 5050 - 8800 volumes: - poet-shared:/poet-shared command: | bash -c " sawadm keygen --force && \ mkdir -p /poet-shared/validator-1 || true && \ cp -a /etc/sawtooth/keys /poet-shared/validator-1/ && \ sawtooth-validator -v \ --bind network:tcp://eth0:8800 \ --bind component:tcp://eth0:4004 \ --bind consensus:tcp://eth0:5050 \ --peering static \ --endpoint tcp://validator-1:8800 \ --peers tcp://validator-0:8800 \ --scheduler parallel \ --network-auth trust " environment: PYTHONPATH: "/project/sawtooth-core/consensus/poet/common:\ /project/sawtooth-core/consensus/poet/simulator:\ /project/sawtooth-core/consensus/poet/core" stop_signal: SIGKILL rest-api-0: image: hyperledger/sawtooth-rest-api:chime container_name: sawtooth-rest-api-default-0 expose: - 8008 command: | bash -c " sawtooth-rest-api \ --connect tcp://validator-0:4004 \ --bind rest-api-0:8008 " stop_signal: SIGKILL rest-api-1: image: hyperledger/sawtooth-rest-api:chime container_name: sawtooth-rest-api-default-1 expose: - 9008 command: | bash -c " sawtooth-rest-api \ --connect tcp://validator-1:4004 \ --bind rest-api-1:9008 " stop_signal: SIGKILL settings-tp-0: image: hyperledger/sawtooth-settings-tp:chime container_name: sawtooth-settings-tp-default-0 expose: - 4004 command: settings-tp -v -C tcp://validator-0:4004 stop_signal: SIGKILL settings-tp-1: image: hyperledger/sawtooth-settings-tp:chime container_name: sawtooth-settings-tp-default-1 expose: - 4004 command: settings-tp -v -C tcp://validator-1:4004 stop_signal: SIGKILL poet-engine-0: image: hyperledger/sawtooth-poet-engine:chime container_name: sawtooth-poet-engine-0 volumes: - poet-shared:/poet-shared command: "bash -c \"\ if [ ! -f /poet-shared/poet-enclave-measurement ]; then \ poet enclave measurement >> /poet-shared/poet-enclave-measurement; \ fi && \ if [ ! -f /poet-shared/poet-enclave-basename ]; then \ poet enclave basename >> /poet-shared/poet-enclave-basename; \ fi && \ if [ ! -f /poet-shared/simulator_rk_pub.pem ]; then \ cp /etc/sawtooth/simulator_rk_pub.pem /poet-shared; \ fi && \ while [ ! -f /poet-shared/validator-0/keys/validator.priv ]; do sleep 1; done && \ cp -a /poet-shared/validator-0/keys /etc/sawtooth && \ poet registration create -k /etc/sawtooth/keys/validator.priv -o /poet-shared/poet.batch && \ poet-engine -C tcp://validator-0:5050 --component tcp://validator-0:4004 \ \"" poet-engine-1: image: hyperledger/sawtooth-poet-engine:chime container_name: sawtooth-poet-engine-1 volumes: - poet-shared:/poet-shared command: "bash -c \"\ while [ ! -f /poet-shared/validator-1/keys/validator.priv ]; do sleep 1; done && \ cp -a /poet-shared/validator-1/keys /etc/sawtooth && \ poet-engine -C tcp://validator-1:5050 --component tcp://validator-1:4004 \ \"" poet-validator-registry-tp-0: image: hyperledger/sawtooth-poet-validator-registry-tp:chime container_name: sawtooth-poet-validator-registry-tp-0 expose: - 4004 command: poet-validator-registry-tp -C tcp://validator-0:4004 environment: PYTHONPATH: /project/sawtooth-core/consensus/poet/common stop_signal: SIGKILL poet-validator-registry-tp-1: image: hyperledger/sawtooth-poet-validator-registry-tp:chime container_name: sawtooth-poet-validator-registry-tp-1 expose: - 4004 command: poet-validator-registry-tp -C tcp://validator-1:4004 environment: PYTHONPATH: /project/sawtooth-core/consensus/poet/common stop_signal: SIGKILL intkey处理程序/** * Copyright 2016 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ------------------------------------------------------------------------------ */'use strict'const { TransactionHandler } = require('sawtooth-sdk/processor/handler')const { InvalidTransaction, InternalError} = require('sawtooth-sdk/processor/exceptions')const crypto = require('crypto')const cbor = require('cbor')// Constants defined in intkey specificationconst MIN_VALUE = 0const MAX_VALUE = 4294967295const MAX_NAME_LENGTH = 20const _hash = (x) => crypto.createHash('sha512').update(x).digest('hex').toLowerCase()const INT_KEY_FAMILY = 'intkey'const INT_KEY_NAMESPACE = _hash(INT_KEY_FAMILY).substring(0, 6)const _decodeCbor = (buffer) => new Promise((resolve, reject) => cbor.decodeFirst(buffer, (err, obj) => (err ? reject(err) : resolve(obj))) )const _toInternalError = (err) => { let message = (err.message) ? err.message : err throw new InternalError(message)}const _setEntry = (context, address, stateValue) => { let entries = { [address]: cbor.encode(stateValue) } return context.setState(entries)}const _applySet = (context, address, name, value) => (possibleAddressValues) => { let stateValueRep = possibleAddressValues[address] let stateValue if (stateValueRep && stateValueRep.length > 0) { stateValue = cbor.decodeFirstSync(stateValueRep) let stateName = stateValue[name] if (stateName) { throw new InvalidTransaction( `Verb is "set" but Name already in state, Name: ${name} Value: ${stateName}` ) } } // 'set' passes checks so store it in the state if (!stateValue) { stateValue = {} } stateValue[name] = value return _setEntry(context, address, stateValue)}const _applyOperator = (verb, op) => (context, address, name, value) => (possibleAddressValues) => { let stateValueRep = possibleAddressValues[address] if (!stateValueRep || stateValueRep.length === 0) { throw new InvalidTransaction(`Verb is ${verb} but Name is not in state`) } let stateValue = cbor.decodeFirstSync(stateValueRep) if (stateValue[name] === null || stateValue[name] === undefined) { throw new InvalidTransaction(`Verb is ${verb} but Name is not in state`) } const result = op(stateValue[name], value) if (result < MIN_VALUE) { throw new InvalidTransaction( `Verb is ${verb}, but result would be less than ${MIN_VALUE}` ) } if (result > MAX_VALUE) { throw new InvalidTransaction( `Verb is ${verb}, but result would be greater than ${MAX_VALUE}` ) } // Increment the value in state by value // stateValue[name] = op(stateValue[name], value) stateValue[name] = result return _setEntry(context, address, stateValue)}const _applyInc = _applyOperator('inc', (x, y) => x + y)const _applyDec = _applyOperator('dec', (x, y) => x - y)class IntegerKeyHandler extends TransactionHandler { constructor () { super(INT_KEY_FAMILY, ['1.0'], [INT_KEY_NAMESPACE]) } apply (transactionProcessRequest, context) { return _decodeCbor(transactionProcessRequest.payload) .catch(_toInternalError) .then((update) => { // // Validate the update let name = update.Name if (!name) { throw new InvalidTransaction('Name is required') } if (name.length > MAX_NAME_LENGTH) { throw new InvalidTransaction( `Name must be a string of no more than ${MAX_NAME_LENGTH} characters` ) } let verb = update.Verb if (!verb) { throw new InvalidTransaction('Verb is required') } let value = update.Value if (value === null || value === undefined) { throw new InvalidTransaction('Value is required') } let parsed = parseInt(value) if (parsed !== value || parsed < MIN_VALUE || parsed > MAX_VALUE) { throw new InvalidTransaction( `Value must be an integer ` + `no less than ${MIN_VALUE} and ` + `no greater than ${MAX_VALUE}`) } value = parsed // Determine the action to apply based on the verb let actionFn if (verb === 'set') { actionFn = _applySet } else if (verb === 'dec') { actionFn = _applyDec } else if (verb === 'inc') { actionFn = _applyInc } else { throw new InvalidTransaction(`Verb must be set, inc, dec not ${verb}`) } let address = INT_KEY_NAMESPACE + _hash(name).slice(-64) // Get the current state, for the key's address: let getPromise = context.getState([address]) // Apply the action to the promise's result: let actionPromise = getPromise.then( actionFn(context, address, name, value) ) // Validate that the action promise results in the correctly set address: return actionPromise.then(addresses => { if (addresses.length === 0) { throw new InternalError('State Error!') } console.log(`Verb: ${verb} Name: ${name} Value: ${value}`) }) }) }}module.exports = IntegerKeyHandler intkey索引/** * Copyright 2016 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ------------------------------------------------------------------------------ */'use strict'const { TransactionProcessor } = require('sawtooth-sdk/processor')const IntegerKeyHandler = require('./handler')const address = "tcp://localhost:4004";const transactionProcessor = new TransactionProcessor(address)transactionProcessor.addHandler(new IntegerKeyHandler())transactionProcessor.start() 解决方案此问题通过转发rest-api和Validator容器中的端口来解决:但是我仍然无法成功提交交易.交易仍待处理.const {createContext, CryptoFactory} = require('sawtooth-sdk/signing')const cbor = require('cbor')const {createHash} = require('crypto')const {protobuf} = require('sawtooth-sdk')const crypto = require('crypto')// Creating a Private Key and Signerconst context = createContext('secp256k1')const privateKey = context.newRandomPrivateKey()const signer = new CryptoFactory(context).newSigner(privateKey)const _hash = (x) => crypto.createHash('sha512').update(x).digest('hex').toLowerCase()// Encoding Your Payloadconst payload = { Verb: 'set', Name: 'foo', Value: 25}const payloadBytes = cbor.encode(payload)let familyAddr = _hash('intkey').substring(0, 6);let nameAddr = _hash(payload.Name).slice(-64);let addr = familyAddr + nameAddr;console.log(addr);// Create the Transaction Headerconst transactionHeaderBytes = protobuf.TransactionHeader.encode({ familyName: 'intkey', familyVersion: '1.0', inputs: [addr], outputs: [addr], signerPublicKey: signer.getPublicKey().asHex(), batcherPublicKey: signer.getPublicKey().asHex(), dependencies: [], payloadSha512: createHash('sha512').update(payloadBytes).digest('hex')}).finish()// Create the Transactionconst signature = signer.sign(transactionHeaderBytes)const transaction = protobuf.Transaction.create({ header: transactionHeaderBytes, headerSignature: signature, payload: payloadBytes})// Create the BatchHeaderconst transactions = [transaction]const batchHeaderBytes = protobuf.BatchHeader.encode({ signerPublicKey: signer.getPublicKey().asHex(), transactionIds: transactions.map((txn) => txn.headerSignature),}).finish()// Create the Batchconst headerSignature = signer.sign(batchHeaderBytes)const batch = protobuf.Batch.create({ header: batchHeaderBytes, headerSignature: headerSignature, transactions: transactions})// Encode the Batch(es) in a BatchListconst batchListBytes = protobuf.BatchList.encode({ batches: [batch]}).finish()// Submitting Batches to the Validatorconst request = require('request')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)})I am trying to set up a multi node sawtooth netwrok using sawtooth 1.2. I tested the docker compose file with the default intkey containers and it worked.But when I tried to set up intkey using the NodeJs SDK and tried to connect to the validator, the connection is not responded. Also when I try to browse the http://localhost:8008/batches, the url is unreachable.docker-compose fileversion: "2.1"volumes: poet-shared:services: shell: image: hyperledger/sawtooth-shell:chime container_name: sawtooth-shell-default entrypoint: "bash -c \"\ sawtooth keygen && \ tail -f /dev/null \ \"" validator-0: image: hyperledger/sawtooth-validator:chime container_name: sawtooth-validator-default-0 expose: - 4004 - 5050 - 8800 volumes: - poet-shared:/poet-shared command: "bash -c \"\ sawadm keygen --force && \ mkdir -p /poet-shared/validator-0 || true && \ cp -a /etc/sawtooth/keys /poet-shared/validator-0/ && \ while [ ! -f /poet-shared/poet-enclave-measurement ]; do sleep 1; done && \ while [ ! -f /poet-shared/poet-enclave-basename ]; do sleep 1; done && \ while [ ! -f /poet-shared/poet.batch ]; do sleep 1; done && \ cp /poet-shared/poet.batch / && \ sawset genesis \ -k /etc/sawtooth/keys/validator.priv \ -o config-genesis.batch && \ sawset proposal create \ -k /etc/sawtooth/keys/validator.priv \ sawtooth.consensus.algorithm.name=PoET \ sawtooth.consensus.algorithm.version=0.1 \ sawtooth.poet.report_public_key_pem=\ \\\"$$(cat /poet-shared/simulator_rk_pub.pem)\\\" \ sawtooth.poet.valid_enclave_measurements=$$(cat /poet-shared/poet-enclave-measurement) \ sawtooth.poet.valid_enclave_basenames=$$(cat /poet-shared/poet-enclave-basename) \ -o config.batch && \ sawset proposal create \ -k /etc/sawtooth/keys/validator.priv \ sawtooth.poet.target_wait_time=5 \ sawtooth.poet.initial_wait_time=25 \ sawtooth.publisher.max_batches_per_block=100 \ -o poet-settings.batch && \ sawadm genesis \ config-genesis.batch config.batch poet.batch poet-settings.batch && \ sawtooth-validator -v \ --bind network:tcp://eth0:8800 \ --bind component:tcp://eth0:4004 \ --bind consensus:tcp://eth0:5050 \ --peering static \ --endpoint tcp://validator-0:8800 \ --scheduler parallel \ --network-auth trust \"" environment: PYTHONPATH: "/project/sawtooth-core/consensus/poet/common:\ /project/sawtooth-core/consensus/poet/simulator:\ /project/sawtooth-core/consensus/poet/core" stop_signal: SIGKILL validator-1: image: hyperledger/sawtooth-validator:chime container_name: sawtooth-validator-default-1 expose: - 4004 - 5050 - 8800 volumes: - poet-shared:/poet-shared command: | bash -c " sawadm keygen --force && \ mkdir -p /poet-shared/validator-1 || true && \ cp -a /etc/sawtooth/keys /poet-shared/validator-1/ && \ sawtooth-validator -v \ --bind network:tcp://eth0:8800 \ --bind component:tcp://eth0:4004 \ --bind consensus:tcp://eth0:5050 \ --peering static \ --endpoint tcp://validator-1:8800 \ --peers tcp://validator-0:8800 \ --scheduler parallel \ --network-auth trust " environment: PYTHONPATH: "/project/sawtooth-core/consensus/poet/common:\ /project/sawtooth-core/consensus/poet/simulator:\ /project/sawtooth-core/consensus/poet/core" stop_signal: SIGKILL rest-api-0: image: hyperledger/sawtooth-rest-api:chime container_name: sawtooth-rest-api-default-0 expose: - 8008 command: | bash -c " sawtooth-rest-api \ --connect tcp://validator-0:4004 \ --bind rest-api-0:8008 " stop_signal: SIGKILL rest-api-1: image: hyperledger/sawtooth-rest-api:chime container_name: sawtooth-rest-api-default-1 expose: - 9008 command: | bash -c " sawtooth-rest-api \ --connect tcp://validator-1:4004 \ --bind rest-api-1:9008 " stop_signal: SIGKILL settings-tp-0: image: hyperledger/sawtooth-settings-tp:chime container_name: sawtooth-settings-tp-default-0 expose: - 4004 command: settings-tp -v -C tcp://validator-0:4004 stop_signal: SIGKILL settings-tp-1: image: hyperledger/sawtooth-settings-tp:chime container_name: sawtooth-settings-tp-default-1 expose: - 4004 command: settings-tp -v -C tcp://validator-1:4004 stop_signal: SIGKILL poet-engine-0: image: hyperledger/sawtooth-poet-engine:chime container_name: sawtooth-poet-engine-0 volumes: - poet-shared:/poet-shared command: "bash -c \"\ if [ ! -f /poet-shared/poet-enclave-measurement ]; then \ poet enclave measurement >> /poet-shared/poet-enclave-measurement; \ fi && \ if [ ! -f /poet-shared/poet-enclave-basename ]; then \ poet enclave basename >> /poet-shared/poet-enclave-basename; \ fi && \ if [ ! -f /poet-shared/simulator_rk_pub.pem ]; then \ cp /etc/sawtooth/simulator_rk_pub.pem /poet-shared; \ fi && \ while [ ! -f /poet-shared/validator-0/keys/validator.priv ]; do sleep 1; done && \ cp -a /poet-shared/validator-0/keys /etc/sawtooth && \ poet registration create -k /etc/sawtooth/keys/validator.priv -o /poet-shared/poet.batch && \ poet-engine -C tcp://validator-0:5050 --component tcp://validator-0:4004 \ \"" poet-engine-1: image: hyperledger/sawtooth-poet-engine:chime container_name: sawtooth-poet-engine-1 volumes: - poet-shared:/poet-shared command: "bash -c \"\ while [ ! -f /poet-shared/validator-1/keys/validator.priv ]; do sleep 1; done && \ cp -a /poet-shared/validator-1/keys /etc/sawtooth && \ poet-engine -C tcp://validator-1:5050 --component tcp://validator-1:4004 \ \"" poet-validator-registry-tp-0: image: hyperledger/sawtooth-poet-validator-registry-tp:chime container_name: sawtooth-poet-validator-registry-tp-0 expose: - 4004 command: poet-validator-registry-tp -C tcp://validator-0:4004 environment: PYTHONPATH: /project/sawtooth-core/consensus/poet/common stop_signal: SIGKILL poet-validator-registry-tp-1: image: hyperledger/sawtooth-poet-validator-registry-tp:chime container_name: sawtooth-poet-validator-registry-tp-1 expose: - 4004 command: poet-validator-registry-tp -C tcp://validator-1:4004 environment: PYTHONPATH: /project/sawtooth-core/consensus/poet/common stop_signal: SIGKILLintkey handler/** * Copyright 2016 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ------------------------------------------------------------------------------ */'use strict'const { TransactionHandler } = require('sawtooth-sdk/processor/handler')const { InvalidTransaction, InternalError} = require('sawtooth-sdk/processor/exceptions')const crypto = require('crypto')const cbor = require('cbor')// Constants defined in intkey specificationconst MIN_VALUE = 0const MAX_VALUE = 4294967295const MAX_NAME_LENGTH = 20const _hash = (x) => crypto.createHash('sha512').update(x).digest('hex').toLowerCase()const INT_KEY_FAMILY = 'intkey'const INT_KEY_NAMESPACE = _hash(INT_KEY_FAMILY).substring(0, 6)const _decodeCbor = (buffer) => new Promise((resolve, reject) => cbor.decodeFirst(buffer, (err, obj) => (err ? reject(err) : resolve(obj))) )const _toInternalError = (err) => { let message = (err.message) ? err.message : err throw new InternalError(message)}const _setEntry = (context, address, stateValue) => { let entries = { [address]: cbor.encode(stateValue) } return context.setState(entries)}const _applySet = (context, address, name, value) => (possibleAddressValues) => { let stateValueRep = possibleAddressValues[address] let stateValue if (stateValueRep && stateValueRep.length > 0) { stateValue = cbor.decodeFirstSync(stateValueRep) let stateName = stateValue[name] if (stateName) { throw new InvalidTransaction( `Verb is "set" but Name already in state, Name: ${name} Value: ${stateName}` ) } } // 'set' passes checks so store it in the state if (!stateValue) { stateValue = {} } stateValue[name] = value return _setEntry(context, address, stateValue)}const _applyOperator = (verb, op) => (context, address, name, value) => (possibleAddressValues) => { let stateValueRep = possibleAddressValues[address] if (!stateValueRep || stateValueRep.length === 0) { throw new InvalidTransaction(`Verb is ${verb} but Name is not in state`) } let stateValue = cbor.decodeFirstSync(stateValueRep) if (stateValue[name] === null || stateValue[name] === undefined) { throw new InvalidTransaction(`Verb is ${verb} but Name is not in state`) } const result = op(stateValue[name], value) if (result < MIN_VALUE) { throw new InvalidTransaction( `Verb is ${verb}, but result would be less than ${MIN_VALUE}` ) } if (result > MAX_VALUE) { throw new InvalidTransaction( `Verb is ${verb}, but result would be greater than ${MAX_VALUE}` ) } // Increment the value in state by value // stateValue[name] = op(stateValue[name], value) stateValue[name] = result return _setEntry(context, address, stateValue)}const _applyInc = _applyOperator('inc', (x, y) => x + y)const _applyDec = _applyOperator('dec', (x, y) => x - y)class IntegerKeyHandler extends TransactionHandler { constructor () { super(INT_KEY_FAMILY, ['1.0'], [INT_KEY_NAMESPACE]) } apply (transactionProcessRequest, context) { return _decodeCbor(transactionProcessRequest.payload) .catch(_toInternalError) .then((update) => { // // Validate the update let name = update.Name if (!name) { throw new InvalidTransaction('Name is required') } if (name.length > MAX_NAME_LENGTH) { throw new InvalidTransaction( `Name must be a string of no more than ${MAX_NAME_LENGTH} characters` ) } let verb = update.Verb if (!verb) { throw new InvalidTransaction('Verb is required') } let value = update.Value if (value === null || value === undefined) { throw new InvalidTransaction('Value is required') } let parsed = parseInt(value) if (parsed !== value || parsed < MIN_VALUE || parsed > MAX_VALUE) { throw new InvalidTransaction( `Value must be an integer ` + `no less than ${MIN_VALUE} and ` + `no greater than ${MAX_VALUE}`) } value = parsed // Determine the action to apply based on the verb let actionFn if (verb === 'set') { actionFn = _applySet } else if (verb === 'dec') { actionFn = _applyDec } else if (verb === 'inc') { actionFn = _applyInc } else { throw new InvalidTransaction(`Verb must be set, inc, dec not ${verb}`) } let address = INT_KEY_NAMESPACE + _hash(name).slice(-64) // Get the current state, for the key's address: let getPromise = context.getState([address]) // Apply the action to the promise's result: let actionPromise = getPromise.then( actionFn(context, address, name, value) ) // Validate that the action promise results in the correctly set address: return actionPromise.then(addresses => { if (addresses.length === 0) { throw new InternalError('State Error!') } console.log(`Verb: ${verb} Name: ${name} Value: ${value}`) }) }) }}module.exports = IntegerKeyHandlerintkey index/** * Copyright 2016 Intel Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ------------------------------------------------------------------------------ */'use strict'const { TransactionProcessor } = require('sawtooth-sdk/processor')const IntegerKeyHandler = require('./handler')const address = "tcp://localhost:4004";const transactionProcessor = new TransactionProcessor(address)transactionProcessor.addHandler(new IntegerKeyHandler())transactionProcessor.start() 解决方案 This problem was solved by forwarding the ports in rest-api and validator containers:But I am still unable to successfully submit transactions. the transactions remains pending.const {createContext, CryptoFactory} = require('sawtooth-sdk/signing')const cbor = require('cbor')const {createHash} = require('crypto')const {protobuf} = require('sawtooth-sdk')const crypto = require('crypto')// Creating a Private Key and Signerconst context = createContext('secp256k1')const privateKey = context.newRandomPrivateKey()const signer = new CryptoFactory(context).newSigner(privateKey)const _hash = (x) => crypto.createHash('sha512').update(x).digest('hex').toLowerCase()// Encoding Your Payloadconst payload = { Verb: 'set', Name: 'foo', Value: 25}const payloadBytes = cbor.encode(payload)let familyAddr = _hash('intkey').substring(0, 6);let nameAddr = _hash(payload.Name).slice(-64);let addr = familyAddr + nameAddr;console.log(addr);// Create the Transaction Headerconst transactionHeaderBytes = protobuf.TransactionHeader.encode({ familyName: 'intkey', familyVersion: '1.0', inputs: [addr], outputs: [addr], signerPublicKey: signer.getPublicKey().asHex(), batcherPublicKey: signer.getPublicKey().asHex(), dependencies: [], payloadSha512: createHash('sha512').update(payloadBytes).digest('hex')}).finish()// Create the Transactionconst signature = signer.sign(transactionHeaderBytes)const transaction = protobuf.Transaction.create({ header: transactionHeaderBytes, headerSignature: signature, payload: payloadBytes})// Create the BatchHeaderconst transactions = [transaction]const batchHeaderBytes = protobuf.BatchHeader.encode({ signerPublicKey: signer.getPublicKey().asHex(), transactionIds: transactions.map((txn) => txn.headerSignature),}).finish()// Create the Batchconst headerSignature = signer.sign(batchHeaderBytes)const batch = protobuf.Batch.create({ header: batchHeaderBytes, headerSignature: headerSignature, transactions: transactions})// Encode the Batch(es) in a BatchListconst batchListBytes = protobuf.BatchList.encode({ batches: [batch]}).finish()// Submitting Batches to the Validatorconst request = require('request')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)}) 这篇关于无法将Intkey Tp连接到锯齿测试网络的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 10-11 08:38