Skip to content

Commit

Permalink
feat(validator): add a draft of Iroha Validator
Browse files Browse the repository at this point in the history
Signed-off-by: Takeshi Yonezu <tkyonezu@gmail.com>
  • Loading branch information
tkyonezu authored and petermetz committed Sep 25, 2021
1 parent 90e4dd1 commit 466db28
Show file tree
Hide file tree
Showing 17 changed files with 661 additions and 0 deletions.
92 changes: 92 additions & 0 deletions packages-python/cactus_validator_socketio_iroha/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Socket.io-typed Validator for Iroha

## Features

This validator codes provides the following features:
- execSyncFunction (* under construction)
- sendSignedTransaction (* under construction)
- monitoring blocks

## How to test this validator

### Requirements:

- OS: Linux (Ubuntu or CentOS)
- node.js: v12
- python: v3.8
- Available port number: 5060

### How to execute test client (in the current status, only the monitor feature can be tested)

1. Launch [iroha-testnet](https://github.com/hyperledger/cactus/tree/main/tools/docker/iroha-testnet) docker and execute its wallet script
```
$ cd cactus/tools/docker/iroha-testnet/
$ docker-compose up -d
$ cd example/iroha-wallet
$ bash setup-iroha-wallet.sh
```

1. Launch validator server on the first console
```
$ cd cactus/packages-python/cactus_validator_socketio_iroha/validator-python
$ pip3 install websocket eventlet flask requests flask-socketio==4.3.2 pyyaml pyjwt cryptography iroha schedule
$ python3 -m main
```
- If there is the following message on your first console, the validator is successfully launched.

```
socket port: 5060
Server initialized for eventlet.
```

1. Execute test script on the second console

```
$ cd cactus/packages-python/cactus_validator_socketio_iroha/testcli
$ npm install
$ node testsock.js
```

- If there is the following message on your second console, the block monitoring request is successfully executed.

```
connect
81680a4dc06a4685b8219b22fd002023
polling
call nop!
##exec requestStartMonitor()
```

- After this request is executed, the messages about monitoring blocks (`##get_block block num is : n`) will appear on your first console.

```
81680a4dc06a4685b8219b22fd002023: Sending packet OPEN data {'sid': '81680a4dc06a4685b8219b22fd002023', 'upgrades': ['websocket'], 'pingTimeout': 60000, 'pingInterval': 25000}
on connect (sessionid: 81680a4dc06a4685b8219b22fd002023)
##called getValidatorInstance()
##IrohaConnector.__init__
81680a4dc06a4685b8219b22fd002023: Sending packet MESSAGE data 0
81680a4dc06a4685b8219b22fd002023: Received request to upgrade to websocket
81680a4dc06a4685b8219b22fd002023: Received packet MESSAGE data 2["test-event"]
received event "test-event" from 81680a4dc06a4685b8219b22fd002023 [/]
##IrohaConnector.cb()
81680a4dc06a4685b8219b22fd002023: Upgrade to websocket successful
81680a4dc06a4685b8219b22fd002023: Received packet MESSAGE data 2["nop"]
received event "nop" from 81680a4dc06a4685b8219b22fd002023 [/]
received nop
##IrohaConnector.nop()
81680a4dc06a4685b8219b22fd002023: Received packet MESSAGE data 2["startMonitor"]
received event "startMonitor" from 81680a4dc06a4685b8219b22fd002023 [/]
on startMonitor
##called monitoring_routine()
##get_block block num is : 1
##get_block block num is : 2
##get_block block num is : 3
...
##get_block block num is : 12
```

- After 180 seconds on the second console, run requestStopMonitor and the test script will stop running.

```
##exec requestStopMonitor()
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
port: 8000
logging_dir: ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
proto: ""
url: ""
publickey: ""
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
sign_key: ""
auth_credential: ""
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
port: 5060
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBdTCCARoCCQC/F+Mh551QzDAKBggqhkjOPQQDAjBCMQswCQYDVQQGEwJKUDEQ
MA4GA1UECAwHZXNqbXMxMjEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkg
THRkMB4XDTE4MDYyNzA3MjIzNVoXDTI4MDYyNDA3MjIzNVowQjELMAkGA1UEBhMC
SlAxEDAOBgNVBAgMB2Vzam1zMTIxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMg
UHR5IEx0ZDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDPpSD2w0zrqJKraGD1b
5Jq2sDuacThSUqi7fvz8oyrWtuKDjZ15zIaSOtak6XRxFh9V9Gokdg5GNbW/pTZc
TuowCgYIKoZIzj0EAwIDSQAwRgIhAKH6ERsyd5bpEMIkY4clPqguwDWoTLk2VKq6
ONEhUqotAiEA4yJxGmZpFdRScG2gDUIF2VDeX+XfHdJI2J41hyW9/zI=
-----END CERTIFICATE-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "testcli",
"version": "0.0.0",
"private": true,
"dependencies": {
"json-bigint": "^1.0.0",
"jsonwebtoken": "^8.5.1",
"socket.io-client": "^2.4.0"
}
}
102 changes: 102 additions & 0 deletions packages-python/cactus_validator_socketio_iroha/testcli/testsock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
const fs = require("fs");
const jwt = require("jsonwebtoken");
const JSONbig = require('json-bigint');

// NOTE: Run pip install socket.io-client.
const io = require('socket.io-client');
const url = "http://localhost:5060";
const socket = io(url, {
//transports: [ 'websocket', 'polling']
});

const crtPath = "3PfTJw8g.crt";
const paramAlgorithm = "ES256";

socket.on('connect', () => {
console.log('connect');
console.log(socket.id);
const transport = socket.io.engine.transport.name;
console.log(transport);
//socket.emit('mymessage', 'hoge');
});

socket.on('mymessage', () => {
console.log('received mymessage');
});

socket.on("response", (result) => {
console.log(`#[recv]response, res: ${result}`);
responseFlag = true;
decodeFunc(result.resObj.data);
});

