±à¼ÍƼö: |
±¾ÎÄÀ´×ÔÓÚIBM£¬±¾ÎÄÖ÷Òª½éÉÜÁËÈçºÎʹÓÃ
Tendermint ºÍ Lotionjs ÇáËɽ«¡°È¨ÒæÖ¤Ã÷¡±Çø¿éÁ´Ó¦ÓÃ×÷ΪÁ½¸öÑéÖ¤Õ߽ڵ㲿ÊðÖÁ
IBM ÈÝÆ÷¡£ |
|
ǰÌáÌõ¼þ
ÄúÐèÒª°²×°ÒÔÏÂÈí¼þ£º
IBM Cloud CLI£¬ÓÃÓÚ¹ÜÀí IBM Cloud ÖеÄÓ¦Óá¢ÈÝÆ÷¡¢»ù´¡¼Ü¹¹¡¢·þÎñºÍÆäËû×ÊÔ´µÄÃüÁîÐнçÃæ
Docker£¬Ê¹ÓÃÈÝÆ÷¿ª·¢¡¢²¿ÊðºÍÔËÐÐÓ¦ÓÃµÄÆ½Ì¨
Kubectl£¬ÓÃÓÚÔÚ Kubernetes Éϲ¿ÊðºÍ¹ÜÀíÓ¦ÓõÄÃüÁîÐй¤¾ß
±³¾°
Çø¿éÁ´¼¼ÊõÊÇ×Ô´ÓÒòÌØÍøµ®ÉúÒÔÀ´×îΰ´óµÄ¼¼Êõ´´ÐÂÖ®Ò»¡£ÒòÌØÍøÖ§³ÖÐÅÏ¢µÄ×ÔÓÉÁ÷¶¯£¬¶øÇø¿éÁ´ÔòÖ§³Ö¼ÛÖµµÄÎÞÕϰÁ÷¶¯¡£ÔÚÓ¦ÓÃÃÜÂëѧ·½Ã棬ǰËùδÓеĴóÁ¿Ñо¿ÕýÔÚÈç»ðÈçݱµØÕ¹¿ª¡£¸÷Ðи÷ÒµµÄÆóÒµ¶¼ÔÚ½«Çø¿éÁ´¼¼ÊõÓ¦ÓÃÓÚÕæÊµµÄÒµÎñÓÃÀý¡£
Çø¿éÁ´Ò²ÊÇÒ»Ïîոеļ¼Êõ¡£¿ìËÙ¿ª·¢Çø¿éÁ´Ó¦ÓÃÔÐͲ¢ÔÚÔÆ¶ËÔËÐÐÍùÍùÀ§ÄÑÖØÖØ¡£Tendermint ¿ÉÓÃÓÚ¿ìËÙ´´½¨Çø¿éÁ´Ó¦Óã¬ÒòΪËü¿É´¦ÀíλÓڵײãµÄÇø¿éÁ´²ã£¨ÀýÈç£¬ÍøÂçºÍ¹²Ê¶£©£¬Í¬Ê±»¹¿Éͨ¹ý
ABCI£¨Ó¦ÓÃÇø¿éÁ´½Ó¿Ú£©¾Û½¹Ó¦Óò㡣ÔÚ±¾½Ì³ÌÖУ¬ÎÒ½«ÏòÄúչʾÈçºÎʹÓà Tendermint ºÍ Lotionjs
ÇáËÉ´´½¨Çø¿éÁ´ÁÄÌìÓ¦Ó㬲¢½«Æä²¿ÊðÖÁ IBM Cloud¡£
ʲôÊÇ Tendermint£¿
¼ò¶øÑÔÖ®£¬Tendermint ÊÇ¿ÉÓÃÓÚÔÚÈκηֲ¼Ê½¼ÆËãÆ½Ì¨ÖÐʵÏÖ°ÝռͥÈÝ´í (BFT) µÄÈí¼þ¡£´Ó¹ÜÀí»ù´¡¼Ü¹¹µ½Éè¼Æ·Ö²¼Ê½Êý¾Ý¿â£¬¶¼¿ÉʹÓÃ
Tendermint¡£Tendermint »ùÓÚÁ½¸öÖØÒªµÄ¼¼Êõ×é¼þ¶ø¹¹½¨£º
¹²Ê¶ÒýÇæ£¨Ò²³ÆÎª Tendermint ºËÐÄ£©¿Éͨ¹ý¡°È¨ÒæÖ¤Ã÷¡±¹²Ê¶È·±£ÔÚÿ̨»úÆ÷Öа´Ïàͬ˳Ðò¼Ç¼ÿ¸öÊÂÎñ¡£
ABCI£¨Ó¦ÓÃÇø¿éÁ´½Ó¿Ú£©Ö§³ÖÒÔÈκαà³ÌÓïÑÔÀ´´¦ÀíÊÂÎñ¡£
Tendermint ¾ßÓÐÒÔÏÂÌØÐÔ£º
°ÝռͥÈÝ´í£ºTendermint ×î¸ß¿ÉÈÝÈÌÈý·ÖÖ®Ò»µÄ»úÆ÷³öÏÖÈÎÒâ¹ÊÕÏ¡£Õâ°üÀ¨Ã÷È·µÄ¶ñÒâÐÐΪ¡£
״̬»ú¸´ÖÆ£ºTendermint ¿É¸´ÖÆÒÔÈκαà³ÌÓïÑÔ±àдµÄÈ·¶¨ÐÔ״̬»ú¡£
°²È«µÄ P2P£ºÍ¨¹ý Tendermint Öо¹ýÈÏÖ¤µÄ¼ÓÃÜϵͳÀ´±£»¤ Gossip ÐÒéºÍ¶ÔµÈ½Úµã·¢ÏÖ¡£
ÉÁµç°ãµÄËÙ¶È£ºTendermint Ö§³ÖÿÃëÊýǧ¸öÊÂÎñ£¬1000 ºÁÃëÑÓ³Ù¡£
ʲôÊÇ Lotionjs£¿
Lotion ÊÇÔÚ JavaScript Öд´½¨Çø¿éÁ´Ó¦ÓõÄÒ»ÖÖ¿ìËÙ¶øÓÐȤµÄ·½·¨¡£ËüÊÇ»ùÓÚ Tendermint
ʹÓà ABCI ÐÒé¹¹½¨µÄ¡£
1ÉèÖÃÏîÄ¿
´´½¨ÐÂĿ¼²¢µ¼º½ÖÁ´ËĿ¼£º
$ mkdir blockchain
$ cd blockchain |
°²×°ËùÐèµÄ¿â£º
$ npm i lotion
--save
$ npm i dotenv --save |
2´´½¨ 2 ¸öÑéÖ¤Õß½ÚµãµÄ˽ÓÐÃÜÔ¿ºÍ´´Ê¼Îļþ
´´½¨´´Ê¼Îļþ£º
½«³õʼÄÚÈÝÌî³äµ½ genesis.json ÖУº
{ "genesis_time":
"0001-01-01T00:00:00Z", "chain_id":
"name", "validators":
[
], "app_hash": ""
} |
Éú³É 2 ¸öÑéÖ¤Õß½ÚµãµÄÃÜÔ¿£º
$ ./node_modules/lotion/bin/tendermint
gen_validator > privkey0.json
$ ./node_modules/lotion/bin/tendermint gen_validator
> privkey1.json |
˽ÓÐÃÜÔ¿ÀàËÆÈçÏ£¬¹«ÓÃÃÜÔ¿ºÍ˽ÓÐÃÜÔ¿ÊÇËæ»úÉú³ÉµÄ£º
{ "address":
"B809574EC51377DE48454094BF3302989CBB50A9",
"pub_key": { "type": "ed25519",
"data": "8A049817BA6D1B065C30D927A529AAFA7147BE0D147 E1CCD7A25FAADBE80C8D0"
}, "priv_key": { "type":
"ed25519", "data": "57BAFDD6136E1140FA9F906313BF2CFC75802F044704DD7AAF3 0BC1010E6519C8 A049817BA6D1B065C30D927A529AAFA7147BE0D147E1CCD7A25F AADBE80C8D0"
}
} |
½ö¸´Öƹ«ÓÃÃÜÔ¿ÐÅÏ¢£¬²¢½«ÆäÕ³Ìûµ½ genesis.json ÖС£Ìí¼ÓÁ½¸öÑéÖ¤Õߺ󣬽«ÀàËÆÈçÏ£º
{ "genesis_time":
"0001-01-01T00:00:00Z", "chain_id":
"name", "validators":
[
{ "pub_key": { "type":
"ed25519", "data": "8A049817BA6D1B065C30D927A529AAFA7147BE0D1 47E1CCD7A25FAADBE80C8D0"
}, "power": 10, "name":
"saif"
},
{ "pub_key": { "type":
"ed25519", "data": "5FD1FBF59759E50BD1C23911E832198AB78A4F7E6F 1F23A64AAFEC5992608CA8"
}, "power": 20, "name":
"prerna"
}
], "app_hash": ""
} |
3¹¹½¨ÑéÖ¤Õß 1
´´½¨ node1 Îļþ¼Ð£º
ä¯ÀÀÖÁ node1 Ŀ¼£º
°²×°ËùÐèµÄ¿â£º
$ npm i lotion
--save
$ npm i dotenv --save |
½«ÏÈǰÉú³ÉµÄ genesis.json ºÍ privkey0.json ¸´ÖƵ½ node1 Îļþ¼Ð¡£
´´½¨ node1 µÄ»·¾³Îļþ£º
¶Ô node1.js µÄÄÚÈݽøÐбàÂ룺
LOTION_HOME="./.lotion_node1" |
´´½¨ node1.js£º
¶Ô node1.js µÄÄÚÈݽøÐбàÂ룺
require('dotenv').config({path:
".env-node1"});
let lotion = require('lotion')
let app = lotion({
genesis: './genesis.json',
tendermintPort: 30090,
initialState: { messages: [] },
p2pPort: 30092,
logTendermint: true,
keys: 'privkey0.json',
peers: ['workernode2:30092']
})
app.use((state, tx,chainInfo) => {
if (typeof tx.sender === 'string' && typeof
tx.message === 'string') {
state.messages.push({ sender: tx.sender, message:
tx.message })
}
})
app.listen(3000).then(({ GCI }) => {
console.log(GCI)
}) |
´´½¨ Dockerfile£º
¶Ô Dockerfile µÄÄÚÈݽøÐбàÂ룺
FROM node:carbon
WORKDIR /usr/src/app
COPY package*.json ./
COPY privkey0.json ./
COPY .env-node1 ./
RUN npm install
COPY ..
EXPOSE 30090 30092
CMD [ "node", "node1.js" ] |
4¹¹½¨ÑéÖ¤Õß 2
´´½¨ node2 Îļþ¼Ð£º
ä¯ÀÀÖÁ node2 Ŀ¼£º
°²×°ËùÐèµÄ¿â£º
$ npm i lotion
--save
$ npm i dotenv --save |
½«ÏÈǰÉú³ÉµÄ genesis.json ºÍ privkey0.json ¸´ÖƵ½ node2 Îļþ¼Ð¡£
´´½¨ node2 µÄ»·¾³Îļþ£º
¶Ô node2.js µÄÄÚÈݽøÐбàÂ룺
LOTION_HOME="./.lotion_node2" |
´´½¨ node2.js£º
¶Ô node2.js µÄÄÚÈݽøÐбàÂ룺
require('dotenv').config({path:
".env-node2"});
let lotion = require('lotion')
let app = lotion({
genesis: './genesis.json',
tendermintPort: 30090,
initialState: { messages: [] },
p2pPort: 30092,
logTendermint: true,
keys: 'privkey1.json',
peers: ['workernode1:30092']
})
app.use((state, tx,chainInfo) => {
if (typeof tx.sender === 'string' && typeof
tx.message === 'string') {
state.messages.push({ sender: tx.sender, message:
tx.message })
}
})
app.listen(3000).then(({ GCI }) => {
console.log(GCI)
}) |
´´½¨ Dockerfile£º
¶Ô Dockerfile µÄÄÚÈݽøÐбàÂ룺
FROM node:carbon
WORKDIR /usr/src/app
COPY package*.json ./
COPY privkey0.json ./
COPY .env-node1 ./
RUN npm install
COPY ..
EXPOSE 30090 30092
CMD [ "node", "node2.js" ] |
5½«ÕâÁ½¸öÑéÖ¤Õ߽ڵ㲿Êðµ½ IBM Cloud ÉÏ
×¢²á IBM Cloud¡£
°²×° Cloud Foundry CLI¡£
°²×° IBM Cloud CLI¡£
°²×° Kubernetes CLI¡£
ä¯ÀÀÖÁ node1 Ŀ¼£º
¹¹½¨ Docker ¾µÏñ£º
$ docker build
-t node1 . |
תÖÁ IBM Cloud ¿ØÖÆÌ¨¡£
µ¼º½ÖÁ Containers£º Ñ¡ÔñÈÝÆ÷·þÎñ

