hyperledger-sawtooth - 无法将 intkey Tp 连接到锯齿测试网络
问题描述
我正在尝试使用锯齿 1.2 设置多节点锯齿网络。我用默认的 intkey 容器测试了 docker compose 文件,它工作正常。
但是当我尝试使用 NodeJs SDK 设置 intkey 并尝试连接到验证器时,连接没有响应。此外,当我尝试浏览http://localhost:8008/batches时,网址无法访问。
码头工人撰写文件
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 specification
const MIN_VALUE = 0
const MAX_VALUE = 4294967295
const MAX_NAME_LENGTH = 20
const _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
键索引
/**
* 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 和验证器容器中转发端口解决了这个问题:
但我仍然无法成功提交交易。交易仍待处理。
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 Signer
const 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 Payload
const 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 Header
const 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 Transaction
const signature = signer.sign(transactionHeaderBytes)
const transaction = protobuf.Transaction.create({
header: transactionHeaderBytes,
headerSignature: signature,
payload: payloadBytes
})
// Create the BatchHeader
const transactions = [transaction]
const batchHeaderBytes = protobuf.BatchHeader.encode({
signerPublicKey: signer.getPublicKey().asHex(),
transactionIds: transactions.map((txn) => txn.headerSignature),
}).finish()
// Create the Batch
const headerSignature = signer.sign(batchHeaderBytes)
const batch = protobuf.Batch.create({
header: batchHeaderBytes,
headerSignature: headerSignature,
transactions: transactions
})
// Encode the Batch(es) in a BatchList
const batchListBytes = protobuf.BatchList.encode({
batches: [batch]
}).finish()
// Submitting Batches to the Validator
const 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)
})
推荐阅读
- arrays - 尝试保留此原始数组在此处失败
- kotlin - kotlin中接口引用如何访问类方法和变量
- java - 如何打开现有的 android 应用程序并使用颤振向其发送数据
- postgresql - Postgres 在 Schema 中使用 Hstore 给出运算符不存在的错误
- maven - 在“更新 Maven 项目”期间发生内部错误。java.lang.ExceptionInInitializerError
- sql-server - Oracle 和 SQL Server `CEIL/CEILING` 函数返回不同的结果
- python - Matplotlib 返回:AttributeError:'property' 对象没有属性'__name__'
- html - 如何设置比下拉宽度长的下拉项的宽度
- shiny - 有没有办法在闪亮的仪表板上制作布告栏?
- daxstudio - 如何在 Daxstudio 中更改数据库