socket.on("eventReceived", (result) => {
console.log(`#[recv]eventReceived, res: ${result}`);
responseFlag = true;
console.log(`#[recv]eventReceived, res_status: ${result.status}`)
decodeFunc(result.blockData);
});

const verify = (signature) => new Promise(resolve => {
const publicKey = fs.readFileSync(crtPath);

const option = {
algorithms: paramAlgorithm,
};

jwt.verify(signature, publicKey, option, (err, decoded) => {
return new Promise((resolve, reject) => {
if (err) {
// Authentication NG
console.log(`Authentication NG : error = ${err}`);
reject(err);
} else {
// Authentication OK
console.log(`Authentication OK`);
console.log(`decoded : ${JSON.stringify(decoded)}`);

resolve(decoded);
}
});
});
});

const decodeFunc = async (signsignature) => {
try {
console.log("call verify()");
console.log(`##signsignature: ${signsignature}`);
const decoded = await verify(signsignature);
console.log(`##decoded: ${decoded}`);

} catch (err) {
console.log(`err: ${err}`);
}
};

const requestStartMonitor = () => {
console.log('##exec requestStartMonitor()');
socket.emit('startMonitor');

setTimeout(requestStopMonitor,180000);
}

const requestStopMonitor = () => {
console.log('##exec requestStopMonitor()');
socket.emit('stopMonitor');

setTimeout(function(){
// end communication
socket.disconnect();
process.exit(0);
},5000);
}

setTimeout(requestStartMonitor, 2000);

socket.emit('test-event');

setTimeout(() => {
console.log('call nop!');
socket.emit('nop');
}, 1000);

Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
from typing import Type
from iroha import Iroha, IrohaCrypto, IrohaGrpc
import schedule

net = IrohaGrpc('localhost:50051')

iroha = Iroha('admin@test')
admin_priv_key = 'f101537e319568c765b2cc89698325604991dca57b9716b58016b253506cab70' #Private Key of user decided at previous line

temp_blocks = []
latestNumOfBlocks = 0
isMonitoring = False

def init():
global temp_blocks
global latestNumOfBlocks
global isMonitoring
temp_blocks = []
latestNumOfBlocks = 0
isMonitoring = True
get_diff_blocks()
clear_temp_blocks()

def get_block(blockNum):
# create Query
get_block_query = iroha.query(
'GetBlock',
height = blockNum
)
# sign Query
IrohaCrypto.sign_query(get_block_query, admin_priv_key)
# send Query
response = net.send_query(get_block_query)
return response

def get_diff_blocks():
print("called get_diff_blocks")
global temp_blocks
global latestNumOfBlocks

print(f"latestNumOfBlocks before execute: {latestNumOfBlocks}")

height = latestNumOfBlocks
is_latest = False

# get blocks from latestNumOfBlocks + 1
while(not is_latest):
height += 1
response = get_block(height)

if(response.error_response.error_code == 0):
temp_blocks.append(response)
elif(response.error_response.error_code == 3):
print(response.error_response.message)
latestNumOfBlocks = height - 1
is_latest = True

print(f"latestNumOfBlocks after execute: {latestNumOfBlocks}")

def clear_temp_blocks():
print("called clear_temp_blocks")
global temp_blocks
temp_blocks = []

def monitoring_routine():
get_diff_blocks()
print("temp_blocks")
print(temp_blocks)
# send blocks to verifier
# TODO implement
#after sending, clear temp
clear_temp_blocks()


# start monitoring
# when starting monitoring, call get_diff_blocks and clear_temp_blocks once as for get latest number of blocks
init()

schedule.every(1).minutes.do(monitoring_routine)

while isMonitoring:
schedule.run_pending()

print("finish")


Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
__pycache__
*.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-----BEGIN EC PARAMETERS-----
BggqhkjOPQMBBw==
-----END EC PARAMETERS-----
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEICIlCfK3zMTFzUgdaj01LAHjJmHlbg6Xql9+i70iPz5EoAoGCCqGSM49
AwEHoUQDQgAEM+lIPbDTOuokqtoYPVvkmrawO5pxOFJSqLt+/PyjKta24oONnXnM
hpI61qTpdHEWH1X0aiR2DkY1tb+lNlxO6g==
-----END EC PRIVATE KEY-----
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from validator_socketio_module.SocketIoValidator import SocketIoValidator

if __name__ == '__main__':
validator = SocketIoValidator()
validator.run()
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from abc import ABCMeta, abstractmethod

class AbstractConnector:
@abstractmethod
def __init__(self):
pass

@abstractmethod
def getValidatorInformation(self, validatorURL):
"""Get the validator information including version, name, ID, and other information"""
pass

@abstractmethod
def sendSignedTransaction(self, signedTransaction):
"""Request a verifier to execute a ledger operation"""
pass

@abstractmethod
def getBalance(self, address):
"""Get balance of an account for native token on a leder"""
pass

@abstractmethod
def execSyncFunction(self, address, funcName, args):
"""Execute a synchronous function held by a smart contract"""
pass

@abstractmethod
def startMonitor(self, clientId, cb):
"""Request a validator to start monitoring ledger"""
pass

@abstractmethod
def stopMonitor(self, clientId):
"""Request a validator to stop monitoring ledger"""
pass

@abstractmethod
def cb(self, callbackData):
"""Callback function to call when receiving data from Ledger"""
pass

@abstractmethod
def nop(self):
"""Nop function for testing"""
pass
Loading

0 comments on commit 466db28

Please sign in to comment.