µ¥»÷ Create Cluster£º ´´½¨Ò»¸öм¯Èº

ÃüÃûÄúµÄ¼¯Èº£¬²¢´´½¨Ò»¸ö¼¯Èº£»µÈ´ý¼¸·ÖÖÓ£¬ÒÔ±ãÍêÈ«²¿Êð´Ë¼¯Èº¡£ÍêÈ«²¿Êðºó£¬µ¥»÷´Ë¼¯ÈºÒԲ鿴ÒѲ¿Êð¼¯ÈºµÄ¸ÅÊö£º
ÒѲ¿Êð¼¯ÈºµÄ¸ÅÊö

µ¥»÷×ó²àµ¼º½ÖÐµÄ Access£¬×ñÑָʾÐÅÏ¢½øÐвÙ×÷¡£
°²×°ÈÝÆ÷·þÎñ²å¼þ£º
$ bx plugin
install container-service -r Bluemix |
µÇ¼µ½ÄúµÄ IBM Cloud ÕÊ»§£º
$ bx login -a
https://api.eu-de.bluemix.net
$ bx cs region-set eu-central |
ÔÚ CLI ÖÐÉèÖü¯ÈºµÄ»·¾³£º
»ñÈ¡ÉèÖû·¾³±äÁ¿µÄÃüÁ²¢ÏÂÔØ Kubernetes ÅäÖÃÎļþ£º
$ bx cs cluster-config
NameOfYourCluster |
ÉèÖà KUBECONFIG »·¾³±äÁ¿¡£½«ÏÈǰÃüÁîµÄÊä³ö¸´ÖƲ¢Õ³Ìûµ½ÄúµÄÖÕ¶ËÄÚ¡£
ÁгöÄúµÄ¹¤×÷½Úµã£¬ÑéÖ¤ÄúÊÇ·ñ¿ÉÁ¬½Óµ½×Ô¼ºµÄ¼¯Èº£º
תÖÁ IBM Cloud Container Registry¡£
Ñ¡ÔñÊ׸öÃû³Æ¿Õ¼äµÄÃû³Æ£¬²¢´´½¨¸ÃÃû³Æ¿Õ¼ä¡£
$ bx cr namespace-add
<my_namespace> |
½«±¾µØ Docker ÊØ»¤³ÌÐò¼Ç¼µ½ IBM Cloud Container Registry ÖУº
Ñ¡Ôñ´æ´¢¿âºÍÓÃÓÚʶ±ð¾µÏñµÄ±êÇ©¡£ÔÚ±¾½Ì³ÌµÄÆäÓಿ·ÖʹÓÃÏàͬµÄ´æ´¢¿âºÍ±êÇ©¡£
$ docker tag
node1 <registry>/<my_namespace>/node1:latest
|
ÍÆË;µÏñ¡£
$ docker push
<registry>/<my_namespace>/node1:latest |
ÑéÖ¤ÄúµÄ¾µÏñÊÇ·ñλÓÚ˽ÓÐ×¢²á±íÖУº
¼ÈÈ»ÄúµÄÈÝÆ÷ÒѲ¿Êðµ½ IBM ÈÝÆ÷ÉÏ£¬ÊÇʱºòʹÓà Kubernetes À´ÔËÐÐһЩ pod ÁË¡£ ʹÓø´ÖÆ/Õ³Ìû½«¾µÏñÃû³Æ´Ó×¢²á±íµÄ˽ÓÐÃû³Æ¸ü¸ÄΪÆäËûÃû³Æ¡££¨Î»ÓÚ
service-deployment.yml ÎļþÖеľµÏñÊôÐÔ½«Óë˽ÓÐ×¢²á±íÖеľµÏñÃû³ÆÏàͬ¡££©
apiVersion:
extensions/v1beta1
kind: Deployment
metadata:
name: tendermintnodeone # give any name
spec:
replicas: 1
template:
metadata:
name: tendermintnodeone
labels:
run: tendermint1
spec:
containers:
- name: saif1cluster
image: "<registry>/<my_namespace>/node1:latest"
# your registry name
imagePullPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
name: my-service-tendermint-11 # give a service
name
labels:
run: tendermint1
spec:
type: NodePort
selector:
run: tendermint1
ports:
- protocol: TCP
name: tendermint1
port: 30090
nodePort: 30090
- protocol: TCP
name: port
port: 30092
nodePort: 30092 |
ÅäÖà Kubernetes ÒÔ´´½¨ pod¡¢·þÎñºÍ²¿Êð£º
$ kubectl create
-f service-deployment.yml |
ɾ³ýËùÓв¿Êð£º
$ kubectl delete
deployments --all |
ɾ³ýËùÓзþÎñ£º
$ kubectl delete
services --all |
·ÃÎÊ pod ºÍÈÕÖ¾£º
$ kubectl get
pods
$ kubectl logs podname |
·ÃÎÊ Tendermint RPC API£ºhttp://workerip:30092
¶Ô node2 ÖØ¸´ÏàͬµÄ²½Öè¡£
6´´½¨ÇáÁ¿¼¶¿Í»§¶ËÒÔÔÚÇø¿éÁ´ÉÏÖ´ÐжÁ/д²Ù×÷
°²×° lotion-connect£º
$ npm install
lotion-connect --save |
´´½¨ write.js£º
¶Ô read-write.js µÄÄÚÈݽøÐбàÂ룺
let { connect
} = require('lotion-connect')
async function main() {
let { state, send } = await connect(null, {
genesis: require('./genesis.json'),
nodes: [ 'ws://wordernode1:30092','ws://wordernode2:30092'
]
})
console.log(await state)
console.log(await send({ "sender": 'saif',"message":"himom"
}))
process.exit();
}
main() |
½áÊøÓï
Tendermint ±ãÓÚÒµÎñ¿ª·¢ÈËÔ±±àÐ´Çø¿éÁ´Ó¦Ó㬶ø IBM Cloud Ôò¼ò»¯ÁË´ËÀàÓ¦ÓõIJ¿ÊðºÍ²Ù×÷¡£
|