From e10474afa45b8654019f1bd83fd8fc10b717eb33 Mon Sep 17 00:00:00 2001 From: MickeyWang Date: Wed, 4 Apr 2018 09:37:44 +0800 Subject: [PATCH 1/6] update some test;fix issue1;fix pr #7 --- package.json | 6 +- src/SDK/index.ts | 60 ++- src/claim.ts | 2 +- src/common/fixed64.ts | 41 ++ src/consts.ts | 4 +- src/core.ts | 42 +- src/crypto.ts | 23 ++ src/index.ts | 3 +- src/sdk/index.ts | 477 +++++++++++++++++++++++ src/smartcontract/data/IdContract.abi.ts | 2 +- src/smartcontract/data/IdContract.avm | Bin 9674 -> 10008 bytes src/transaction/DDO.ts | 67 ++-- src/transaction/TxSender.ts | 21 +- src/transaction/ddo.ts | 89 +++++ src/transaction/payload/deployCode.ts | 83 ++++ src/transaction/payload/invokeCode.ts | 147 +++++++ src/transaction/transaction.ts | 6 +- src/transaction/transactionBuilder.ts | 17 +- src/transaction/txSender.ts | 64 +++ test/AbiInfo.test.ts | 27 +- test/DDO.test.ts | 2 +- test/account.test.ts | 4 +- test/claim.test.ts | 20 +- test/core.test.ts | 47 +-- test/deployCodeTx.test.ts | 10 +- test/identity.test.ts | 2 +- test/scrypt.test.ts | 8 +- test/transfer.test.ts | 6 +- test/tx.node.ts | 40 +- tsconfig.json | 2 +- webpack.config.js | 2 +- 31 files changed, 1180 insertions(+), 144 deletions(-) create mode 100644 src/common/fixed64.ts create mode 100644 src/sdk/index.ts mode change 100644 => 100755 src/smartcontract/data/IdContract.avm create mode 100644 src/transaction/ddo.ts create mode 100644 src/transaction/payload/deployCode.ts create mode 100644 src/transaction/payload/invokeCode.ts create mode 100644 src/transaction/txSender.ts diff --git a/package.json b/package.json index ba94b80a..38ba66d5 100644 --- a/package.json +++ b/package.json @@ -5,9 +5,9 @@ "main": "./lib/index.js", "types": "./lib/types/index.d.ts", "scripts": { - "test": "jest", - "build:dev": "webpack --display-error-details --config webpack.config.js --progress --color", - "build:prod": "webpack --env.prod --config webpack.config.js --progress --color" + "test": "./node_modules/.bin/jest", + "build:dev": "./node_modules/.bin/webpack --display-error-details --config webpack.config.js --progress --color", + "build:prod": "./node_modules/.bin/webpack --env.prod --config webpack.config.js --progress --color" }, "jest": { "moduleFileExtensions": [ diff --git a/src/SDK/index.ts b/src/SDK/index.ts index e3b4ad53..94a8f78a 100644 --- a/src/SDK/index.ts +++ b/src/SDK/index.ts @@ -32,6 +32,33 @@ import axios from 'axios' import {BigNumber} from 'bignumber.js' import {DDO} from '../transaction/ddo'; export class SDK { + static SERVER_NODE : string + static REST_PORT : string + static SOCKET_PORT : string + + static setServerNode(node : string) { + if(node) { + SDK.SERVER_NODE = node + return; + } + throw new Error('Can not set ' + node + 'as server node') + } + + static setRestPort(port: string) { + if (port) { + SDK.REST_PORT = port + return; + } + throw new Error('Can not set ' + port + ' as restful port') + } + + static setSocketPort(port: string) { + if (port) { + SDK.SOCKET_PORT = port + return; + } + throw new Error('Can not set ' + port + 'as socket port') + } static getDecryptError(err:any) { return { @@ -80,7 +107,8 @@ export class SDK { socket.close() } } - var txSender = new TxSender(ONT_NETWORK.TEST) + let socket = `ws://${SDK.SERVER_NODE}:${SDK.SOCKET_PORT}` + var txSender = new TxSender(socket) txSender.sendTxWithSocket(param, socketCallback) // callback && sendBackResult2Native(JSON.stringify(obj), callback) return obj @@ -90,10 +118,8 @@ export class SDK { password : string, callback ?: string) { let identity = new Identity() let wallet = Wallet.parseJson(walletDataStr) - let privateKey = '' try { //TODO check ontid - privateKey = scrypt.decrypt(encryptedPrivateKey, password) identity = Identity.importIdentity(label, encryptedPrivateKey, password) } catch (err) { let obj = this.getDecryptError(err) @@ -109,9 +135,10 @@ export class SDK { desc : '' } //check ontid on chain - let tx = buildGetDDOTx(identity.ontid, privateKey) + let tx = buildGetDDOTx(identity.ontid) let param = buildRestfulParam(tx) - let url = sendRawTxRestfulUrl(TEST_ONT_URL.REST_URL, true) + let restUrl = `http://${SDK.SERVER_NODE}:${SDK.REST_PORT}/` + let url = sendRawTxRestfulUrl(restUrl, true) axios.post(url, param).then((res:any) => { if (res.data.Result && res.data.Result.length > 0 && res.data.Result[0] !== '0000000000000000') { @@ -130,9 +157,7 @@ export class SDK { static importIdentity(label : string, encryptedPrivateKey : string, password : string, callback ?: string) { let identity = new Identity() let error = {} - let privateKey try { - privateKey = scrypt.decrypt(encryptedPrivateKey, password) identity = Identity.importIdentity(label, encryptedPrivateKey, password) let wallet = new Wallet() wallet.create(identity.label) @@ -145,10 +170,11 @@ export class SDK { desc: '' } //check ontid on chain - let tx = buildGetDDOTx(identity.ontid, privateKey) + let tx = buildGetDDOTx(identity.ontid) let param = buildRestfulParam(tx) - let url = sendRawTxRestfulUrl(TEST_ONT_URL.REST_URL, true) - axios.post(url, param).then((res: any) => { + let restUrl = `http://${SDK.SERVER_NODE}:${SDK.REST_PORT}/` + let url = sendRawTxRestfulUrl(restUrl, true) + return axios.post(url, param).then((res: any) => { if (res.data.Result && res.data.Result.length > 0 && res.data.Result[0] !== '0000000000000000') { } else { @@ -163,7 +189,7 @@ export class SDK { } catch(err) { error = this.getDecryptError(err) callback && sendBackResult2Native(JSON.stringify(error), callback) - return error + return Promise.reject(error) } } @@ -180,8 +206,9 @@ export class SDK { //register ontid let tx = buildRegisterOntidTx(identity.ontid, privateKey) let param = buildRestfulParam(tx) - const url = TEST_ONT_URL.sendRawTxByRestful - axios.post(url, param).then((res: any) => { + let restUrl = `http://${SDK.SERVER_NODE}:${SDK.REST_PORT}${REST_API.sendRawTx}` + + axios.post(restUrl, param).then((res: any) => { if(res.data.Error === 0) { callback && sendBackResult2Native(JSON.stringify(obj), callback) } else { @@ -322,7 +349,8 @@ export class SDK { // let txId = core.getHash(tx.serialize()) let param = buildTxParam(tx) //通过socket能获得推送的结果 - var txSender = new TxSender(ONT_NETWORK.TEST) + let socket = `ws://${SDK.SERVER_NODE}:${SDK.SOCKET_PORT}` + var txSender = new TxSender(socket) const socketCallback = function(res : any, socket : any) { console.log('res: '+ JSON.stringify(res)) if(res.Action === 'InvokeTransaction' && res.Error === 0) { @@ -365,7 +393,7 @@ export class SDK { if(address.length === 40) { address = core.u160ToAddress(address) } - let request = `http://${TEST_NODE}:${HTTP_REST_PORT}${REST_API.getBalance}/${address}` + let request = `http://${SDK.SERVER_NODE}:${SDK.REST_PORT}${REST_API.getBalance}/${address}` axios.get(request).then((res : any) => { if(res.data.Error === 0) { let result = res.data.Result @@ -423,7 +451,7 @@ export class SDK { let tx = makeTransferTransaction('ONT',from, to, value, privateKey) var param = buildRestfulParam(tx) - let request = `http://${TEST_NODE}:${HTTP_REST_PORT}${REST_API.sendRawTx}` + let request = `http://${SDK.SERVER_NODE}:${SDK.REST_PORT}${REST_API.sendRawTx}` axios.post(request, param).then( (res:any) => { console.log('transfer response: ' + JSON.stringify(res.data)) if(res.data.Error === 0) { diff --git a/src/claim.ts b/src/claim.ts index 80346a58..62edb621 100644 --- a/src/claim.ts +++ b/src/claim.ts @@ -62,7 +62,7 @@ export class Claim { this.Id = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(JSON.stringify(body))).toString() } - sign( privateKey: string ) { + sign( privateKey: string ) : Signature { let claimBody = { Context: this.Context, Id: this.Id, diff --git a/src/common/fixed64.ts b/src/common/fixed64.ts new file mode 100644 index 00000000..703f22fe --- /dev/null +++ b/src/common/fixed64.ts @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + + +import {str2hexstr, hexstr2str ,StringReader} from '../utils' +const Fixed64Len = 8 +export default class Fixed64 { + //8 bytes + value : string + constructor() { + this.value = '0000000000000000' + } + + serialize() { + // return str2hexstr(this.value) + return this.value + } + + static deserialize(sr:StringReader) { + let f = new Fixed64() + const v = sr.read(8) + // f.value = hexstr2str(v) + f.value = v + return f + } +} \ No newline at end of file diff --git a/src/consts.ts b/src/consts.ts index d4aaa235..d1dd9a2c 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -42,7 +42,7 @@ export class Algorithm { export const DEFAULT_ALGORITHM = { algorithm : "ECDSA", parameters : { - "curve": "secp256r1" + "curve": "secp256r1" // also called p256 } } @@ -77,7 +77,7 @@ export const TEST_ONT_URL = { RPC_URL: `http://${TEST_NODE}:${HTTP_JSON_PORT}/`, - REST_URL: `http://${TEST_NODE}:${HTTP_REST_PORT}/`, +REST_URL: `http://${TEST_NODE}:${HTTP_REST_PORT}/`, sendRawTxByRestful : `http://${TEST_NODE}:${HTTP_REST_PORT}${REST_API.sendRawTx}` } diff --git a/src/core.ts b/src/core.ts index f1cb952c..e4401152 100644 --- a/src/core.ts +++ b/src/core.ts @@ -21,10 +21,13 @@ import * as base58 from 'bs58' import * as ecurve from 'ecurve' import * as bigInteger from 'bigi' import { ab2hexstring, hexstring2ab, StringReader, hexstr2str, num2hexstring } from './utils' -import { ADDR_VERSION } from './consts' +import { ADDR_VERSION, TEST_ONT_URL } from './consts' import * as scrypt from './scrypt' import {ERROR_CODE} from './error' import { VmType } from './transaction/vmcode'; +import { buildGetDDOTx, buildRestfulParam, sendRawTxRestfulUrl} from './transaction/transactionBuilder' +import axios from 'axios' +import { DDO } from './transaction/ddo' var ec = require('elliptic').ec var wif = require('wif') @@ -147,12 +150,20 @@ export function signatureData(data: string, privateKey: string): string { return signatureValue.toString('hex'); } -export function verifySignature(data : string, signature : string, publicKey : string) { + +/* +@data original value of signature +@signature +@publicKey the public key of the signer. is array-like or buffer +*/ +export function verifySignature(data: string, signature: string, publicKey: any) { let msg = cryptoJS.enc.Hex.parse(data) let msgHash = cryptoJS.SHA256(msg) let elliptic = new ec('p256') - const result = elliptic.verify(data.toString(), signature, publicKey, null) + let r = signature.substr(0, 64) + let s = signature.substr(64, 64) + const result = elliptic.verify(msgHash.toString(), { r, s }, publicKey, null) return result } @@ -212,11 +223,30 @@ export function checkPrivateKey(encryptedPrivateKey : string, password : string) return true } - +/* +@claim claim json object +*/ export function verifyOntidClaim(claim : any) { if(!claim.Metadata || !claim.Metadata.Issuer) { throw new Error('Invalid claim.') } - let issuer = claim.Metadata.Issuer - //TODO + let issuerDid = claim.Metadata.Issuer + let tx = buildGetDDOTx(issuerDid) + let param = buildRestfulParam(tx) + let url = sendRawTxRestfulUrl(TEST_ONT_URL.REST_URL, true) + return axios.post(url, param).then( (res:any) => { + if (res.data.Result && res.data.Result.length > 0) { + console.log('ddo hexstr: '+ res.data.Result[0]) + const ddo = DDO.deserialize(res.data.Result[0]) + console.log('ddo: ' + JSON.stringify(ddo)) + if(ddo.publicKeys.length > 0) { + const pk = ddo.publicKeys[0].pk + const signature = claim.Signature.Value + claim.delete('Signature') + return verifySignature(JSON.stringify(claim), signature, hexstring2ab(pk)) + } else { + return false + } + } + }) } \ No newline at end of file diff --git a/src/crypto.ts b/src/crypto.ts index 0c1e1833..25cea760 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -13,3 +13,26 @@ export enum SignatureSchema { SHA512withEDDSA } + +export enum CurveLabel { + P224 = 1, + P256 = 2, + P384 = 3, + P521 = 4, + + SM2P256V1 = 20, + + ED25519 = 25 +} + +export enum KeyType { + PK_ECDSA = 0x12, + PK_SM2 = 0x13, + PK_EDDSA = 0x14, +} + +export class PublicKey { + algorithm: number + curve: number + pk: string +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index d3fc4ae7..b194d310 100644 --- a/src/index.ts +++ b/src/index.ts @@ -31,7 +31,6 @@ import * as core from './core' import * as utils from './utils' import * as CONST from './consts' import { SDK } from './SDK/index' -import { CompleterResult } from 'readline'; class ONT { Account : any @@ -81,7 +80,7 @@ class ONT { this.CONST.HTTP_REST_PORT = port } - setWsPortyarn(port: string) { + setSocketPort(port: string) { this.CONST.HTTP_WS_PORT = port } } diff --git a/src/sdk/index.ts b/src/sdk/index.ts new file mode 100644 index 00000000..94a8f78a --- /dev/null +++ b/src/sdk/index.ts @@ -0,0 +1,477 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + +import {Wallet} from '../wallet' +import {Identity} from '../identity' +import {Account} from '../account' +import {Claim, Metadata, Signature} from '../claim' +import * as scrypt from '../scrypt' +import {sendBackResult2Native, EventEmitter, str2hexstr, ab2hexstring} from '../utils' +import * as core from '../core' +import {buildAddAttributeTx, buildTxParam, buildRpcParam, buildRegisterOntidTx, parseEventNotify, buildGetDDOTx, makeTransferTransaction, buildRestfulParam, sendRawTxRestfulUrl} from '../transaction/transactionBuilder' +import { ERROR_CODE } from '../error'; +import { ONT_NETWORK, TEST_NODE, REST_API, HTTP_REST_PORT, TEST_ONT_URL } from '../consts'; +import { encrypt } from '../scrypt'; +import TxSender from '../transaction/txSender' +import axios from 'axios' +import {BigNumber} from 'bignumber.js' +import {DDO} from '../transaction/ddo'; +export class SDK { + static SERVER_NODE : string + static REST_PORT : string + static SOCKET_PORT : string + + static setServerNode(node : string) { + if(node) { + SDK.SERVER_NODE = node + return; + } + throw new Error('Can not set ' + node + 'as server node') + } + + static setRestPort(port: string) { + if (port) { + SDK.REST_PORT = port + return; + } + throw new Error('Can not set ' + port + ' as restful port') + } + + static setSocketPort(port: string) { + if (port) { + SDK.SOCKET_PORT = port + return; + } + throw new Error('Can not set ' + port + 'as socket port') + } + + static getDecryptError(err:any) { + return { + error: ERROR_CODE.Decrypto_ERROR, + result: '', + desc: err.message || '' + } + } + + static createWallet(name : string, password : string, callback?: string) { + let wallet = new Wallet() + wallet.create(name) + let identity = new Identity() + let privateKey = core.generatePrivateKeyStr() + identity.create(privateKey, password,name) + + wallet.defaultOntid = identity.ontid + wallet.addIdentity(identity) + + // let account = new Account() + // account.create(privateKey, password, name) + // wallet.addAccount(account) + + let walletDataStr = wallet.toJson() + let obj = { + error: 0, + result: walletDataStr, + desc: '' + } + + let tx = buildRegisterOntidTx(identity.ontid, privateKey) + let param = buildTxParam(tx) + const socketCallback = function(res:any, socket:any) { + if(res.Error === 0) { + callback && sendBackResult2Native(JSON.stringify(obj), callback) + socket.close() + } else { + let errResult = { + error: res.Error, + result: '', + desc: res.Result + } + if (callback) { + sendBackResult2Native(JSON.stringify(errResult), callback) + } + socket.close() + } + } + let socket = `ws://${SDK.SERVER_NODE}:${SDK.SOCKET_PORT}` + var txSender = new TxSender(socket) + txSender.sendTxWithSocket(param, socketCallback) + // callback && sendBackResult2Native(JSON.stringify(obj), callback) + return obj + } + + static importIdentityWithWallet(walletDataStr : string, label : string, encryptedPrivateKey : string, + password : string, callback ?: string) { + let identity = new Identity() + let wallet = Wallet.parseJson(walletDataStr) + try { + //TODO check ontid + identity = Identity.importIdentity(label, encryptedPrivateKey, password) + } catch (err) { + let obj = this.getDecryptError(err) + + callback && sendBackResult2Native(JSON.stringify(obj), callback) + return obj + } + wallet.addIdentity(identity) + let walletStr = wallet.toJson() + let obj = { + error : ERROR_CODE.SUCCESS, + result : walletStr, + desc : '' + } + //check ontid on chain + let tx = buildGetDDOTx(identity.ontid) + let param = buildRestfulParam(tx) + let restUrl = `http://${SDK.SERVER_NODE}:${SDK.REST_PORT}/` + let url = sendRawTxRestfulUrl(restUrl, true) + axios.post(url, param).then((res:any) => { + if (res.data.Result && res.data.Result.length > 0 && res.data.Result[0] !== '0000000000000000') { + + } else { + obj.error = ERROR_CODE.UNKNOWN_ONTID + obj.result = '' + } + callback && sendBackResult2Native(JSON.stringify(obj), callback) + return obj + }) + // callback && sendBackResult2Native(JSON.stringify(obj), callback) + // return obj + } + + //send http post to check + static importIdentity(label : string, encryptedPrivateKey : string, password : string, callback ?: string) { + let identity = new Identity() + let error = {} + try { + identity = Identity.importIdentity(label, encryptedPrivateKey, password) + let wallet = new Wallet() + wallet.create(identity.label) + wallet.defaultOntid = identity.ontid + wallet.addIdentity(identity) + let walletStr = wallet.toJson() + let obj = { + error: ERROR_CODE.SUCCESS, + result: walletStr, + desc: '' + } + //check ontid on chain + let tx = buildGetDDOTx(identity.ontid) + let param = buildRestfulParam(tx) + let restUrl = `http://${SDK.SERVER_NODE}:${SDK.REST_PORT}/` + let url = sendRawTxRestfulUrl(restUrl, true) + return axios.post(url, param).then((res: any) => { + if (res.data.Result && res.data.Result.length > 0 && res.data.Result[0] !== '0000000000000000') { + + } else { + obj.error = ERROR_CODE.UNKNOWN_ONTID + obj.result = '' + } + callback && sendBackResult2Native(JSON.stringify(obj), callback) + return obj + }) + // callback && sendBackResult2Native(JSON.stringify(obj), callback) + // return obj + } catch(err) { + error = this.getDecryptError(err) + callback && sendBackResult2Native(JSON.stringify(error), callback) + return Promise.reject(error) + } + } + + static createIdentity(label : string, password : string, callback?: string) { + let identity = new Identity() + let privateKey = core.generatePrivateKeyStr() + identity.create(privateKey, password, label) + let result = identity.toJson() + let obj = { + error: ERROR_CODE.SUCCESS, + result: result, + desc: '' + } + //register ontid + let tx = buildRegisterOntidTx(identity.ontid, privateKey) + let param = buildRestfulParam(tx) + let restUrl = `http://${SDK.SERVER_NODE}:${SDK.REST_PORT}${REST_API.sendRawTx}` + + axios.post(restUrl, param).then((res: any) => { + if(res.data.Error === 0) { + callback && sendBackResult2Native(JSON.stringify(obj), callback) + } else { + let obj = { + error: JSON.stringify(res.data.Error), + result: res.data.Result + } + callback && sendBackResult2Native(JSON.stringify(obj), callback) + } + }) + return result + } + + static createAccount(label: string, password: string, callback?: string): string { + let account = new Account() + let privateKey = core.generatePrivateKeyStr() + account.create(privateKey, password, label) + let result = account.toJson() + if (callback) { + let obj = { + error : ERROR_CODE.SUCCESS, + result : result, + desc : '' + } + sendBackResult2Native(JSON.stringify(obj), callback) + } + return result + } + + static importAccountWithWallet(walletDataStr:string, label : string, encryptedPrivateKey:string, password:string, callback: string) { + let wallet = Wallet.parseJson(walletDataStr) + let account = new Account() + try { + account = Account.importAccount(label, encryptedPrivateKey, password) + } catch(err) { + let result = this.getDecryptError(err) + if (callback) { + sendBackResult2Native(JSON.stringify(result), callback) + } + return result + } + wallet.addAccount(account) + let walletStr = wallet.toJson() + let obj = { + error: ERROR_CODE.SUCCESS, + result: walletStr, + desc: '' + } + callback && sendBackResult2Native(JSON.stringify(obj), callback) + return obj + } + + static signSelfClaim(context: string, claimData : string, ontid : string, + encryptedPrivateKey : string, password : string, callback :string) { + let privateKey = '' + try { + privateKey = scrypt.decrypt(encryptedPrivateKey, password); + } catch(err) { + let result = this.getDecryptError(err) + + if (callback) { + sendBackResult2Native(JSON.stringify(result), callback) + } + return result + } + + let claimDataObj = JSON.parse(claimData) + let metadata = new Metadata() + let date = (new Date()).toISOString() + if(date.indexOf('.') > -1) { + date = date.substring(0, date.indexOf('.')) + 'Z' + } + metadata.CreateTime = date + metadata.Issuer = ontid + metadata.Subject = ontid + let claim = new Claim(context, claimDataObj, metadata) + claim.sign(privateKey) + let obj = { + error : 0, + result : claim, + desc : '' + } + if(callback) { + sendBackResult2Native(JSON.stringify(obj), callback) + } + return obj + } + + + static decryptEncryptedPrivateKey( encryptedPrivateKey : string, password : string, callback?: string) { + let privateKey = '' + try { + privateKey = scrypt.decrypt(encryptedPrivateKey, password); + } catch(err) { + let result = this.getDecryptError(err) + + if(callback) { + sendBackResult2Native(JSON.stringify(result), callback) + } + return result + } + let obj = { + error : 0, + result : privateKey, + desc : '' + } + + if (callback) { + sendBackResult2Native(JSON.stringify(obj), callback) + } + return obj + } + + + + static getClaim(claimId : string, context: string, issuer : string, subject : string, encryptedPrivateKey : string, + password : string, callback : string ) { + let privateKey = '' + try { + privateKey = scrypt.decrypt(encryptedPrivateKey, password); + } catch (err) { + let result = this.getDecryptError(err) + callback && sendBackResult2Native(JSON.stringify(result), callback) + return result + } + let path = str2hexstr('claim' + claimId) + let valueObj = { + Type : 'JSON', + Value : { + Context: context, + Issuer: issuer + } + } + let type = str2hexstr('JSON') + const value = str2hexstr(JSON.stringify(valueObj)) + let tx = buildAddAttributeTx(path, value,type, subject, privateKey) + + // let txId = core.getHash(tx.serialize()) + let param = buildTxParam(tx) + //通过socket能获得推送的结果 + let socket = `ws://${SDK.SERVER_NODE}:${SDK.SOCKET_PORT}` + var txSender = new TxSender(socket) + const socketCallback = function(res : any, socket : any) { + console.log('res: '+ JSON.stringify(res)) + if(res.Action === 'InvokeTransaction' && res.Error === 0) { + const txHash = res.Result[0].TxHash + let hash = ab2hexstring(txHash) + console.log('hash: '+ hash) + let obj = { + error : ERROR_CODE.SUCCESS, + result : hash + } + callback && sendBackResult2Native(JSON.stringify(obj), callback) + socket.close() + } + } + + txSender.sendTxWithSocket(param, socketCallback) + } + + static signData(content : string, encryptedPrivateKey : string, password : string, callback? : string) { + let privateKey = '' + try { + privateKey = scrypt.decrypt(encryptedPrivateKey, password); + } catch (err) { + let result = this.getDecryptError(err) + + callback && sendBackResult2Native(JSON.stringify(result), callback) + return result + } + let value = core.signatureData(content, privateKey) + + let result = new Signature() + result.Value = value + + callback && sendBackResult2Native(JSON.stringify(result), callback) + return result + } + + + static getBalance(address : string, callback : string) { + if(address.length === 40) { + address = core.u160ToAddress(address) + } + let request = `http://${SDK.SERVER_NODE}:${SDK.REST_PORT}${REST_API.getBalance}/${address}` + axios.get(request).then((res : any) => { + if(res.data.Error === 0) { + let result = res.data.Result + let obj = { + error : 0, + result : result + } + callback && sendBackResult2Native(JSON.stringify(obj), callback) + } else { + let obj = { + error: res.data.Error, + result : '' + } + callback && sendBackResult2Native(JSON.stringify(obj), callback) + + } + }).catch( (err:any) => { + let obj = { + error: JSON.stringify(err), + result: '' + } + callback && sendBackResult2Native(JSON.stringify(obj), callback) + }) + } + + //pls check balance before transfer + static transferAssets(token: string , from : string, to : string, value : string, encryptedPrivateKey : string, password : string, callback : string) { + try { + if (from.length !== 40) { + from = core.addressToU160(from) + } + if (to.length !== 40) { + to = core.addressToU160(to) + } + } catch(err) { + let result = { + error : ERROR_CODE.IllegalAddress, + result : '', + desc : 'Illegal adderss' + } + callback && sendBackResult2Native(JSON.stringify(result), callback) + return result + } + + let privateKey = '' + try { + privateKey = scrypt.decrypt(encryptedPrivateKey, password) + } catch (err) { + let result = this.getDecryptError(err) + if (callback) { + sendBackResult2Native(JSON.stringify(result), callback) + } + return result + } + + let tx = makeTransferTransaction('ONT',from, to, value, privateKey) + var param = buildRestfulParam(tx) + let request = `http://${SDK.SERVER_NODE}:${SDK.REST_PORT}${REST_API.sendRawTx}` + axios.post(request, param).then( (res:any) => { + console.log('transfer response: ' + JSON.stringify(res.data)) + if(res.data.Error === 0) { + let obj = { + error : 0, + result : '', + desc : 'Send transfer success.' + } + callback && sendBackResult2Native(JSON.stringify(obj), callback) + } else { + let obj = { + error: res.data.Error, + result: '', + desc: 'Send transfer failed.' + } + callback && sendBackResult2Native(JSON.stringify(obj), callback) + } + }).catch( (err:any) => { + console.log(err) + }) + } + +} \ No newline at end of file diff --git a/src/smartcontract/data/IdContract.abi.ts b/src/smartcontract/data/IdContract.abi.ts index c09428ce..af63ed6d 100644 --- a/src/smartcontract/data/IdContract.abi.ts +++ b/src/smartcontract/data/IdContract.abi.ts @@ -1,5 +1,5 @@ export default { - "hash": "80e7d2fc22c24c466f44c7688569cc6e6d6c6f92", + "hash": "80a45524f3f6a5b98d633e5c7a7458472ec5d625", "entrypoint": "Main", "functions": [ diff --git a/src/smartcontract/data/IdContract.avm b/src/smartcontract/data/IdContract.avm old mode 100644 new mode 100755 index eba7af77977c3ebc6af2a749fe75ac3ebee068e2..f1255149427d8a3292175d73e9b94b5a4b6e3d2d GIT binary patch delta 1190 zcmZuwZEO=|9Pjgx-nDn_U2kiz?YedCig6CsM7InBi7#nl6ajPXx;6L$H+MiBUl44< z9Q7r{w+{;Z$ka&0L=#NJxX=%NFhj{1HINWYOd!N1un+1t@zc5u!T)pZ#ymr@eKyHNt?QObbocCSe*P(yxbqG(=X~iFSMPf416Z-9e6@8Mw*Nf zcii^bE&NfV8Tsrf=jT>zQT$vRHp>Utb)1zucs5f1MgD_x)xeDM2>&>STgv|Yy0DOz zTzXh8Np9+|c)5^wYOC0=z$U_YPj%QdZmAu7PQ~_c8hxQ>aag);0K zW_XRoLY2zR#>(DG4YAU)Yde!N5tDc) zvWH#5-;qS}6Pb{mD_jw~7RdKEWQ>h`i;f+}7{99FoH4=o1w;q@8$UIeMy1Uz3z8ZNm(83M} z2s;$OoS6z76|)xI8Xni$aXqbgN5)46yVnt5QMY)*OyhVmf!^*28v)ChPufoMwvaVv z5$q%XQeL{3@4ZWT>l_pbKOxG9CA=%w1VYhkat%hLy*?42=e$eBGaaAvJ_);1eMqMi zepIG#ke~N^uY_EmPK`1BcgC17phY=XSdFmz@O^h0Tf2UOkv^8WD7D-#NP;FRe(Ob| ziLa&Rm@i36T}hAfe07O9t5Y;>r<`Axg>q#U!4N0@yJdWk*~d&+Srb||%v5w{2l?z0 zZsvwe+8`0dSo4c3J_iI86I}nEMccN#6<^DCb888U*@w;71#``g21H&y5lvuMPjCEm z!?wo`dWXj+t|Xn*Dd+4WKJ9r({-PnS_a@xPiB7ox{Pr3HdK()@yOsTbD2&He)cfWqbg delta 1102 zcmZuw?MqWp9Ns;-d-rnh?wy;PZfcubCaHZWOM4-T^@1-&yK`x!#a+&V{8E;Yi4g=^ zA4K^@^r6t8qQbzngg}Dg_MsQ(4+yM;$f8W8AU9v?ckZV3p)cEW&hz|!zvn#X+-rMY zRS#9M7&dq&DU2Z>Ms&&U=_fc*3`mw>(Un za~Lnw2<=W{{-3-AMg(Yx zUD0BU8`0cOsi_EtEME8^mXZfX5T!ugVJRCS%&)TUic z2BOWA6^LWt(PL4rm_x3RgHeau z&@bSotaidSi;W4xq}#DsiMG$t&6HCe7QCCsbttu#aXrk^HG)C56A``d$TAvdZG6l* zPPi%)Vx0;X^75g_#lcV4SyHD5#c6}@ZYM9(BJHR#HofU3Uo)2A4mNJhjW8A?!!T)S zbY2&~kY{4zhn5EkshowF*PeZg+DzNh(PxX^FwQv`^&TT%W?`Tp3mOUp?p;z*BDZzW zx1z`(tMtq0rQ}wAIJszK`;wY$NP^^BNBpy}%U6*ZqLTE3rblO!(C6FkJek0jt=iRU zlkpvOM9(MTn{N$wCP7D-pufO@;|;9F{f0_^Df=UV-5OxZ=Z68mnOm7aVP^upIN*if wn%zt3#>L#}VA{4l0n`3+?*0s7hKko`g;knMBl;|L@0OaMU{{R30 diff --git a/src/transaction/DDO.ts b/src/transaction/DDO.ts index aeee7568..e2ed5957 100644 --- a/src/transaction/DDO.ts +++ b/src/transaction/DDO.ts @@ -17,6 +17,7 @@ */ import {StringReader, hexstr2str} from '../utils' +import {PublicKey} from '../crypto' export class DDOAttribute { path : string @@ -25,42 +26,64 @@ export class DDOAttribute { constructor() {} } export class DDO { - publicKeys : Array = [] + publicKeys : Array = [] attributes : Array = [] + recovery : string constructor() {} - static deserialize(hexstr : string) : DDO { + static deserialize(hexstr: string): DDO { const ss = new StringReader(hexstr) let ddo = new DDO() //total length of public keys - 4 bytes - const pkTotalLen = parseInt(ss.read(4), 16) - const pkNum = ss.readNextLen() - - for(let i=0; i 0) { + const pkNum = parseInt(ss.read(4), 16) + for (let i = 0; i < pkNum; i++) { + //length of public key - 4 bytes + let pkLen = parseInt(ss.read(4), 16) + let pubKey = new PublicKey() + const rawPk = ss.read(pkLen) + const type = parseInt(rawPk.substr(0, 2), 16) + const curve = parseInt(rawPk.substr(2, 2), 16) + const pk = rawPk.substr(4) + pubKey.algorithm = type + pubKey.curve = curve + pubKey.pk = pk + ddo.publicKeys.push(pubKey) + } } + //attribute number - 4bytes const attrTotalLen = parseInt(ss.read(4),16) - const attrNum = ss.readNextLen() - for(let i=0; i 0) { + const attrNum = parseInt(ss.read(4), 16) + for (let i = 0; i < attrNum; i++) { + const totalLen = parseInt(ss.read(4), 16) + + let attr = new DDOAttribute() + const pathLen = parseInt(ss.read(4), 16) + attr.path = hexstr2str(ss.read(pathLen)) - const type_value_len = parseInt(ss.read(4), 16) - const typeLen = parseInt(ss.read(1), 16) - attr.type = hexstr2str(ss.read(typeLen)) + const type_value_len = parseInt(ss.read(4), 16) + const typeLen = parseInt(ss.read(1), 16) + attr.type = hexstr2str(ss.read(typeLen)) - const valueLen = type_value_len - typeLen - 1 - attr.value = hexstr2str(ss.read(valueLen)) - ddo.attributes.push(attr) + const valueLen = type_value_len - typeLen - 1 + attr.value = hexstr2str(ss.read(valueLen)) + ddo.attributes.push(attr) + } } + + //recovery + const recoveryTotalLen = parseInt(ss.read(4), 16) + if(recoveryTotalLen > 0 ) { + const recLen = parseInt(ss.read(4), 16) + const recovery = hexstr2str(ss.read(recLen)) + ddo.recovery = recovery + } + return ddo } } \ No newline at end of file diff --git a/src/transaction/TxSender.ts b/src/transaction/TxSender.ts index 8f4b736f..b52560fe 100644 --- a/src/transaction/TxSender.ts +++ b/src/transaction/TxSender.ts @@ -29,16 +29,9 @@ if(typeof window != 'undefined' && (window as any).WebSocket){ export default class TxSender { SOCKET_URL : string - RPC_URL : string - constructor (net : string) { - if(net === ONT_NETWORK.MAIN) { - this.SOCKET_URL = MAIN_ONT_URL.SOCKET_URL - this.RPC_URL = MAIN_ONT_URL.RPC_URL - } else { - this.SOCKET_URL = TEST_ONT_URL.SOCKET_URL - this.RPC_URL = TEST_ONT_URL.RPC_URL - } + constructor (socketUrl : string) { + this.SOCKET_URL = socketUrl } sendTxWithSocket(param : string, callback : (res:any, socket:any) => any) { @@ -55,16 +48,6 @@ export default class TxSender { } else { res = event.data } - // console.log('response for send tx: ' + JSON.stringify(res)) - // if (callback) { - // callback(event.data) - // socket.close() - // } - // if (res.Action === 'Notify') { - // let result = parseEventNotify(res) - // console.log('paresed event notify: ' + JSON.stringify(result)) - // } - // socket.close() //pass socket to let caller decide when to close the it. if(callback) { diff --git a/src/transaction/ddo.ts b/src/transaction/ddo.ts new file mode 100644 index 00000000..e2ed5957 --- /dev/null +++ b/src/transaction/ddo.ts @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + +import {StringReader, hexstr2str} from '../utils' +import {PublicKey} from '../crypto' + +export class DDOAttribute { + path : string + type : string + value : string + constructor() {} +} +export class DDO { + publicKeys : Array = [] + attributes : Array = [] + recovery : string + + constructor() {} + + static deserialize(hexstr: string): DDO { + const ss = new StringReader(hexstr) + let ddo = new DDO() + //total length of public keys - 4 bytes + const pkTotalLen = parseInt(ss.read(4),16) + if(pkTotalLen > 0) { + const pkNum = parseInt(ss.read(4), 16) + for (let i = 0; i < pkNum; i++) { + //length of public key - 4 bytes + let pkLen = parseInt(ss.read(4), 16) + let pubKey = new PublicKey() + const rawPk = ss.read(pkLen) + const type = parseInt(rawPk.substr(0, 2), 16) + const curve = parseInt(rawPk.substr(2, 2), 16) + const pk = rawPk.substr(4) + pubKey.algorithm = type + pubKey.curve = curve + pubKey.pk = pk + ddo.publicKeys.push(pubKey) + } + } + + + //attribute number - 4bytes + const attrTotalLen = parseInt(ss.read(4),16) + if(attrTotalLen > 0) { + const attrNum = parseInt(ss.read(4), 16) + for (let i = 0; i < attrNum; i++) { + const totalLen = parseInt(ss.read(4), 16) + + let attr = new DDOAttribute() + const pathLen = parseInt(ss.read(4), 16) + attr.path = hexstr2str(ss.read(pathLen)) + + const type_value_len = parseInt(ss.read(4), 16) + const typeLen = parseInt(ss.read(1), 16) + attr.type = hexstr2str(ss.read(typeLen)) + + const valueLen = type_value_len - typeLen - 1 + attr.value = hexstr2str(ss.read(valueLen)) + ddo.attributes.push(attr) + } + } + + //recovery + const recoveryTotalLen = parseInt(ss.read(4), 16) + if(recoveryTotalLen > 0 ) { + const recLen = parseInt(ss.read(4), 16) + const recovery = hexstr2str(ss.read(recLen)) + ddo.recovery = recovery + } + + return ddo + } +} \ No newline at end of file diff --git a/src/transaction/payload/deployCode.ts b/src/transaction/payload/deployCode.ts new file mode 100644 index 00000000..6d3a7f73 --- /dev/null +++ b/src/transaction/payload/deployCode.ts @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + + +import Payload from './payload' +import {VmType, VmCode} from '../vmcode' +import {str2VarBytes, hex2VarBytes, num2VarInt, bool2VarByte, StringReader, hexstr2str, num2hexstring} from '../../utils' + +export default class DeployCode extends Payload { + //hex string + code : VmCode + + needStorage : boolean + name : string + version : string + author : string + email : string + description : string + + constructor() { + super() + } + + + serialize() : string { + let result = '' + + result += this.code.serialize() + + result += bool2VarByte(this.needStorage) + + result += str2VarBytes(this.name) + + result += str2VarBytes(this.version) + + result += str2VarBytes(this.author) + + result += str2VarBytes(this.email) + + result += str2VarBytes(this.description) + + return result + } + + deserialize(sr : StringReader) : void { + + const code = VmCode.deserialize(sr) + this.code = code + + const boolValue = sr.read(1) + this.needStorage = boolValue == '00'? false : true + + const name = sr.readNextBytes() + this.name = hexstr2str(name) + + const codeVersion = sr.readNextBytes() + this.version = hexstr2str(codeVersion) + + const author = sr.readNextBytes() + this.author = hexstr2str(author) + + const email = sr.readNextBytes() + this.email = hexstr2str(email) + + const description = sr.readNextBytes() + this.description = hexstr2str(description) + } +} \ No newline at end of file diff --git a/src/transaction/payload/invokeCode.ts b/src/transaction/payload/invokeCode.ts new file mode 100644 index 00000000..1868de9d --- /dev/null +++ b/src/transaction/payload/invokeCode.ts @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + + +import Payload from './payload' +import { num2VarInt, num2hexstring, StringReader, str2hexstr, hexstr2str } from '../../utils' +import OPCODE from '../opcode' +import Fixed64 from '../../common/fixed64'; +import { VmCode } from '../vmcode'; + +export default class InvokeCode extends Payload { + //the length is of bytes 20 + /* + scriptHash : string + parameters : Array = [] + functionName : string + */ + + gasLimit : Fixed64 + code : VmCode + + constructor() { + super() + this.gasLimit = new Fixed64() + } + +/* serialize() : string { + let payloadLength + let paramsLength = num2hexstring( 0x50 + this.parameters.length) //start from '0x50' + const paramsEnd = 'c1' + let funcNameHex = str2hexstr(this.functionName) + const funcNameLength = num2hexstring(funcNameHex.length/2) + + let params = [] + for(let i = this.parameters.length-1; i > -1; i--) { + let p = this.parameters[i] + let hexP = p.getValue() + let hexPLength = num2VarInt( hexP.length / 2) + let opcode = '' + if( hexP.length/2 < OPCODE.PUSHBYTES75) { + + } else if (hexP.length / 2 < 0x100) { + opcode = num2VarInt( OPCODE.PUSHDATA1 ) + } else if( hexP.length/2 < 0x1000 ) { + opcode = num2hexstring( OPCODE.PUSHDATA2, 2, true) + } else { + opcode = num2hexstring( OPCODE.PUSHDATA4, 4, true) + } + params.push ({ + hexPLength, + hexP, + opcode + }) + } + + let result = '' + //scripthash + // result += this.scriptHash + //params + for(let v of params) { + if(v.opcode) { + result += v.opcode + } + result += v.hexPLength + result += v.hexP + } + result += paramsLength + //end + result += paramsEnd + //function + result += funcNameLength + result += funcNameHex + let totalParamsLength = num2VarInt(result.length / 2) + //result = this.scriptHash + totalParamsLength + result + + + console.log('invode serialze: '+ result) + + return result + } */ + + serialize() { + let result = '' + if(this.gasLimit) { + result += this.gasLimit.serialize() + } + result += this.code.serialize() + return result + } + + /* deserialize(ss : StringReader) : void { + //scriptHash, fixed langth + this.scriptHash = ss.read(20) + //payload total lenght + const payloadLen = ss.readNextLen() + + //read params start + let params = [] + let nextByte = ss.readNextLen() + //params's length start from 0x50 + while(nextByte < 0x50) { + let p = ss.read(nextByte) + params.push(p) + nextByte = ss.readNextLen() + } + //params end + let end = ss.read(1) + console.log('end :' + end) + if(end === 'c1') { + for(let i=0; i< params.length; i++) { + //TODO can only get value + this.parameters.push(new Parameter('','',params[i])) + } + } + //function name + let funNameLen = ss.readNextLen() + let func = ss.read(funNameLen) + func = hexstr2str(func) + //payload end + this.functionName = func + + } */ + + deserialize(sr : StringReader) { + let gasLimit = Fixed64.deserialize(sr) + let code = VmCode.deserialize(sr) + this.gasLimit = gasLimit + this.code = code + return this + } + +} diff --git a/src/transaction/transaction.ts b/src/transaction/transaction.ts index c1120386..b71a931e 100644 --- a/src/transaction/transaction.ts +++ b/src/transaction/transaction.ts @@ -25,6 +25,7 @@ import DeployCode from './payload/deployCode'; import Fixed64 from '../common/fixed64' import Uint160 from '../common/uint160'; import Uint256 from '../common/uint256'; +import { KeyType } from '../crypto' import * as core from '../core' import * as cryptoJS from 'crypto-js' @@ -65,11 +66,6 @@ export class Fee { payer : Uint160 } -export enum KeyType { - PK_ECDSA = 0x12, - PK_SM2 = 0x13, - PK_EDDSA = 0x14, -} export class PubKey { type : KeyType diff --git a/src/transaction/transactionBuilder.ts b/src/transaction/transactionBuilder.ts index 34266bb2..58587141 100644 --- a/src/transaction/transactionBuilder.ts +++ b/src/transaction/transactionBuilder.ts @@ -21,7 +21,7 @@ import AbiFunction from "../smartcontract/abi/abiFunction"; import {Parameter, ParameterType } from '../smartcontract/abi/parameter' import InvokeCode from './payload/invokeCode' import DeployCode from './payload/deployCode' -import {Transaction, TxType, Sig, PubKey, KeyType} from './transaction' +import {Transaction, TxType, Sig, PubKey} from './transaction' import {Transfers, Contract, State} from '../smartcontract/token' import {TransactionAttribute, TransactionAttributeUsage} from './txAttribute' import {createSignatureScript, getHash, getPublicKey } from '../core' @@ -195,6 +195,11 @@ export const buildSmartContractParam = (functionName : string, params : Array } -export const makeInvokeTransaction = (func : AbiFunction, scriptHash : string, privateKey : string) => { +export const makeInvokeTransaction = (func : AbiFunction, scriptHash : string, privateKey ?: string) => { let tx = new Transaction() tx.type = TxType.Invoke tx.version = 0x00 @@ -241,7 +246,9 @@ export const makeInvokeTransaction = (func : AbiFunction, scriptHash : string, tx.payload = payload //sig - signTransaction(tx, privateKey) + if(privateKey) { + signTransaction(tx, privateKey) + } return tx } @@ -332,7 +339,7 @@ export function buildRegisterOntidTx (ontid: string, privateKey: string) { return tx } -export function buildGetDDOTx(ontid : string, privateKey : string) { +export function buildGetDDOTx(ontid : string) { let f = abiInfo.getFunction('GetDDO') if (ontid.substr(0, 3) == 'did') { ontid = str2hexstr(ontid) @@ -342,7 +349,7 @@ export function buildGetDDOTx(ontid : string, privateKey : string) { let nonce = ab2hexstring( core.generateRandomArray(10) ) let p2 = new Parameter(f.parameters[1].getName(), ParameterType.ByteArray, nonce) f.setParamsValue(p1,p2) - let tx = makeInvokeTransaction( f, abiInfo.getHash(), privateKey) + let tx = makeInvokeTransaction( f, abiInfo.getHash(), '') return tx } diff --git a/src/transaction/txSender.ts b/src/transaction/txSender.ts new file mode 100644 index 00000000..b52560fe --- /dev/null +++ b/src/transaction/txSender.ts @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + +import {ONT_NETWORK, MAIN_ONT_URL, TEST_ONT_URL} from '../consts' +import {Transaction} from './transaction' +import axios from 'axios' + +var WebSocket : any +if(typeof window != 'undefined' && (window as any).WebSocket){ + WebSocket = (window as any).WebSocket +} else { + WebSocket = require('ws') +} + +export default class TxSender { + SOCKET_URL : string + + constructor (socketUrl : string) { + this.SOCKET_URL = socketUrl + } + + sendTxWithSocket(param : string, callback : (res:any, socket:any) => any) { + if(!param) return; + const socket = new WebSocket(this.SOCKET_URL) + socket.onopen = () => { + console.log('connected') + socket.send(param) + } + socket.onmessage = (event : any) => { + let res + if (typeof event.data === 'string') { + res = JSON.parse(event.data) + } else { + res = event.data + } + + //pass socket to let caller decide when to close the it. + if(callback) { + callback(res, socket) + } + } + socket.onerror = (event : any) => { + //no server or server is stopped + console.log(event) + socket.close() + } + } + +} \ No newline at end of file diff --git a/test/AbiInfo.test.ts b/test/AbiInfo.test.ts index 96dd39e2..32bb3ac5 100644 --- a/test/AbiInfo.test.ts +++ b/test/AbiInfo.test.ts @@ -18,7 +18,7 @@ import AbiInfo from '../src/smartcontract/abi/abiInfo' import AbiFunction from '../src/smartcontract/abi/abiFunction' -import Parameter from '../src/smartcontract/abi/parameter' +import {Parameter, ParameterType} from '../src/smartcontract/abi/parameter' import json from '../src/smartcontract/data/IdContract.abi' import {Transaction} from '../src/transaction/transaction' @@ -35,26 +35,24 @@ describe('test AbiInfo', () => { tx : Transaction, serialized : string + a = AbiInfo.parseJson(JSON.stringify(json)) + f = a.getFunction('RegIdWithPublicKey') test('test read json', () => { - a = AbiInfo.parseJson(JSON.stringify(json)) - f = a.getFunction('RegIdByPublicKey') - + expect(f.parameters.length).toEqual(2) let ontidhex = str2hexstr('did:ont:TQLASLtT6pWbThcSCYU1biVqhMnzhTgLFq') - let p1 = new Parameter('id', 'ByteArray',ontidhex) - let p2 = new Parameter('pk', 'ByteArray', '039fbb47841f7338c0c654addd6225995642b5b6d492413563f7f8755ba83c0ecd') + let p1 = new Parameter('ontid', ParameterType.ByteArray,ontidhex) + let p2 = new Parameter('publicKey', ParameterType.ByteArray, '039fbb47841f7338c0c654addd6225995642b5b6d492413563f7f8755ba83c0ecd') f.setParamsValue(p1,p2) console.log(f) - }) test('test make invokecode tx', () => { - let privateKey = generatePrivateKeyStr() - tx = makeInvokeTransaction( f, privateKey ) + tx = makeInvokeTransaction( f, a.getHash() ) console.log(tx) serialized = tx.serialize() @@ -66,15 +64,6 @@ describe('test AbiInfo', () => { let t = Transaction.deserialize(serialized) console.log('deserialized: '+ t.toString()) - expect(t.txAttributes.length).toEqual(1) + expect(t.txAttributes.length).toEqual(0) }) - - test('test deserialize with given string', ()=> { - let str = 'd100eacecb46f117f55c80147a9d391c7c65af10bd366921039fbb47841f7338c0c654addd6225995642b5b6d492413563f7f8755ba83c0ecd2a2a6469643a6f6e743a41526a42735a32546e6f336345384e3132706631454b6a67464c37646a4247573452c1194372656174654964656e7469747942795075626c69634b6579012014082e502f35ec5cf8cc1209d0de00c550578911a700000000000000000000014140e76b00f381f0b6a7cf9946a65d619c967e705ee94a58ac34c292bc4c238d53fffe9039c6fbfc9d9d08806d54ffe4e63d56cfd6a5acc903b9bff17c982347e4842321039fbb47841f7338c0c654addd6225995642b5b6d492413563f7f8755ba83c0ecdac' - let t = Transaction.deserialize(str) - console.log('deserialized str: '+JSON.stringify(t)) - expect(t.payload.parameters.length).toEqual(2) - }) - - }) diff --git a/test/DDO.test.ts b/test/DDO.test.ts index 8376e3f8..d9584aac 100644 --- a/test/DDO.test.ts +++ b/test/DDO.test.ts @@ -21,7 +21,7 @@ import {DDO} from '../src/transaction/ddo' const hexstring = // "000000260100000021039392ba7df4a7badc4cc498be257202f9bbb89c887502e9bcb96a6636ee050ba80000001c010000001700000004436572740000000b06537472696e6761626364" -"00000026010000002103fb3793c14e2233f01db2145307d179f0aa21ad239de61452cda4cc9278cbad2b000000d702000000a400000020b5a87bea92d52525b6eba3b670595cf8b9cbb51e972f5cbff499d48677ddee8a0000007c044a534f4e7b2254797065223a224a534f4e222c2256616c7565223a7b22436f6e74657874223a22636c61696d3a73746166665f61757468656e7469636174696f6e38222c22497373756572223a226469643a6f6e743a545675463646483150736b7a574a4146685741466731374e5369744d4445424e6f61227d7d0000002a0000000d436c61696d3a747769747465720000001506537472696e6777616e6731374074776974746572" +"0000002b0000000100000023120203fb3793c14e2233f01db2145307d179f0aa21ad239de61452cda4cc9278cbad2b000000d200000001000000ca00000046636c61696d3a623561383762656139326435323532356236656261336236373035393563663862396362623531653937326635636266663439396434383637376464656538610000007c044a534f4e7b2254797065223a224a534f4e222c2256616c7565223a7b22436f6e74657874223a22636c61696d3a73746166665f61757468656e7469636174696f6e38222c22497373756572223a226469643a6f6e743a545675463646483150736b7a574a4146685741466731374e5369744d4445424e6f61227d7d00000000" describe('test ddo', () => { test('test ddo deserialize', () => { let ddo = DDO.deserialize(hexstring) diff --git a/test/account.test.ts b/test/account.test.ts index c7688a04..b89ccdbc 100644 --- a/test/account.test.ts +++ b/test/account.test.ts @@ -45,7 +45,7 @@ describe('test account', ()=>{ test('test import account with correct password', () => { let a try { - a = Account.importAccount(accountDataStr, encryptedPrivateKey, '123456') + a = Account.importAccount('mickey', encryptedPrivateKey, '123456') } catch(err) {} expect(a.label).toBe('mickey') @@ -56,7 +56,7 @@ describe('test account', ()=>{ test('test import with incorrect password', () => { try { - let a = Account.importAccount(accountDataStr,encryptedPrivateKey, '1234567') + let a = Account.importAccount('mickey',encryptedPrivateKey, '1234567') } catch(err) { expect(err).toEqual(ERROR_CODE.Decrypto_ERROR) } diff --git a/test/claim.test.ts b/test/claim.test.ts index 23d59b82..2f9b919b 100644 --- a/test/claim.test.ts +++ b/test/claim.test.ts @@ -17,7 +17,7 @@ */ import {Claim , Metadata } from '../src/claim' -import {generatePrivateKeyStr, signatureData} from '../src/core' +import {generatePrivateKeyStr, signatureData, verifySignature, getPublicKey} from '../src/core' describe('test claim', () => { @@ -49,11 +49,27 @@ describe('test claim', () => { test('make a signature', ()=>{ const {Id, Metadata, Context, Content} = claim + //!!! the order of attributes matters let obj = { - Id, Metadata, Content, Context + Context: Context, + Id: Id, + Content: Content, + Metadata: Metadata } let signed = signatureData(JSON.stringify(obj), privateKey) let signatureValue = claim.Signature.Value expect(signed).toEqual(signatureValue) }) + + test('verify a signature', () => { + let publicKey = getPublicKey(privateKey, true) + let data = Object.assign({}, { + Context : claim.Context, + Id : claim.Id, + Content : claim.Content, + Metadata : claim.Metadata, + }) + let result = verifySignature(JSON.stringify(data), claim.Signature.Value, publicKey) + expect(result).toBeTruthy() + }) }) \ No newline at end of file diff --git a/test/core.test.ts b/test/core.test.ts index 09aa826b..1aa91d5a 100644 --- a/test/core.test.ts +++ b/test/core.test.ts @@ -32,39 +32,40 @@ describe('test core', ()=>{ privateKey = utils.ab2hexstring( core.generatePrivateKey() ) }) - test('test getWIFFromPrivateKey', () => { - wifKey = core.getWIFFromPrivateKey(privateKey) - expect(wifKey).toBeDefined() - }) + // test('test getWIFFromPrivateKey', () => { + // wifKey = core.getWIFFromPrivateKey(privateKey) + // expect(wifKey).toBeDefined() + // }) - test('test getPrivateKeyFromWIF', () => { - let key = core.getPrivateKeyFromWIF(wifKey) - expect(key).toEqual(privateKey) - }) + // test('test getPrivateKeyFromWIF', () => { + // let key = core.getPrivateKeyFromWIF(wifKey) + // expect(key).toEqual(privateKey) + // }) - test('get public key', () => { - let pkBuffer = core.getPublicKey(privateKey, true) - let pk = utils.ab2hexstring(pkBuffer) - console.log('get pk: ' + pk) - expect(pk).toBeDefined() - }) + // test('get public key', () => { + // let pkBuffer = core.getPublicKey(privateKey, true) + // let pk = utils.ab2hexstring(pkBuffer) + // console.log('get pk: ' + pk) + // expect(pk).toBeDefined() + // }) - test('encrypt private key', () => { - let privateKey = 'b02304dcb35bc9a055147f07b2a3291db4ac52f664ec38b436470c98db4200d9' - let wif = core.getWIFFromPrivateKey(privateKey) - let encrypt = scrypt.encrypt(wif, '123456') - console.log('encrypt: '+ encrypt) - }) + // test('encrypt private key', () => { + // let privateKey = 'b02304dcb35bc9a055147f07b2a3291db4ac52f664ec38b436470c98db4200d9' + // let wif = core.getWIFFromPrivateKey(privateKey) + // let encrypt = scrypt.encrypt(wif, '123456') + // console.log('encrypt: '+ encrypt) + // }) test('sign and verify', () => { let privateKey = core.generatePrivateKeyStr() let data = 'hello world' let signed = core.signatureData(data, privateKey) - console.log('signed: '+ signed) + console.log('signed: ' + signed) - let pk = ab2hexstring(core.getPublicKey(privateKey, false)) + let pk = core.getPublicKey(privateKey, true) let verifyResult = core.verifySignature(data, signed, pk) - expect(verifySignature).toBeTruthy() + console.log('verifyResult: ' + verifyResult) + expect(verifyResult).toBeTruthy() }) }) \ No newline at end of file diff --git a/test/deployCodeTx.test.ts b/test/deployCodeTx.test.ts index 231398bd..68992e46 100644 --- a/test/deployCodeTx.test.ts +++ b/test/deployCodeTx.test.ts @@ -51,7 +51,7 @@ var serialized const WebSocket = require('ws'); -var txSender = new TxSender(ONT_NETWORK.TEST) +var txSender = new TxSender(TEST_ONT_URL.SOCKET_URL) const testDeployCodeTx = () => { @@ -78,7 +78,9 @@ const testDeployCodeTx = () => { console.log('param: '+JSON.stringify(param)) axios.post(url, param).then((res)=>{ console.log('deploy res: '+JSON.stringify(res.data)) - getContract() + setTimeout(function() { + getContract() + }, 6000) }).catch(err => { console.log(err) }) @@ -117,9 +119,9 @@ const getContract = () => { -// testDeployCodeTx() +testDeployCodeTx() -getContract() +// getContract() // testDeserialize() /* diff --git a/test/identity.test.ts b/test/identity.test.ts index 5c3d3aef..88c73a45 100644 --- a/test/identity.test.ts +++ b/test/identity.test.ts @@ -44,7 +44,7 @@ describe('test identity', () => { console.log('encryptedkey: ' + encryptedPrivateKey) let a try { - a = Identity.importIdentity('', encryptedPrivateKey, '123456') + a = Identity.importIdentity('mickey', encryptedPrivateKey, '123456') } catch(err) { console.log(err) } diff --git a/test/scrypt.test.ts b/test/scrypt.test.ts index 11b65f61..8bbb71b7 100644 --- a/test/scrypt.test.ts +++ b/test/scrypt.test.ts @@ -18,6 +18,7 @@ import * as scrypt from '../src/scrypt' import * as core from '../src/core' +import { ERROR_CODE } from '../src/error'; describe('test scrypt', () => { it('test encrypt and decrypt', () => { @@ -28,7 +29,10 @@ describe('test scrypt', () => { let result = scrypt.decrypt(encrypt, '123456') expect(result).toEqual(privateKey) - result = scrypt.decrypt(encrypt, '1234567') - expect(result).not.toEqual(privateKey) + try { + result = scrypt.decrypt(encrypt, '1234567') + } catch(err) { + expect(err).toEqual(ERROR_CODE.Decrypto_ERROR) + } }) }) \ No newline at end of file diff --git a/test/transfer.test.ts b/test/transfer.test.ts index 8537a201..241d7f3e 100644 --- a/test/transfer.test.ts +++ b/test/transfer.test.ts @@ -25,11 +25,11 @@ import axios from 'axios' import { ab2hexstring, StringReader } from "../src/utils"; import {State} from '../src/smartcontract/token' import * as scrypt from '../src/scrypt' -import {TEST_NODE, HTTP_REST_PORT, REST_API, ONT_NETWORK} from '../src/consts' +import {TEST_NODE, HTTP_REST_PORT, REST_API, ONT_NETWORK, TEST_ONT_URL} from '../src/consts' import {BigNumber} from 'bignumber.js' import { addressToU160 } from "../src/core"; -var txSender = new TxSender(ONT_NETWORK.TEST) +var txSender = new TxSender(TEST_ONT_URL.SOCKET_URL) var accountFrom = { hexAddress: '018f0dcf09ec2f0040e6e8d7e54635dba40f7d63', @@ -82,7 +82,7 @@ const testTransferTx = () => { } const testGetBalance = (address, addressName) => { - let request = `http://${TEST_NODE}:${HTTP_REST_PORT}${REST_API.getBalance}/${address}` + let request = `https://${TEST_NODE}:${HTTP_REST_PORT}${REST_API.getBalance}/${address}` axios.get(request).then((res) => { let result = res.data.Result // console.log(result) diff --git a/test/tx.node.ts b/test/tx.node.ts index 188c4409..43d82d12 100644 --- a/test/tx.node.ts +++ b/test/tx.node.ts @@ -27,7 +27,7 @@ import AbiFunction from '../src/smartcontract/abi/abiFunction' import {Parameter, ParameterType } from '../src/smartcontract/abi/parameter' import json2 from '../src/smartcontract/data/IdContract.abi' import { ab2hexstring, str2hexstr, StringReader } from '../src/utils' -import { DEFAULT_ALGORITHM, ONT_NETWORK } from '../src/consts'; +import { DEFAULT_ALGORITHM, ONT_NETWORK, TEST_NODE } from '../src/consts'; import { DDO } from '../src/transaction/ddo' import { TEST_ONT_URL} from '../src/consts' import { getHash } from '../src/core'; @@ -36,7 +36,7 @@ import axios from 'axios' const codeHash = '80e7d2fc22c24c466f44c7688569cc6e6d6c6f92' -var txSender = new TxSender(ONT_NETWORK.TEST) +var txSender = new TxSender(TEST_ONT_URL.SOCKET_URL) // const SOCKET_URL = 'ws://52.80.115.91:20335' const Default_params = { @@ -139,7 +139,7 @@ const callback = function (res, socket) { } const testDDOTx = () => { - let tx = buildGetDDOTx(ontid, privateKey) + let tx = buildGetDDOTx(ontid) // let param = buildTxParam(tx, false) @@ -326,6 +326,38 @@ const testChangeRecovery = () => { sendTx(param) } +const testVerifyOntidClaim = () => { + var claim = { + "Context": "claim:github_authentication", + "Content": { + "GistCreateTime": "2018-02-28T03:24:48Z", + "Company": "onchain", + "Email": "leewi9@yahoo.com", + "Alias": "leewi9", + "Bio": "software engineer", + "Id": "10832544", + "GistUrl": "https://gist.github.com/42298ebb0c44054c43f48e1afd763ff6", + "Avatar": "https://avatars2.githubusercontent.com/u/10832544?v=4", + "Name": "zhouzhou", + "Location": "" + }, + "Signature": { + "Format": "pgp", + "Value": "rsjaenrxJm8qDmhtOHNBNOCOlvz/GC1c6CMnUb7KOb1jmHbMNGB63VXhtKflwSggyu1cVBK14/0t7qELqIrNmQ==", + "Algorithm": "ECDSAwithSHA256" + }, + "Metadata": { + "Issuer": "did:ont:TVuF6FH1PskzWJAFhWAFg17NSitMDEBNoK", + "CreateTime": "2018-03-07T16:06:21Z", + "Subject": "did:ont:TKhyXw8o6Em5GjmJwiPT1oNXsy4p6fYZPB" + }, + "Id": "111ab2f56d106dac92e891b6f7fc4d9546fdf2eb94a364208fa65a9996b03ba0" + } + core.verifyOntidClaim(claim).then(res =>{ + console.log('verify result : '+ res) + }) +} + //uncomment one line to test one tx each time. @@ -335,6 +367,8 @@ const testChangeRecovery = () => { testDDOTx() +// testVerifyOntidClaim() + // testDDOByRpc() // testGetPublicKeys() diff --git a/tsconfig.json b/tsconfig.json index 53c2dc77..4e4e18fe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { /* Basic Options */ "target": "ES6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ - "module": "amd", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "module": "umd", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation: */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ diff --git a/webpack.config.js b/webpack.config.js index 13a257e1..42113b4c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -26,7 +26,7 @@ let common = { 'child_process': 'empty' }, plugins: [ - new CleanWebpackPlugin(['lib/*.js', 'lib/*.js.map']) + new CleanWebpackPlugin(['lib/*.js', 'lib/*.js.map', 'lib/types/*']) ] } From be35a33263f6c34aa7677edc74e9231f4a4b32b9 Mon Sep 17 00:00:00 2001 From: MickeyWang Date: Wed, 4 Apr 2018 09:42:01 +0800 Subject: [PATCH 2/6] update tsconfig.json for build amd file --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 4e4e18fe..53c2dc77 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { /* Basic Options */ "target": "ES6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ - "module": "umd", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "module": "amd", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation: */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ From f8129b905464813968c5b813e5d94e301240ff40 Mon Sep 17 00:00:00 2001 From: MickeyWang Date: Wed, 4 Apr 2018 19:38:34 +0800 Subject: [PATCH 3/6] add verify ontid claim; add ontidContract tx --- src/SDK/index.ts | 10 +- src/consts.ts | 9 +- src/core.ts | 111 +++++++++++++++++- src/merkle.ts | 77 ++++++++++++ src/sdk/index.ts | 10 +- src/smartcontract/ontidContract.ts | 162 ++++++++++++++++++++++++++ src/transaction/DDO.ts | 3 +- src/transaction/TxSender.ts | 12 ++ src/transaction/ddo.ts | 3 +- src/transaction/transactionBuilder.ts | 62 +--------- src/transaction/txSender.ts | 12 ++ test/claim.test.ts | 2 +- test/tx.node.ts | 101 +++++----------- tsconfig.json | 2 +- 14 files changed, 427 insertions(+), 149 deletions(-) create mode 100644 src/merkle.ts create mode 100644 src/smartcontract/ontidContract.ts diff --git a/src/SDK/index.ts b/src/SDK/index.ts index 94a8f78a..d0354a39 100644 --- a/src/SDK/index.ts +++ b/src/SDK/index.ts @@ -23,7 +23,8 @@ import {Claim, Metadata, Signature} from '../claim' import * as scrypt from '../scrypt' import {sendBackResult2Native, EventEmitter, str2hexstr, ab2hexstring} from '../utils' import * as core from '../core' -import {buildAddAttributeTx, buildTxParam, buildRpcParam, buildRegisterOntidTx, parseEventNotify, buildGetDDOTx, makeTransferTransaction, buildRestfulParam, sendRawTxRestfulUrl} from '../transaction/transactionBuilder' +import { buildTxParam, buildRpcParam, parseEventNotify, makeTransferTransaction, buildRestfulParam, sendRawTxRestfulUrl} from '../transaction/transactionBuilder' +import { buildAddAttributeTx, buildRegisterOntidTx, buildGetDDOTx} from '../smartcontract/ontidContract' import { ERROR_CODE } from '../error'; import { ONT_NETWORK, TEST_NODE, REST_API, HTTP_REST_PORT, TEST_ONT_URL } from '../consts'; import { encrypt } from '../scrypt'; @@ -364,6 +365,13 @@ export class SDK { callback && sendBackResult2Native(JSON.stringify(obj), callback) socket.close() } + if(res.Error !== 0) { + let obj = { + error : res.Error, + result : '' + } + callback && sendBackResult2Native(JSON.stringify(obj), callback) + } } txSender.sendTxWithSocket(param, socketCallback) diff --git a/src/consts.ts b/src/consts.ts index d1dd9a2c..98db0703 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -63,7 +63,8 @@ export const HTTP_JSON_PORT = '20336' export const REST_API = { getBalance: '/api/v1/balance', - sendRawTx: '/api/v1/transaction' + sendRawTx: '/api/v1/transaction', + getMerkleProof : '/api/v1/merkleproof' // end with /txHash } @@ -73,11 +74,11 @@ export const ONT_NETWORK = { } export const TEST_ONT_URL = { - SOCKET_URL: `ws://${TEST_NODE}:${HTTP_WS_PORT}/`, + SOCKET_URL: `ws://${TEST_NODE}:${HTTP_WS_PORT}`, - RPC_URL: `http://${TEST_NODE}:${HTTP_JSON_PORT}/`, + RPC_URL: `http://${TEST_NODE}:${HTTP_JSON_PORT}`, -REST_URL: `http://${TEST_NODE}:${HTTP_REST_PORT}/`, + REST_URL: `http://${TEST_NODE}:${HTTP_REST_PORT}`, sendRawTxByRestful : `http://${TEST_NODE}:${HTTP_REST_PORT}${REST_API.sendRawTx}` } diff --git a/src/core.ts b/src/core.ts index e4401152..7dec2118 100644 --- a/src/core.ts +++ b/src/core.ts @@ -21,13 +21,15 @@ import * as base58 from 'bs58' import * as ecurve from 'ecurve' import * as bigInteger from 'bigi' import { ab2hexstring, hexstring2ab, StringReader, hexstr2str, num2hexstring } from './utils' -import { ADDR_VERSION, TEST_ONT_URL } from './consts' +import { ADDR_VERSION, TEST_ONT_URL, REST_API } from './consts' import * as scrypt from './scrypt' import {ERROR_CODE} from './error' import { VmType } from './transaction/vmcode'; import { buildGetDDOTx, buildRestfulParam, sendRawTxRestfulUrl} from './transaction/transactionBuilder' import axios from 'axios' import { DDO } from './transaction/ddo' +import { getPublicKeyStatus } from './smartcontract/ontidContract' +import { verifyLeafHashInclusion } from './merkle' var ec = require('elliptic').ec var wif = require('wif') @@ -249,4 +251,111 @@ export function verifyOntidClaim(claim : any) { } } }) +} + +const getDDO = (ontid : string, url ?: string) => { + let tx = buildGetDDOTx(ontid) + let param = buildRestfulParam(tx) + url = url || TEST_ONT_URL.REST_URL + let requestUrl = sendRawTxRestfulUrl(url , true) + return axios.post(requestUrl, param).then((res: any) => { + if (res.data.Result && res.data.Result.length > 0) { + console.log('ddo hexstr: ' + res.data.Result[0]) + const ddo = DDO.deserialize(res.data.Result[0]) + console.log('ddo: ' + JSON.stringify(ddo)) + return ddo + } + }) +} + +const getMerkleProof = (txHash : string, url ?: string) => { + url = url || TEST_ONT_URL.REST_URL + let requestUrl = `${url}${REST_API.getMerkleProof}/${txHash} ` + return axios.get(requestUrl).then((res:any)=> { + console.log('merkle : ' + JSON.stringify(res.data)) + return res.data + }) +} + +const getRovocationList = (url : string) => { + return axios.get(url).then(res => { + return res.data + }) +} + +const VerifyOntidClaimResult = { + CLAIM_NOT_ONCHAIN : 'CLAIM_NOT_ONCHAIN', + INVALID_SIGNATURE : 'INVALID_SIGNATURE', + PK_IN_REVOKEED : 'PK_IN_REVOKED', + EXPIRED_CLAIM : 'EXPIRED_CLAIM', + REVOKED_CLAIM : 'REVOKED_CLAIM', + VALID_CLAIM : 'VALID_CLAIM' +} + +/* +*@claim : claim json object +*@url : the node to send tx, eg: http://192.168.3.111:20334 +*/ + +export async function verifyOntidClaimAsync(claim : any, url ?: string) { + if (!claim.Metadata || !claim.Metadata.Issuer) { + throw new Error('Invalid claim.') + } + + //verify expiration + const expiration = new Date( claim.Metadata.Expires ) + let d = new Date() + if(d > expiration) { + return VerifyOntidClaimResult.EXPIRED_CLAIM + } + + // verify signature + let issuerDid = claim.Metadata.Issuer + //issuer is : ONTID#PkId + let issuerPkId = issuerDid.substr(issuerDid.indexOf('#') + 1) + //pkStatus = { publicKey, status : [IN USE, Revoked] } + let pkStatus = await getPublicKeyStatus(issuerDid, issuerPkId, url) + if (pkStatus.status === 'Revoked') { + return VerifyOntidClaimResult.PK_IN_REVOKEED + } + + //verify signature + const pk = pkStatus.publicKey.substr(0,4) === '1202' ? pkStatus.publicKey.substr(4) : pkStatus.publicKey + //the order of claim's attributes matters. + let signature = Object.assign({}, { + Context: claim.Context, + Id: claim.Id, + Content: claim.Content, + Metadata: claim.Metadata, + }) + + let result = verifySignature(JSON.stringify(claim), JSON.stringify(signature), hexstring2ab(pk)) + if(!result) { + return VerifyOntidClaimResult.INVALID_SIGNATURE + } + + // verify merkle + let merkle = await getMerkleProof(claim.txHash, url) + const leafHash = merkle.BlockRoot + const leafIndex = merkle.BlockHeight + const proof = merkle.TargetHashes + const rootHash = merkle.CurBlockRoot + const treeSize = merkle.CurBlockHeight + + let verifyMerkleResult = verifyLeafHashInclusion(leafHash, leafIndex, proof, rootHash, treeSize) + if(!verifyMerkleResult) { + return VerifyOntidClaimResult.CLAIM_NOT_ONCHAIN + } + + //verify revoke - optional + if(claim.Metadata.Revocation) { + let url = claim.Metadata.Crl + if(claim.Metadata.Revocation === 'RevocationList' && claim.Metadata.Crl) { + + } else if(claim.Metadata.Revocation === 'RevocationUrl') { + + } + } + + return VerifyOntidClaimResult.VALID_CLAIM } \ No newline at end of file diff --git a/src/merkle.ts b/src/merkle.ts new file mode 100644 index 00000000..189aa02c --- /dev/null +++ b/src/merkle.ts @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + +import * as cryptoJS from 'crypto-js' + + +/* + verify a Merkle Audit Path + + leaf_hash: The hash of the leaf for which the proof was provided. + leaf_index: Index of the leaf in the tree. + proof: A list of SHA-256 hashes representing the Merkle audit path. + tree_size: The size of the tree + root_hash: The root hash of the tree + + Returns: + true when the proof is valid +*/ +export function verifyLeafHashInclusion(leafHash : string, leafIndex : number, proof : Array, +rootHash : string, treeSize : number) { + if(treeSize <= leafIndex) { + throw new Error('Wrong params, the tree size is smaller than the leaf index') + } + + let calculatedRootHash = calculateRootHashFromAuditPath(leafHash, leafIndex, proof, treeSize) + if(calculatedRootHash !== rootHash) { + return false + } + return true +} + +export function calculateRootHashFromAuditPath(leafHash : string, leafIndex : number, proof : Array, treeSize : number) { + let calculatedHash = leafHash + let lastNode = treeSize - 1 + let pos = 0 + let pathLen = proof.length + while(lastNode > 0) { + if(pos > pathLen) { + throw new Error('Proof too short'); + } + if(leafIndex % 2 ===1) { + calculatedHash = hashChildren(proof[pos], calculatedHash) + pos += 1 + } else if (leafIndex < lastNode ){ + calculatedHash = hashChildren(calculatedHash, proof[pos]) + pos += 1 + } + leafIndex /= 2 + lastNode /= 2 + } + if(pos < pathLen) { + throw new Error('Proof too long') + } + return calculatedHash +} + +export function hashChildren(left : string, right : string) { + let data = '01' + left + data += right + let hex = cryptoJS.enc.Hex.parse(data); + return cryptoJS.SHA256(hex).toString(); +} \ No newline at end of file diff --git a/src/sdk/index.ts b/src/sdk/index.ts index 94a8f78a..d0354a39 100644 --- a/src/sdk/index.ts +++ b/src/sdk/index.ts @@ -23,7 +23,8 @@ import {Claim, Metadata, Signature} from '../claim' import * as scrypt from '../scrypt' import {sendBackResult2Native, EventEmitter, str2hexstr, ab2hexstring} from '../utils' import * as core from '../core' -import {buildAddAttributeTx, buildTxParam, buildRpcParam, buildRegisterOntidTx, parseEventNotify, buildGetDDOTx, makeTransferTransaction, buildRestfulParam, sendRawTxRestfulUrl} from '../transaction/transactionBuilder' +import { buildTxParam, buildRpcParam, parseEventNotify, makeTransferTransaction, buildRestfulParam, sendRawTxRestfulUrl} from '../transaction/transactionBuilder' +import { buildAddAttributeTx, buildRegisterOntidTx, buildGetDDOTx} from '../smartcontract/ontidContract' import { ERROR_CODE } from '../error'; import { ONT_NETWORK, TEST_NODE, REST_API, HTTP_REST_PORT, TEST_ONT_URL } from '../consts'; import { encrypt } from '../scrypt'; @@ -364,6 +365,13 @@ export class SDK { callback && sendBackResult2Native(JSON.stringify(obj), callback) socket.close() } + if(res.Error !== 0) { + let obj = { + error : res.Error, + result : '' + } + callback && sendBackResult2Native(JSON.stringify(obj), callback) + } } txSender.sendTxWithSocket(param, socketCallback) diff --git a/src/smartcontract/ontidContract.ts b/src/smartcontract/ontidContract.ts new file mode 100644 index 00000000..5389c379 --- /dev/null +++ b/src/smartcontract/ontidContract.ts @@ -0,0 +1,162 @@ + +import AbiInfo from '../smartcontract/abi/abiInfo' +import AbiFunction from "../smartcontract/abi/abiFunction"; +import { Parameter, ParameterType } from '../smartcontract/abi/parameter' + +import {TEST_ONT_URL} from '../consts' +import { sendRawTxRestfulUrl } from '../transaction/transactionBuilder'; +import axios from 'axios' +import * as core from '../core' +import {ab2hexstring, str2hexstr} from '../utils' +import {Transaction} from '../transaction/transaction' +import {makeInvokeTransaction} from '../transaction/transactionBuilder' + +import abiJson from '../smartcontract/data/IdContract.abi' +const abiInfo = AbiInfo.parseJson(JSON.stringify(abiJson)) + + +export function getPublicKeyStatus(ontid : string, pkId : string, url ?: string) { + url = url || TEST_ONT_URL.REST_URL + let requestUrl = sendRawTxRestfulUrl(url, true) + let param = '' + return axios.post(url, param).then(res => { + return res.data + }) +} + +export function buildGetPublicKeyStatusTx(ontid : string, pkId : string) { + +} + +export function buildRegisterOntidTx(ontid: string, privateKey: string) { + let publicKey = ab2hexstring(core.getPublicKey(privateKey, true)) + if (ontid.substr(0, 3) == 'did') { + ontid = str2hexstr(ontid) + } + console.log("Register ", ontid) + let f = abiInfo.getFunction('RegIdWithPublicKey') + + let name1 = f.parameters[0].getName(), + type1 = ParameterType.ByteArray + let p1 = new Parameter(name1, type1, ontid) + + + let name2 = f.parameters[1].getName(), + type2 = ParameterType.ByteArray + //algorithm&curve + publicKey = '1202' + publicKey + + let p2 = new Parameter(name2, type2, publicKey) + + f.setParamsValue(p1, p2) + let tx = makeInvokeTransaction(f, abiInfo.getHash(), privateKey) + + return tx +} + +//all parameters shuld be hex string +export function buildAddAttributeTx(path: string, value: string, type: string, ontid: string, privateKey: string) { + let publicKey = ab2hexstring(core.getPublicKey(privateKey, true)) + //algorithm&curve + publicKey = '1202' + publicKey + let f = abiInfo.getFunction('AddAttribute') + if (ontid.substr(0, 3) === 'did') { + ontid = str2hexstr(ontid) + } + let p1 = new Parameter(f.parameters[0].getName(), ParameterType.ByteArray, ontid) + let p2 = new Parameter(f.parameters[1].getName(), ParameterType.ByteArray, path) + let p3 = new Parameter(f.parameters[2].getName(), ParameterType.ByteArray, type) + let p4 = new Parameter(f.parameters[3].getName(), ParameterType.ByteArray, value) + let p5 = new Parameter(f.parameters[4].getName(), ParameterType.ByteArray, publicKey) + + f.setParamsValue(p1, p2, p3, p4, p5) + let tx = makeInvokeTransaction(f, abiInfo.getHash(), privateKey) + return tx +} + +export function buildGetDDOTx(ontid: string) { + let f = abiInfo.getFunction('GetDDO') + if (ontid.substr(0, 3) == 'did') { + ontid = str2hexstr(ontid) + } + + let p1 = new Parameter(f.parameters[0].getName(), ParameterType.ByteArray, ontid) + let nonce = ab2hexstring(core.generateRandomArray(10)) + let p2 = new Parameter(f.parameters[1].getName(), ParameterType.ByteArray, nonce) + f.setParamsValue(p1, p2) + let tx = makeInvokeTransaction(f, abiInfo.getHash()) + + return tx +} + +export function buildAddPKTx(ontid : string, newPk : string, sender : string, privateKey : string) { + let f = abiInfo.getFunction('AddKey') + if (ontid.substr(0, 3) === 'did') { + ontid = str2hexstr(ontid) + } + let p1 = new Parameter(f.parameters[0].getName(), ParameterType.ByteArray, ontid) + newPk = '1202' + newPk + let p2 = new Parameter(f.parameters[1].getName(), ParameterType.ByteArray, newPk) + sender = '1202' + sender + let p3 = new Parameter(f.parameters[2].getName(), ParameterType.ByteArray, sender) + + f.setParamsValue(p1, p2, p3) + let tx = makeInvokeTransaction(f, abiInfo.getHash(), privateKey) + return tx +} + +export function buildGetPublicKeysTx(ontid : string, privateKey : string) { + let f = abiInfo.getFunction('GetPublicKeys') + if (ontid.substr(0, 3) === 'did') { + ontid = str2hexstr(ontid) + } + let p1 = new Parameter(f.parameters[0].getName(), ParameterType.ByteArray, ontid) + f.setParamsValue(p1) + let tx = makeInvokeTransaction(f, abiInfo.getHash(), privateKey) + return tx +} + +export function buildRemovePkTx(ontid : string, pk2Remove : string, sender : string, privateKey : string) { + let f = abiInfo.getFunction('RemoveKey') + if (ontid.substr(0, 3) === 'did') { + ontid = str2hexstr(ontid) + } + let p1 = new Parameter(f.parameters[0].getName(), ParameterType.ByteArray, ontid) + pk2Remove = '1202' + pk2Remove + let p2 = new Parameter(f.parameters[1].getName(), ParameterType.ByteArray, pk2Remove) + sender = '1202' + sender + let p3 = new Parameter(f.parameters[2].getName(), ParameterType.ByteArray, sender) + + f.setParamsValue(p1, p2, p3) + let tx = makeInvokeTransaction(f, abiInfo.getHash(), privateKey) + return tx +} + +export function buildAddRecoveryTx(ontid : string, recovery : string, publicKey : string, privateKey : string) { + let f = abiInfo.getFunction('AddRecovery') + if (ontid.substr(0, 3) === 'did') { + ontid = str2hexstr(ontid) + } + let p1 = new Parameter(f.parameters[0].getName(), ParameterType.ByteArray, ontid) + let p2 = new Parameter(f.parameters[1].getName(), ParameterType.ByteArray, recovery) + publicKey = '1202' + publicKey + let p3 = new Parameter(f.parameters[2].getName(), ParameterType.ByteArray, publicKey) + + f.setParamsValue(p1, p2, p3) + let tx = makeInvokeTransaction(f, abiInfo.getHash(), privateKey) + return tx +} + +export function buildChangeRecoveryTx(ontid : string, newrecovery : string, oldrecovery : string, privateKey : string) { + let f = abiInfo.getFunction('ChangeRecovery') + if (ontid.substr(0, 3) === 'did') { + ontid = str2hexstr(ontid) + } + let p1 = new Parameter(f.parameters[0].getName(), ParameterType.ByteArray, ontid) + let p2 = new Parameter(f.parameters[1].getName(), ParameterType.ByteArray, newrecovery) + let p3 = new Parameter(f.parameters[2].getName(), ParameterType.ByteArray, oldrecovery) + + f.setParamsValue(p1, p2, p3) + let tx = makeInvokeTransaction(f, abiInfo.getHash(), privateKey) + return tx +} \ No newline at end of file diff --git a/src/transaction/DDO.ts b/src/transaction/DDO.ts index e2ed5957..95232cf8 100644 --- a/src/transaction/DDO.ts +++ b/src/transaction/DDO.ts @@ -79,8 +79,7 @@ export class DDO { //recovery const recoveryTotalLen = parseInt(ss.read(4), 16) if(recoveryTotalLen > 0 ) { - const recLen = parseInt(ss.read(4), 16) - const recovery = hexstr2str(ss.read(recLen)) + const recovery = ss.read(recoveryTotalLen) ddo.recovery = recovery } diff --git a/src/transaction/TxSender.ts b/src/transaction/TxSender.ts index b52560fe..c170fcb0 100644 --- a/src/transaction/TxSender.ts +++ b/src/transaction/TxSender.ts @@ -19,6 +19,7 @@ import {ONT_NETWORK, MAIN_ONT_URL, TEST_ONT_URL} from '../consts' import {Transaction} from './transaction' import axios from 'axios' +import { ERROR_CODE } from '../error'; var WebSocket : any if(typeof window != 'undefined' && (window as any).WebSocket){ @@ -57,6 +58,17 @@ export default class TxSender { socket.onerror = (event : any) => { //no server or server is stopped console.log(event) + let res + if (typeof event.data === 'string') { + res = JSON.parse(event.data) + } else { + res = event.data + } + res.Error = ERROR_CODE.NETWORK_ERROR + //pass socket to let caller decide when to close the it. + if (callback) { + callback(res, socket) + } socket.close() } } diff --git a/src/transaction/ddo.ts b/src/transaction/ddo.ts index e2ed5957..95232cf8 100644 --- a/src/transaction/ddo.ts +++ b/src/transaction/ddo.ts @@ -79,8 +79,7 @@ export class DDO { //recovery const recoveryTotalLen = parseInt(ss.read(4), 16) if(recoveryTotalLen > 0 ) { - const recLen = parseInt(ss.read(4), 16) - const recovery = hexstr2str(ss.read(recLen)) + const recovery = ss.read(recoveryTotalLen) ddo.recovery = recovery } diff --git a/src/transaction/transactionBuilder.ts b/src/transaction/transactionBuilder.ts index 58587141..c5a162a3 100644 --- a/src/transaction/transactionBuilder.ts +++ b/src/transaction/transactionBuilder.ts @@ -159,7 +159,7 @@ export const pushHexString = (param : string) => { } -//params is like [functionName, param1, param2...] +//params is like [param1, param2...] export const buildSmartContractParam = (functionName : string, params : Array) => { let result = '' for (let i= params.length -1; i > -1; i--) { @@ -293,66 +293,6 @@ export function buildTxParam (tx : Transaction, is_pre_exec : boolean = false) { return JSON.stringify(Object.assign({}, Default_params, { Data: serialized }, op)) } -//all parameters shuld be hex string -export function buildAddAttributeTx (path : string, value : string, type: string, ontid : string, privateKey : string) { - let publicKey = ab2hexstring(core.getPublicKey(privateKey, true)) - //algorithm&curve - publicKey = '1202' + publicKey - let f = abiInfo.getFunction('AddAttribute') - if(ontid.substr(0,3) === 'did') { - ontid = str2hexstr(ontid) - } - let p1 = new Parameter(f.parameters[0].getName(), ParameterType.ByteArray, ontid) - let p2 = new Parameter(f.parameters[1].getName(), ParameterType.ByteArray, path) - let p3 = new Parameter(f.parameters[2].getName(), ParameterType.ByteArray, type) - let p4 = new Parameter(f.parameters[3].getName(), ParameterType.ByteArray, value) - let p5 = new Parameter(f.parameters[4].getName(), ParameterType.ByteArray, publicKey) - - f.setParamsValue(p1, p2, p3, p4, p5) - let tx = makeInvokeTransaction( f,abiInfo.getHash(), privateKey) - return tx -} - -export function buildRegisterOntidTx (ontid: string, privateKey: string) { - let publicKey = ab2hexstring(core.getPublicKey(privateKey, true)) - if (ontid.substr(0, 3) == 'did') { - ontid = str2hexstr(ontid) - } - console.log("Register ", ontid) - let f = abiInfo.getFunction('RegIdWithPublicKey') - - let name1 = f.parameters[0].getName(), - type1 = ParameterType.ByteArray - let p1 = new Parameter(name1, type1, ontid) - - - let name2 = f.parameters[1].getName(), - type2 = ParameterType.ByteArray - //algorithm&curve - publicKey = '1202' + publicKey - - let p2 = new Parameter(name2, type2, publicKey) - - f.setParamsValue(p1, p2) - let tx = makeInvokeTransaction( f, abiInfo.getHash(), privateKey) - - return tx -} - -export function buildGetDDOTx(ontid : string) { - let f = abiInfo.getFunction('GetDDO') - if (ontid.substr(0, 3) == 'did') { - ontid = str2hexstr(ontid) - } - - let p1 = new Parameter(f.parameters[0].getName(), ParameterType.ByteArray, ontid) - let nonce = ab2hexstring( core.generateRandomArray(10) ) - let p2 = new Parameter(f.parameters[1].getName(), ParameterType.ByteArray, nonce) - f.setParamsValue(p1,p2) - let tx = makeInvokeTransaction( f, abiInfo.getHash(), '') - - return tx -} //{"jsonrpc": "2.0", "method": "sendrawtransaction", "params": ["raw transactioin in hex"], "id": 0} export function buildRpcParam(tx : any) { let param = tx.serialize() diff --git a/src/transaction/txSender.ts b/src/transaction/txSender.ts index b52560fe..c170fcb0 100644 --- a/src/transaction/txSender.ts +++ b/src/transaction/txSender.ts @@ -19,6 +19,7 @@ import {ONT_NETWORK, MAIN_ONT_URL, TEST_ONT_URL} from '../consts' import {Transaction} from './transaction' import axios from 'axios' +import { ERROR_CODE } from '../error'; var WebSocket : any if(typeof window != 'undefined' && (window as any).WebSocket){ @@ -57,6 +58,17 @@ export default class TxSender { socket.onerror = (event : any) => { //no server or server is stopped console.log(event) + let res + if (typeof event.data === 'string') { + res = JSON.parse(event.data) + } else { + res = event.data + } + res.Error = ERROR_CODE.NETWORK_ERROR + //pass socket to let caller decide when to close the it. + if (callback) { + callback(res, socket) + } socket.close() } } diff --git a/test/claim.test.ts b/test/claim.test.ts index 2f9b919b..7c61a01c 100644 --- a/test/claim.test.ts +++ b/test/claim.test.ts @@ -67,7 +67,7 @@ describe('test claim', () => { Context : claim.Context, Id : claim.Id, Content : claim.Content, - Metadata : claim.Metadata, + Metadata : claim.Metadata }) let result = verifySignature(JSON.stringify(data), claim.Signature.Value, publicKey) expect(result).toBeTruthy() diff --git a/test/tx.node.ts b/test/tx.node.ts index 43d82d12..98e5530c 100644 --- a/test/tx.node.ts +++ b/test/tx.node.ts @@ -16,8 +16,9 @@ * along with The ontology. If not, see . */ -import { makeInvokeTransaction , parseEventNotify, buildAddAttributeTx, buildGetDDOTx, - buildRpcParam, buildRegisterOntidTx, buildTxParam, buildRestfulParam, sendRawTxRestfulUrl } from '../src/transaction/transactionBuilder' +import { makeInvokeTransaction , parseEventNotify, + buildRpcParam, buildTxParam, buildRestfulParam, sendRawTxRestfulUrl } from '../src/transaction/transactionBuilder' +import {buildAddAttributeTx, buildGetDDOTx, buildRegisterOntidTx, buildAddPKTx, buildGetPublicKeysTx, buildRemovePkTx, buildAddRecoveryTx, buildChangeRecoveryTx} from '../src/smartcontract/ontidContract' import {Transaction} from '../src/transaction/transaction' import InvokeCode from '../src/transaction/payload/InvokeCode' import { Identity } from '../src/identity' @@ -63,12 +64,12 @@ abiInfo = AbiInfo.parseJson(JSON.stringify(json2)) // console.log('publick key: ' + publicKey) privateKey = '7c47df9664e7db85c1308c080f398400cb24283f5d922e76b478b5429e821b93' -publicKey = ab2hexstring(core.getPublicKey(privateKey, false)) -let publicKey2 = ab2hexstring(core.getPublicKey(privateKey, true)) +publicKey = ab2hexstring(core.getPublicKey(privateKey, true)) +// let publicKey2 = ab2hexstring(core.getPublicKey(privateKey, true)) -var pkPoint = core.getPublicKeyPoint(privateKey) -console.log('pk false: '+ publicKey) -console.log('pk true: ' + publicKey2) +// var pkPoint = core.getPublicKeyPoint(privateKey) +// console.log('pk false: '+ publicKey) +// console.log('pk true: ' + publicKey2) @@ -239,89 +240,39 @@ const testAddAttribute = () => { const testAddPK = () => { - let f = abiInfo.getFunction('AddKey') - - let p1 = new Parameter('id', ParameterType.ByteArray, ontid) - let p2 = new Parameter('newpubkey', ParameterType.ByteArray, pk2) - let p3 = new Parameter('sender', ParameterType.ByteArray, publicKey) - - f.setParamsValue(p1, p2, p3) - let tx = makeInvokeTransaction( f, abiInfo.getHash(), privateKey) - - let serialized = tx.serialize() - // console.log('add pk tx: ' + serialized) - - let param = JSON.stringify(Object.assign({}, Default_params, { Data: serialized })) + let tx = buildAddPKTx(ontid, pk2, publicKey, privateKey) + let param = buildTxParam(tx) console.log('add pk param: ' + param) sendTx(param) } const testGetPublicKeys = () => { - let f = abiInfo.getFunction('GetPublicKeys') - let p1 = new Parameter('id', ParameterType.ByteArray, ontid) - f.setParamsValue(p1) - let tx = makeInvokeTransaction(f, abiInfo.getHash(),privateKey) - let serialized = tx.serialize() - - let param = JSON.stringify(Object.assign({}, Default_params, {Data : serialized})) - sendTx(param) + let tx = buildGetPublicKeysTx(ontid, privateKey) + // let param = buildTxParam(tx) + // sendTx(param) + let param = buildRestfulParam(tx) + let url = sendRawTxRestfulUrl(TEST_ONT_URL.REST_URL, true) + axios.post(url, param).then(res => { + console.log(res.data) + }) } const testRemovePK = () => { - let f = abiInfo.getFunction('RemoveKey') - - let p1 = new Parameter('id', ParameterType.ByteArray, ontid) - let p2 = new Parameter('oldpubkey', ParameterType.ByteArray, pk2) - let p3 = new Parameter('sender', ParameterType.ByteArray, publicKey) - - f.setParamsValue(p1, p2, p3) - let tx = makeInvokeTransaction(f, abiInfo.getHash(), privateKey) - - let serialized = tx.serialize() - - // let hashed = core.getHash(serialized) - // console.log('remove pk tx: ' + serialized) - // console.log('hashed:' + hashed) - - let param = JSON.stringify(Object.assign({}, Default_params, { Data: serialized })) + let tx = buildRemovePkTx(ontid, pk2, publicKey, privateKey) + let param = buildTxParam(tx) console.log('remove pk param: ' + param) sendTx(param) } const testAddRecovery = () => { - let f = abiInfo.getFunction('AddRecovery') - - let p1 = new Parameter('id', ParameterType.ByteArray, ontid) - let p2 = new Parameter('recovery', ParameterType.ByteArray, oldrecovery) - let p3 = new Parameter('pk', ParameterType.ByteArray, publicKey) - - f.setParamsValue(p1, p2, p3) - let tx = makeInvokeTransaction(f, abiInfo.getHash(),privateKey) - - let serialized = tx.serialize() - - // let hashed = core.getHash(serialized) - // console.log('remove pk tx: ' + serialized) - // console.log('hashed:' + hashed) - - let param = JSON.stringify(Object.assign({}, Default_params, { Data: serialized })) - console.log('change recovery param: ' + param) + let tx = buildAddRecoveryTx(ontid, oldrecovery, publicKey, privateKey) + let param = buildTxParam(tx) sendTx(param) } const testChangeRecovery = () => { - let f = abiInfo.getFunction('ChangeRecovery') - - let p1 = new Parameter('id', ParameterType.ByteArray, ontid) - let p2 = new Parameter('newrecovery', ParameterType.ByteArray, newrecovery) - let p3 = new Parameter('recovery', ParameterType.ByteArray, oldrecovery) - - f.setParamsValue(p1, p2, p3) - let tx = makeInvokeTransaction(f, abiInfo.getHash(), privateKey) - - let serialized = tx.serialize() - - let param = JSON.stringify(Object.assign({}, Default_params, { Data: serialized })) + let tx = buildChangeRecoveryTx(ontid, newrecovery, oldrecovery, privateKey) + let param = buildTxParam(tx) console.log('change recovery param: ' + param) sendTx(param) } @@ -365,7 +316,7 @@ const testVerifyOntidClaim = () => { // testAddAttribute() -testDDOTx() +// testDDOTx() // testVerifyOntidClaim() @@ -381,6 +332,6 @@ testDDOTx() // testAddRecovery() -// testChangeRecovery() +testChangeRecovery() diff --git a/tsconfig.json b/tsconfig.json index 53c2dc77..4e4e18fe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { /* Basic Options */ "target": "ES6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ - "module": "amd", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "module": "umd", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation: */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ From 066aa1b01b8ad4580e77058916b1e4f11affead1 Mon Sep 17 00:00:00 2001 From: MickeyWang Date: Mon, 9 Apr 2018 11:47:29 +0800 Subject: [PATCH 4/6] update ontid contract --- src/consts.ts | 2 +- src/core.ts | 34 +++++++++--------- src/crypto.ts | 32 +++++++++++++++++ src/identity.ts | 2 +- src/merkle.ts | 4 +-- src/smartcontract/data/IdContract.avm | Bin 0 -> 10988 bytes src/smartcontract/data/idContract.abi.ts | 43 ++++++++++++++++++++++- src/smartcontract/data/idContract.avm | Bin 10008 -> 0 bytes src/smartcontract/ontidContract.ts | 33 ++++++++++++++--- src/transaction/transactionBuilder.ts | 4 +-- test/core.test.ts | 42 +++++++++++----------- test/deployCodeTx.test.ts | 7 ++-- test/merkle.test.ts | 35 ++++++++++++++++++ test/tx.node.ts | 34 ++++++++++++++++-- tsconfig.json | 2 +- 15 files changed, 220 insertions(+), 54 deletions(-) create mode 100644 src/smartcontract/data/IdContract.avm delete mode 100755 src/smartcontract/data/idContract.avm create mode 100644 test/merkle.test.ts diff --git a/src/consts.ts b/src/consts.ts index 98db0703..c5ef1b70 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -51,7 +51,7 @@ export const ALGORITHM_TYPE = { } export const TEST_NODE = '139.219.111.50' -// export const TEST_NODE = '192.168.3.97' +// export const TEST_NODE = '192.168.50.10' // export const TEST_NODE = '54.222.182.88' export const MAIN_NODE = '54.222.182.88' diff --git a/src/core.ts b/src/core.ts index 7dec2118..db207ad5 100644 --- a/src/core.ts +++ b/src/core.ts @@ -25,10 +25,10 @@ import { ADDR_VERSION, TEST_ONT_URL, REST_API } from './consts' import * as scrypt from './scrypt' import {ERROR_CODE} from './error' import { VmType } from './transaction/vmcode'; -import { buildGetDDOTx, buildRestfulParam, sendRawTxRestfulUrl} from './transaction/transactionBuilder' +import { buildRestfulParam, sendRawTxRestfulUrl} from './transaction/transactionBuilder' import axios from 'axios' import { DDO } from './transaction/ddo' -import { getPublicKeyStatus } from './smartcontract/ontidContract' +import { getPublicKeyStatus, buildGetDDOTx } from './smartcontract/ontidContract' import { verifyLeafHashInclusion } from './merkle' var ec = require('elliptic').ec @@ -268,12 +268,12 @@ const getDDO = (ontid : string, url ?: string) => { }) } -const getMerkleProof = (txHash : string, url ?: string) => { +export const getMerkleProof = (txHash : string, url ?: string) => { url = url || TEST_ONT_URL.REST_URL let requestUrl = `${url}${REST_API.getMerkleProof}/${txHash} ` return axios.get(requestUrl).then((res:any)=> { console.log('merkle : ' + JSON.stringify(res.data)) - return res.data + return res.data.Result }) } @@ -333,19 +333,21 @@ export async function verifyOntidClaimAsync(claim : any, url ?: string) { if(!result) { return VerifyOntidClaimResult.INVALID_SIGNATURE } - - // verify merkle - let merkle = await getMerkleProof(claim.txHash, url) - const leafHash = merkle.BlockRoot - const leafIndex = merkle.BlockHeight - const proof = merkle.TargetHashes - const rootHash = merkle.CurBlockRoot - const treeSize = merkle.CurBlockHeight - - let verifyMerkleResult = verifyLeafHashInclusion(leafHash, leafIndex, proof, rootHash, treeSize) - if(!verifyMerkleResult) { - return VerifyOntidClaimResult.CLAIM_NOT_ONCHAIN + if(claim.Proof) { + // verify merkle + let merkle = claim.Proof + const leafHash = merkle.BlockRoot + const leafIndex = merkle.BlockHeight + const proof = merkle.TargetHashes + const rootHash = merkle.CurBlockRoot + const treeSize = merkle.CurBlockHeight + + let verifyMerkleResult = verifyLeafHashInclusion(leafHash, leafIndex, proof, rootHash, treeSize) + if (!verifyMerkleResult) { + return VerifyOntidClaimResult.CLAIM_NOT_ONCHAIN + } } + //verify revoke - optional if(claim.Metadata.Revocation) { diff --git a/src/crypto.ts b/src/crypto.ts index 25cea760..e7c74f2e 100644 --- a/src/crypto.ts +++ b/src/crypto.ts @@ -1,3 +1,5 @@ +import { StringReader } from "./utils"; + export enum SignatureSchema { SHA224withECDSA = 0, SHA256withECDSA, @@ -35,4 +37,34 @@ export class PublicKey { algorithm: number curve: number pk: string + + static deserialize(sr : StringReader) { + let pub = new PublicKey() + const algorithm = parseInt(sr.read(1), 16) + const curve = parseInt(sr.read(1),16) + const pk = sr.read(33) + pub.algorithm = algorithm + pub.curve = curve + pub.pk = pk + return pub + } +} + +export enum PK_STATUS { + IN_USE = '01', + REVOKED = '00' +} + +export class PublicKeyStatus { + pk : PublicKey + status : string + + static deserialize(hexstr : string) : PublicKeyStatus { + let ps = new PublicKeyStatus() + const sr = new StringReader(hexstr) + const status = sr.read(1) + ps.status = status + ps.pk = PublicKey.deserialize(sr) + return ps + } } \ No newline at end of file diff --git a/src/identity.ts b/src/identity.ts index 9e91f403..78ccae24 100644 --- a/src/identity.ts +++ b/src/identity.ts @@ -21,7 +21,7 @@ import * as scrypt from './scrypt' import { ab2hexstring, hexstring2ab } from './utils' import {DEFAULT_ALGORITHM, Algorithm} from './consts' import {ERROR_CODE} from './error' -import { buildGetDDOTx, buildRegisterOntidTx, buildRestfulParam } from './transaction/transactionBuilder'; +import { buildRestfulParam } from './transaction/transactionBuilder'; import { checkPrivateKey } from './core'; export class ControlData { diff --git a/src/merkle.ts b/src/merkle.ts index 189aa02c..1470a445 100644 --- a/src/merkle.ts +++ b/src/merkle.ts @@ -60,8 +60,8 @@ export function calculateRootHashFromAuditPath(leafHash : string, leafIndex : nu calculatedHash = hashChildren(calculatedHash, proof[pos]) pos += 1 } - leafIndex /= 2 - lastNode /= 2 + leafIndex = Math.floor( leafIndex / 2 ) + lastNode = Math.floor( lastNode / 2) } if(pos < pathLen) { throw new Error('Proof too long') diff --git a/src/smartcontract/data/IdContract.avm b/src/smartcontract/data/IdContract.avm new file mode 100644 index 0000000000000000000000000000000000000000..cd2dc3b31add22f11ef24677c35c428f4d4ae0bf GIT binary patch literal 10988 zcmc&)d3+Vs6`n~T1QHTn5<-9k5J8b8D5wZRTO_#Diq5?EvamWYGg%5G^70-vHchOy zRl8VhK&_<)EpAn7YhBtRHuSo;Znf50wHCB$7isMx0c`C#=bl;K%glSR=&yg|&AoH) zJ?A^iJ?GpzQ5QeFe#7SVihj{U@X+94U{{prR`XeAU2CG{yku-cYvb8g=VdUU%Xzvm z*C;qq6aD&jWjnN@awICuB1M6IE%alL<x8+_f7DG-)>Ak?QoXs~-af>!o4PQbZvr$gvn2OfBcd<-)wzMi!MOQ!9C_G6mTdB*m&y$JtOM zvI@H^k&U;z*omyvYJgLQ#;ZD6X8c*u+q;+?Z zE!A)-Rk2ids$f-2y~;=BNAcKEDT3Xf>k({{ja3RZ+3rfgrZ9m?1ava}P9c@=FSfz8 zAUQ=8fXa2N5u71TyHuUZYp41EJBG)ONdY#=3+!kci3B#y?n+?OnZVHmX&U`bCt!Ct zF8Xv10V`V8Vzf0|DcFwX<;VJ9o5f?ZQm|cu#B6VvVS|y_jOkuV#hbx8*hDB#s2`3DmWs+0R;dyg}xrCjXcD7n=Ba#5; z^1N!oG8aQ#O{s0aTUAn1iI;vjVI-0i>D1$S?eXb6PDtf3kLR60Jmw*f6%LOY$z!ya zha^9rm(3UEIrhHPcwe5xV<)9pVgMt%ZHW_k%8A0Tavhg^9;YY***TjNDgoYQcvZ1i%4syqSoFl zvFUn}ST3@t6~=~SQ@ww(G^}^W!W<_#_G^8O#kfibtV>E`!xRlVoB+eNh?oLnhop!` zOT`MSy;@JUC0aLH)yrC}#`TbV+pLZb-|R|jACxSBw1(gpl|u^?1U`hhO)-!wr%OaK zs}$XtHcB1J467i+wU;|@$z$v2ZN)hGRsq77@j4CKm1RbL+-h#^NLXuE|9NmUtXm5yh%Nca7 zty|2Yu_~EGvgtNGS<~9RxrjpaLp4JUMe6}p*ych3#LB}CO@ zNrZh$+E3@8JgbD>2M=#b43TrximQ1hJjg^*q4faaZJvIw*3*ltIn}Qs#|;U+muPaH zgj{C^)6^va(Svk2=c^?k%MS80m9wi_;Y$Q&f+Aokdljw3uIT0UoQ~D;LF>sU1xNzR zxE@0)5lIDK3Mmd}a&M{%k|uC5RxfhiS9ajcK{XJ0;5rq?WKmO!+xxXroa-q$=A&=f z6L74I{9&vx!cfvcAp<3i4kb-QmNc6x&;eKD99bKc3d9)&_rb*>(h9mP^uSH|o$cbd zHX<~fitbH4_*p6X;8*2JMx7)YC;l7N#Pu!i(R+(h2H)5b|JM>_RUBsdFDAoKwD zWY(2g%&-kb^EboG1)0q-I=dN2>7)`;`rhFVMPG&QvK77?i^@R?e-p8~3crLDP9~)d zuzVy8b3n4quocX(r_gb8I)F-L&n-6c;&jl1RW=blex&*yRLKB!Z_=GU8eaJ8d&4M4 zJ5DHIcf@TFyBf8V+3nNxy=j<3(XC&kpAf|wTi^Q&`YB|lTZLv#lCyw0skyX}Di0bW zM~l*augl_Sv(cpff_IE`VEPK4kb>iSh`DnKk( z7=(-th9%V*cu+&l-~*C>Un2!I(2#XyejpswdaMO^69nrFL5-{%m5By)(3|5>bT@^x zE>SE;iZq?xnY&jvbLKIu*YQ%0oqLxU2zb-2giY8q3MT?hc!Xs=$j%3Ggmi`n zA{c~Q*gPdRUAh<%H>~>#QNxsG&_Z}#inY8CEsU3s*q2Apuf^b@3!Lq^541^CvSS13 zeDxrmx6y4c&>f=AqX819>D*DOS*#c+5>+xCDw>+Kjwmy0xR!(o(l8qpw!C!}>Y*MQ zmlt#!)}`1Z8}7|!!)QhhPDC}V8!?cwUQ=yY$2N2fjyCL2J_O15*1@puMh8OiZW{&S z?HrZj5$HRy3ARVvgP~1&0qL78FE3&OcCcY>9LD;}gjpB$$W{xo25ocVCiiwAxA$|0 z#I4~2aSIRf>T8h=Mv_cIX`(K`naO=f9H`15RMk2RY_jmgvS7(!7Ki&cyax^5-Zj?`V3F@6Ch z-^huahq0o_v?{w1nYL14o@YUd)lp3?oOD5pfIN78Rl|&@K zY6xB?7|>4&L6iiYA(J;KA|jpc$N_2}5kT$30vP1?N2`WL?E`vN*FHK~WCK2!T%R>I^2b>Jh>a$*ZWXkAS|NZixEO z!OKdL@;b%H2l0b#R*j~ws_?Vkki%1OWIdALgx0}ZJpb6~T2acPM0yOXQpH6wqC<2e z3Vz<~CTq{)SJAM}Vp<#RMXHaG#ciq$G=i6$I^B?`7XmIYCMQ`K*2}7@aj^v`V4boj56y+O%l*{Ca^_BIrI(uNBK7;A{lCieE=C2E>FwdROs`Q3WqOfX zGQp%vHrSgpyCfZ90*mH!r*!wBt1#9R8aGQsuEj;78wG+dZH5)1(1*vuFuVu9vrGeA9#J*x7xas(a9ls~tNw z9|BUW8T+=V%X$`Taoz>IQQ?AQ7rte$4-2{rb-dgANnoOiGzA^VofEWKpZN&M%)1r* z=v#i+SII!u#aM92Fk&|iji|%}gm)kEC7jvyXf-+m`uVd&-GVGL90rg$wdf8hWyuMS|I;ku0Vj|zoPkyiKsGziJQ1O9?!2|}Sw)P7)#XAzo&7Zlj z^P%z8>esIP`j)G{(Ytlq)z@76&Fj9k{oB{~?YQB_ z@9ezk=38#P?Yp<%ap(8$`u-2@{^33M-gp0xe*BYN5A1&Mr~P|=CLVhDkw+hU{E46c z;>o9;e&*R)# literal 0 HcmV?d00001 diff --git a/src/smartcontract/data/idContract.abi.ts b/src/smartcontract/data/idContract.abi.ts index af63ed6d..b476959c 100644 --- a/src/smartcontract/data/idContract.abi.ts +++ b/src/smartcontract/data/idContract.abi.ts @@ -1,5 +1,5 @@ export default { - "hash": "80a45524f3f6a5b98d633e5c7a7458472ec5d625", + "hash": "8055b362904715fd84536e754868f4c8d27ca3f6", "entrypoint": "Main", "functions": [ @@ -196,6 +196,47 @@ export default { ], "returntype": "ByteArray" }, + { + "name": "GetPublicKeyId", + "parameters": + [ + { + "name": "ontId", + "type": "ByteArray" + }, + { + "name": "publicKey", + "type": "ByteArray" + } + ], + "returntype": "ByteArray" + }, + { + "name": "GetPublicKeyStatus", + "parameters": + [ + { + "name": "ontId", + "type": "ByteArray" + }, + { + "name": "pkId", + "type": "ByteArray" + } + ], + "returntype": "ByteArray" + }, + { + "name": "GetRecovery", + "parameters": + [ + { + "name": "ontId", + "type": "ByteArray" + } + ], + "returntype": "ByteArray" + }, { "name": "GetDDO", "parameters": diff --git a/src/smartcontract/data/idContract.avm b/src/smartcontract/data/idContract.avm deleted file mode 100755 index f1255149427d8a3292175d73e9b94b5a4b6e3d2d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10008 zcmc&(d3;<|6@D*i(=2Vmq-~n6v~-~xVQDESAl4QTu!Z+#CR>xXZ}M&yTN*l1XvBh0M5v6Gh!a3)jw@uz;Qo)~pWZt{)o_o%B zzI*OD_ulAB9$dG6(>l$(@Bw%j@UXBc%T3X8rd`vPYCSidSl`xkw&=V9I!q;JO1n`* zK|}VN+q7-)7FRuSX_smmw5y?=7*RknnuJGG2^iAAR!p^`^e(L~v3I01=qY^Dpf*DigxUavI;UkKhP5qNE#j6M8;~TMM&1DRwIH~jX!G$$(&*b z$sMRjlSQUDuYHqXFnUA{(<9RE%pgV|&wb+qfSP@P^l}FSA=1Y>O@gG4V+G}iM;}YS z;|SI+7uEy?Ycvq#&KORZUcrMaq8ICzaq}((}Nk~76#g3Bp3MZxwj_ISh@92OR1DF+^n66@x zDrt$C?sPtjBAP^VZlEc1$FTe{A?A+bzT*PsHv7#T%Ob~uxw&OvghIPnnJWNu%a@-+ zOLY+oE|T^s>=tECeX;7`?5!Wqa*K)K<1v9Rh&XzE1t1?yR7-1py16F2&{!gG9LTtZ zrQhglD#KAGU_CRE7@--^;NlT=T*UH`cu2WuwN|ba?Nw%aL#pjOQMIg9G_8ZewLx@r zgjOaRd!;e~stp8xI$}Ul@F8uBd`ASQMlb|Sse#bL{BFQ|L%CI$6fJEXDUk#L4U`l@ z!J>Bb{?>9oqLuBbw&qR?{UFGY(^( zxUMuhJYi)?yqXUK!Oa{zaot%H7`p?%s)}h#B*J#pk*@J>!-Rw7RrhsuO4pfaW9Z+F`1sKXZ5oq_Ln>DhR$8(9& zE3=Jfaniz@64Vk?THv=XWkBQ^<)p-Z6kJKM3mL-2-$5Tq27kFiy=n4=-m@4ZxjK|<>KmyeMpj=|G#36X#v6eXDjVwf{ z`s4&Rj*LkI1u?Lx1wZw&4}NuTE6_CK9r%E&GJgz?A#{{v_LQZmjrn6rsoMw3ze}te z^Izo?THlmJR#OtG%aKF2Vyy|}kceW?5-*i#+c=9b1;M@i%P0sbF?$xVC%Cf#a$VxB z0#~EAY4;U}s~poiM}ul6)uZb!#LBCqR@za@$<&S00Q#RBZRK0G4N_F2fMYXRbI1hVJ<`<}O5oKFfftp85x4`fdIVMn2;2e$ zUSDDrBZ0I@hi`E}-e18hahk#%UsLG940SxE9LMpHS*nU*_O?Xq zxjE@@wT3#M;nv)6w^n7DPtO^IjQI?KnKxOP}q7(xRi3>+%g@ddoT6Gu$ z=`dG{iK_$-9Q5Y78ofYQvr8H)P$P-cygiQCxD3`wdo!&FM0VpS=-?d<-NVRQGj|n(+p{2cd1p7KHs)d0>pi3FQ*wQ+(h~`dZXsq@Hm*A2jz~-&hO`O~;u?z2MI2fo} z)Jg-BT~Pr}rB`0^fJry`IiI0`#7Ma%E-yxgDcj-<;Ta^+`Yya-zTAqz;zkw9NtAZO z2j0n5n#VfgykQXM^%z)qLpn^(<5@h;;M^tEF4HV@32`Pmbew8p9Z?R=a5XuTjbWZt zSn|R`9%|vGwy4_@QEbs1?#VTW@gXg^8PyU=3{2)VIEOVnhwg;iFozx52jCecOmy#3 z3?Ou`vk=@%6$T;#V<$1miHOTE;j1VhzG>#wMMZSb%&*M{VVwD)!PaD%aH5zDz_u8c zbG2*0Q43EjofF?iP+*7K7tu+=YqubJ4j)h@u0zBi9TSD|u>9(tqvzm_!2}zdhlBqlHzDNXk(Kpp)w4Mwhun>zAY-7?!=l!=Nc?rDh||zxAzYL z#SAMZaX@fAys&0I7HxsAcsuOkVktI8Qc;;ritDC=l2yvxjalL`T&-AB?=QgV!a92o zy9kARJkzG6Vk${bNYxs|`ii4pfgIW(`$pOns+%i0+ z3J)m0??9;HoY_!q>@m*w?gwR55I2VF3V>|hZ_&kGX7sOdlO}4zhztxfe6s=(NKB#% z5Q2Xu`mUokKvWT`IEHvnA2 z(F%0YN4VkY61SmhJbdM356{QrDP3YZ zV!Lx*s|rPoqop0&phkwPpnvZ&bfvejm4{LYU}D(H8ieX zv(`#9*`m3nwe6GZ)}Obb{rru|j#PTnr!MHc@Y7uvb@yC+$)%sU?6a3&@wv@ce*UU2 zeDUgQzI1Kxmg}}&|K%ILa^tqI-qd&V*S`LZ?YDe$$G5)yom+3a{f;}o`@Orq|AV`K zc+Zc1{F8fsdf(2U_22(<`M`q@J^aX{k3IgxFP?mA*VDiJ)icljdiQhBzwnzEUwZkK z-|pG_>hFI4hd=)5&wu&r-(GwD@Bet?pKt!_-*4?3*ni;Q+wc5`wj*k7(pCV@o?(0W F_W+%&>RSK+ diff --git a/src/smartcontract/ontidContract.ts b/src/smartcontract/ontidContract.ts index 5389c379..fa2c6548 100644 --- a/src/smartcontract/ontidContract.ts +++ b/src/smartcontract/ontidContract.ts @@ -11,7 +11,7 @@ import {ab2hexstring, str2hexstr} from '../utils' import {Transaction} from '../transaction/transaction' import {makeInvokeTransaction} from '../transaction/transactionBuilder' -import abiJson from '../smartcontract/data/IdContract.abi' +import abiJson from '../smartcontract/data/idContract.abi' const abiInfo = AbiInfo.parseJson(JSON.stringify(abiJson)) @@ -24,10 +24,6 @@ export function getPublicKeyStatus(ontid : string, pkId : string, url ?: string) }) } -export function buildGetPublicKeyStatusTx(ontid : string, pkId : string) { - -} - export function buildRegisterOntidTx(ontid: string, privateKey: string) { let publicKey = ab2hexstring(core.getPublicKey(privateKey, true)) if (ontid.substr(0, 3) == 'did') { @@ -159,4 +155,31 @@ export function buildChangeRecoveryTx(ontid : string, newrecovery : string, oldr f.setParamsValue(p1, p2, p3) let tx = makeInvokeTransaction(f, abiInfo.getHash(), privateKey) return tx +} + +export function buildGetPublicKeyStatusTx(ontid: string, pkId: string, privateKey?: string) { + let f = abiInfo.getFunction('GetPublicKeyStatus') + if (ontid.substr(0, 3) === 'did') { + ontid = str2hexstr(ontid) + } + let p1 = new Parameter(f.parameters[0].getName(), ParameterType.ByteArray, ontid) + let p2 = new Parameter(f.parameters[1].getName(), ParameterType.ByteArray, pkId) + + f.setParamsValue(p1, p2) + let tx = makeInvokeTransaction(f, abiInfo.getHash(), privateKey) + return tx +} + +export function buildGetPublicKeyIdTx(ontid: string, pk: string, privateKey ?: string) { + let f = abiInfo.getFunction('GetPublicKeyId') + if (ontid.substr(0, 3) === 'did') { + ontid = str2hexstr(ontid) + } + pk = '1202' + pk + let p1 = new Parameter(f.parameters[0].getName(), ParameterType.ByteArray, ontid) + let p2 = new Parameter(f.parameters[1].getName(), ParameterType.ByteArray, pk) + + f.setParamsValue(p1, p2) + let tx = makeInvokeTransaction(f, abiInfo.getHash(), privateKey) + return tx } \ No newline at end of file diff --git a/src/transaction/transactionBuilder.ts b/src/transaction/transactionBuilder.ts index 20f00a9a..09de5dd7 100644 --- a/src/transaction/transactionBuilder.ts +++ b/src/transaction/transactionBuilder.ts @@ -294,11 +294,11 @@ export function buildTxParam (tx : Transaction, is_pre_exec : boolean = false) { } //{"jsonrpc": "2.0", "method": "sendrawtransaction", "params": ["raw transactioin in hex"], "id": 0} -export function buildRpcParam(tx : any) { +export function buildRpcParam(tx : any, method ?: string) { let param = tx.serialize() let result = { "jsonrpc": "2.0", - "method": "sendrawtransaction", + "method": method || "sendrawtransaction", "params": [param], "id": 10 } diff --git a/test/core.test.ts b/test/core.test.ts index 1aa91d5a..f61994c3 100644 --- a/test/core.test.ts +++ b/test/core.test.ts @@ -21,7 +21,7 @@ import * as core from '../src/core' import * as utils from '../src/utils' import * as scrypt from '../src/scrypt' import { ab2hexstring } from '../src/utils'; -import { verifySignature } from '../src/core'; +import { verifySignature, getMerkleProof } from '../src/core'; describe('test core', ()=>{ @@ -32,29 +32,29 @@ describe('test core', ()=>{ privateKey = utils.ab2hexstring( core.generatePrivateKey() ) }) - // test('test getWIFFromPrivateKey', () => { - // wifKey = core.getWIFFromPrivateKey(privateKey) - // expect(wifKey).toBeDefined() - // }) + test('test getWIFFromPrivateKey', () => { + wifKey = core.getWIFFromPrivateKey(privateKey) + expect(wifKey).toBeDefined() + }) - // test('test getPrivateKeyFromWIF', () => { - // let key = core.getPrivateKeyFromWIF(wifKey) - // expect(key).toEqual(privateKey) - // }) + test('test getPrivateKeyFromWIF', () => { + let key = core.getPrivateKeyFromWIF(wifKey) + expect(key).toEqual(privateKey) + }) - // test('get public key', () => { - // let pkBuffer = core.getPublicKey(privateKey, true) - // let pk = utils.ab2hexstring(pkBuffer) - // console.log('get pk: ' + pk) - // expect(pk).toBeDefined() - // }) + test('get public key', () => { + let pkBuffer = core.getPublicKey(privateKey, true) + let pk = utils.ab2hexstring(pkBuffer) + console.log('get pk: ' + pk) + expect(pk).toBeDefined() + }) - // test('encrypt private key', () => { - // let privateKey = 'b02304dcb35bc9a055147f07b2a3291db4ac52f664ec38b436470c98db4200d9' - // let wif = core.getWIFFromPrivateKey(privateKey) - // let encrypt = scrypt.encrypt(wif, '123456') - // console.log('encrypt: '+ encrypt) - // }) + test('encrypt private key', () => { + let privateKey = 'b02304dcb35bc9a055147f07b2a3291db4ac52f664ec38b436470c98db4200d9' + let wif = core.getWIFFromPrivateKey(privateKey) + let encrypt = scrypt.encrypt(wif, '123456') + console.log('encrypt: '+ encrypt) + }) test('sign and verify', () => { let privateKey = core.generatePrivateKeyStr() diff --git a/test/deployCodeTx.test.ts b/test/deployCodeTx.test.ts index 41389ed1..6e0d7244 100644 --- a/test/deployCodeTx.test.ts +++ b/test/deployCodeTx.test.ts @@ -34,7 +34,7 @@ import json from '../src/smartcontract/data/idContract.abi' import { VmCode, VmType } from '../src/transaction/vmcode'; var fs = require('fs') -let avm = fs.readFileSync('/Users/mickeywang/Desktop/Workspace/ont-sdk-ts-local/src/smartcontract/data/idContract.avm') +let avm = fs.readFileSync('/Volumes/Workspace/ontio/ontology-ts-sdk/src/smartcontract/data/IdContract.avm') var avmCode = ab2hexstring(avm) var privateKey = '7c47df9664e7db85c1308c080f398400cb24283f5d922e76b478b5429e821b93' @@ -111,9 +111,12 @@ const getContract = () => { // let scriptHash = '8046031450d43928654f50dcd50646331bb49e1a' - let url = `${TEST_ONT_URL.REST_URL}api/v1/contract/${scriptHash}` + let url = `${TEST_ONT_URL.REST_URL}/api/v1/contract/${scriptHash}` + console.log('url : '+ url) axios.get(url).then((res)=>{ console.log(res.data) + }).catch(err => { + console.log(err) }) } diff --git a/test/merkle.test.ts b/test/merkle.test.ts new file mode 100644 index 00000000..0521e9b8 --- /dev/null +++ b/test/merkle.test.ts @@ -0,0 +1,35 @@ +import {verifyLeafHashInclusion} from '../src/merkle' + +test('test verify leaf in tree', () => { + const merkle = { + "Type": "MerkleProof", + "TransactionsRoot": "cc61e9484b603f6a29ccca0847977147cf5d1f36c749b74361de04f79554c7c4", + "BlockHeight": 0, + "CurBlockRoot": "815e20bda34d3a26450cc45726b34b143e9c5391642c340e25aceb76d28d2c88", + "CurBlockHeight": 4172, + "TargetHashes": [ + "8efa212233346badd344d0cb926f0b9d62b0eac077c9299c97c1cd4c5fec1450", + "3daa4b24d4762c8ab20cccc9fe1ad4ec2926545194d12cd0b13b58dcddf47afd", + "8cb9c7a58049f809485fbf2cc4bed21966195603748643383349a63c2b04bd07", + "1178ee5780a0d3c795d46f145033302664418b15aa016aee1e6a9bef958801fd", + "6f9a4bf07ba2f05b707b497a00d376d9158b8e7d852395ff4a5e82e23e611cc7", + "78f88b81b660f67e901fbe3e5c274be0e77e28712f334965d9f3af7ed6f4f31a", + "6d18e1c63641485ef692edbe69b516bdb5b46b7123e68e4f27dda161860b8748", + "49efca7304446c69bc7de684f76bac6d9b7ed77279166c4438da99f65a8460d2", + "d0ee3b8f10e0354ba6b6c2ef0d831e75bd4246b23a9c79451061eef749196167", + "80b2ca8c07b4a701cb5ae14a5c171bc8be9a6a88b6417953908cafd1ec99d83a", + "4e3d005c338414583a0154263b5a62a7be4e2d071430eb8ead7ca0cf543d32b9", + "b411acb7ac430dca5758b19bce9063cba0ec3d58096a48544f2745df043ef7f7", + "2e4b0a10b6478bdeea059eb19c1425ab226b0a41b35aad9bcf911e24b4da4906" + ] + } + + const leafHash = merkle.TransactionsRoot + const leafIndex = merkle.BlockHeight + const proof = merkle.TargetHashes + const rootHash = merkle.CurBlockRoot + const treeSize = merkle.CurBlockHeight + let result = verifyLeafHashInclusion(leafHash, leafIndex, proof, rootHash, treeSize) + console.log(result) + expect(result).toBeTruthy() +}) \ No newline at end of file diff --git a/test/tx.node.ts b/test/tx.node.ts index c04e87fe..9d9bed5d 100644 --- a/test/tx.node.ts +++ b/test/tx.node.ts @@ -18,7 +18,7 @@ import { makeInvokeTransaction , parseEventNotify, buildRpcParam, buildTxParam, buildRestfulParam, sendRawTxRestfulUrl } from '../src/transaction/transactionBuilder' -import {buildAddAttributeTx, buildGetDDOTx, buildRegisterOntidTx, buildAddPKTx, buildGetPublicKeysTx, buildRemovePkTx, buildAddRecoveryTx, buildChangeRecoveryTx} from '../src/smartcontract/ontidContract' +import {buildAddAttributeTx, buildGetDDOTx, buildRegisterOntidTx, buildAddPKTx, buildGetPublicKeysTx, buildRemovePkTx, buildAddRecoveryTx, buildChangeRecoveryTx, buildGetPublicKeyIdTx, buildGetPublicKeyStatusTx} from '../src/smartcontract/ontidContract' import {Transaction} from '../src/transaction/transaction' import InvokeCode from '../src/transaction/payload/invokeCode' import { Identity } from '../src/identity' @@ -34,6 +34,7 @@ import { TEST_ONT_URL} from '../src/consts' import { getHash } from '../src/core'; import TxSender from '../src/transaction/txSender' import axios from 'axios' +import { PublicKeyStatus } from '../src/crypto'; const codeHash = '80e7d2fc22c24c466f44c7688569cc6e6d6c6f92' @@ -54,6 +55,7 @@ var pk2: string var ontid: string var oldrecovery : string var newrecovery : string +var pkId : string var abiInfo: AbiInfo var identity: Identity @@ -65,6 +67,7 @@ abiInfo = AbiInfo.parseJson(JSON.stringify(json2)) privateKey = '7c47df9664e7db85c1308c080f398400cb24283f5d922e76b478b5429e821b93' publicKey = ab2hexstring(core.getPublicKey(privateKey, true)) +pkId = '' // let publicKey2 = ab2hexstring(core.getPublicKey(privateKey, true)) // var pkPoint = core.getPublicKeyPoint(privateKey) @@ -238,6 +241,31 @@ const testAddAttribute = () => { }) } +const testGetPublicKeyId = () => { + let tx = buildGetPublicKeyIdTx(ontid, publicKey) + let param = buildRestfulParam(tx) + console.log(param) + let url = sendRawTxRestfulUrl(TEST_ONT_URL.REST_URL, true) + console.log(url) + axios.post(url, param).then((res) => { + console.log(res.data) + }).catch(err => { + console.log(err) + }) +} + +const testGetPublicKeyStatus = () => { + let tx = buildGetPublicKeyStatusTx(ontid, '01') + let param = buildRestfulParam(tx) + let url = sendRawTxRestfulUrl(TEST_ONT_URL.REST_URL, true) + axios.post(url, param).then((res) => { + console.log(res.data) + let ps = PublicKeyStatus.deserialize(res.data.Result[0]) + console.log(ps) + }).catch(err => { + console.log(err) + }) +} const testAddPK = () => { let tx = buildAddPKTx(ontid, pk2, publicKey, privateKey) @@ -332,6 +360,8 @@ const testVerifyOntidClaim = () => { // testAddRecovery() -testChangeRecovery() +// testChangeRecovery() +// testGetPublicKeyId() +testGetPublicKeyStatus() \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 53c2dc77..4e4e18fe 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { /* Basic Options */ "target": "ES6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ - "module": "amd", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "module": "umd", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation: */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ From ebc18706c00e5a101fd2a094549920b365f3b97e Mon Sep 17 00:00:00 2001 From: MickeyWang Date: Mon, 9 Apr 2018 11:49:52 +0800 Subject: [PATCH 5/6] update tsconfig.json compile option --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 4e4e18fe..53c2dc77 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { /* Basic Options */ "target": "ES6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */ - "module": "umd", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + "module": "amd", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation: */ // "allowJs": true, /* Allow javascript files to be compiled. */ // "checkJs": true, /* Report errors in .js files. */ From 54613849c8b49426fb4255d3f503357aa95aecad Mon Sep 17 00:00:00 2001 From: MickeyWang Date: Wed, 11 Apr 2018 15:13:36 +0800 Subject: [PATCH 6/6] add restful,rpc,websocket api --- package.json | 23 +- src/consts.ts | 2 +- src/index.ts | 123 ++++------ src/network/rest/restClient.ts | 197 ++++++++++++++++ src/network/rest/urlConsts.ts | 34 +++ src/network/rpc/rpcClient.ts | 165 +++++++++++++ src/network/websocket/websocketClient.ts | 204 ++++++++++++++++ src/transaction/transactionBuilder.ts | 2 +- src/transaction/txSender.ts | 36 +-- test/deployCodeTx.test.ts | 2 +- test/restClient.test.ts | 147 ++++++++++++ test/rpcClient.test.ts | 107 +++++++++ test/transfer.test.ts | 44 ++-- test/tx.node.ts | 60 ++--- test/websocketClient.test.ts | 287 +++++++++++++++++++++++ 15 files changed, 1266 insertions(+), 167 deletions(-) create mode 100644 src/network/rest/restClient.ts create mode 100644 src/network/rest/urlConsts.ts create mode 100644 src/network/rpc/rpcClient.ts create mode 100644 src/network/websocket/websocketClient.ts create mode 100644 test/restClient.test.ts create mode 100644 test/rpcClient.test.ts create mode 100644 test/websocketClient.test.ts diff --git a/package.json b/package.json index 38ba66d5..be602af7 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,7 @@ "author": "ontologyNetwork", "license": "ISC", "devDependencies": { - "@types/node": "^8.5.2" - }, - "dependencies": { + "@types/node": "^8.5.2", "@types/axios": "^0.14.0", "@types/base-x": "^1.0.29", "@types/bignumber.js": "^5.0.0", @@ -33,6 +31,16 @@ "@types/crypto-js": "^3.1.38", "@types/ecurve": "^1.0.0", "@types/jest": "^22.1.2", + "jest": "^22.1.4", + "jest-cli": "^22.1.4", + "ts-jest": "^22.0.2", + "ts-loader": "^3.2.0", + "typescript": "^2.6.2", + "uglifyjs-webpack-plugin": "^1.2.2", + "clean-webpack-plugin": "^0.1.18", + "webpack": "^3.10.0" + }, + "dependencies": { "axios": "^0.17.1", "babel-core": "^6.26.0", "babel-loader": "^7.1.3", @@ -43,20 +51,13 @@ "bignumber.js": "^6.0.0", "bs58": "^4.0.1", "bs58check": "^2.1.1", - "clean-webpack-plugin": "^0.1.18", "crypto-js": "^3.1.9-1", "ecdsa": "^0.7.0", "ecurve": "^1.0.6", "elliptic": "^6.4.0", - "jest": "^22.1.4", - "jest-cli": "^22.1.4", + "html5-websocket": "^2.0.2", "js-scrypt": "^0.2.0", "secure-random": "^1.1.1", - "ts-jest": "^22.0.2", - "ts-loader": "^3.2.0", - "typescript": "^2.6.2", - "uglifyjs-webpack-plugin": "^1.2.2", - "webpack": "^3.10.0", "wif": "^2.0.6", "ws": "^4.1.0" } diff --git a/src/consts.ts b/src/consts.ts index c5ef1b70..2f8e12af 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -51,7 +51,7 @@ export const ALGORITHM_TYPE = { } export const TEST_NODE = '139.219.111.50' -// export const TEST_NODE = '192.168.50.10' +// export const TEST_NODE = '192.168.3.141' // export const TEST_NODE = '54.222.182.88' export const MAIN_NODE = '54.222.182.88' diff --git a/src/index.ts b/src/index.ts index b5e32589..b75f2f76 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,6 +25,11 @@ import * as TransactionBuilder from './transaction/transactionBuilder' import {Parameter, ParameterType} from './smartcontract/abi/parameter' import AbiFunction from './smartcontract/abi/abiFunction' import AbiInfo from './smartcontract/abi/abiInfo' +import * as Token from './smartcontract/token' +import * as OntidContract from './smartcontract/ontidContract' +import RestClient from './network/rest/restClient' +import RpcClient from './network/rpc/rpcClient' +import WebSocketClientApi from './network/websocket/websocketClient' import * as scrypt from './scrypt' import * as core from './core' @@ -48,23 +53,33 @@ class ONT { CONST : any Wallet : any SDK : any + Token : any + OntidContract : any + RestClient : any + RpcClient : any + WebSocketClientApi : any constructor() { this.Account = Account, - this.Identity = Identity, - this.Claim = Claim, - this.Transaction = Transaction, - this.TransactionBuilder = TransactionBuilder, - this.Parameter = Parameter + this.Identity = Identity, + this.Claim = Claim, + this.Transaction = Transaction, + this.TransactionBuilder = TransactionBuilder, + this.Parameter = Parameter this.ParameterType = ParameterType this.AbiFunction = AbiFunction this.AbiInfo = AbiInfo this.core = core, - this.utils = utils, - this.scrypt = scrypt, - this.CONST = CONST, - this.Wallet = Wallet, - this.SDK = SDK + this.utils = utils, + this.scrypt = scrypt, + this.CONST = CONST, + this.Wallet = Wallet, + this.SDK = SDK, + this.Token = Token, + this.OntidContract = OntidContract + this.RestClient = RestClient + this.RpcClient = RpcClient + this.WebSocketClientApi = WebSocketClientApi } @@ -87,69 +102,25 @@ class ONT { export default ONT export { - Account, - Identity, - Claim, - Transaction, - Parameter, - ParameterType, - AbiFunction, - AbiInfo, - TransactionBuilder, - core, - utils, - scrypt, - CONST, - Wallet, - SDK - } - -// var a = new Claim('{"Name":"zhangsan","Gender":"male","Age":25}',"8de516a7cddf22e328a61faf80f698ad7a410953d86fe06d031e08de7161a051") -// console.log(a.unsignedData) -// console.log(a.signedData) - -// var a = new Transaction(); -// var txData = a.makeInvokeCodeTransaction( "eacecb46f117f55c80147a9d391c7c65af10bd36", "ee6469643a6f6e743a41526a42735a32546e6f336345384e3132706631454b6a67464c37646a42475734", "037a1d32ff0f96f4a353097c2bed2fb4bff386467bddd9c907dcf3963aeb0b66e8" ); -// console.log(txData); - -// var sign = Core.signatureData( txData, "0eb7f605520dd843f930177c247e276bf8d65f5c35be1bcdac0078a25cf8fba3" ); -// console.log(sign); - -// var data = Core.AddContract( txData, sign, "037a1d32ff0f96f4a353097c2bed2fb4bff386467bddd9c907dcf3963aeb0b66e8" ); -// console.log(data); - -// var b = scrypt.encrypt( "KwYgW8gcxj1JWJXhPSu4Fqwzfhp5Yfi42mdYmMa4XqK7NJxXUSK7", "Satoshi" ); -// console.log( b ); - -// scrypt.decrypt( "6PYN6mjwYfjPUuYT3Exajvx25UddFVLpCw4bMsmtLdnKwZ9t1Mi3CfKe8S", "Satoshi" ); - -// var privateKey = utils.ab2hexstring( core.generatePrivateKey() ); -// console.log("privateKey:", privateKey); -// var a = new Account(); -// var b = a.createSecp256r1( privateKey, "123456", "test" ); -// console.log(b); -// a.decrypt( b, "123456" ); - - -// var privateKey = utils.ab2hexstring( core.generatePrivateKey() ); -// console.log("privateKey:", privateKey); -// var a = new Identity(); -// var b = a.createSecp256r1( privateKey, "123456", "test" ); -// console.log(b); -// console.log("ontid:",a.identity.ontid); -// a.decrypt( b, "123456" ); - -//var a = new Wallet(); -// var b = a.create( "myName", "123456" ); -// console.log(b); -//var b = '{"name":"myName","version":"1.0","scrypt":{"n":16384,"r":8,"p":8},"identities":[{"ontid":"did:ont:TRzzdEQDcyZLtrrgjA7iqxDM8ETv5VnHtZ","label":"Default Identity","isDefault":true,"lock":false,"controls":[{"algorithm":"ECDSA","parameters":{"curve":"secp256r1"},"id":"1","key":"6PYWBhHThQpuXzVKYD33RVNtKwjkY7oGYkbg1s1xZvnzdSQQEnW5wGpZQq"}],"extra":null}],"accounts":[{"address":"TFXZXPFCxvvunYxrUtxkNsKo9X9fHxATiD","label":"Default Account","isDefault":true,"lock":false,"algorithm":"ECDSA","parameters":{"curve":"secp256r1"},"key":"6PYMFiDpGEQnkmxGniLR4fhMkgFQmMv2RDGGhvtP1P5jZG2G3udvrb2zsX","contract":{"script":"210270cfbe2c5e3509f6ce639e6643409f71d537db8c3ced407c6774ea8b9d493868ac","parameters":[],"deployed":false},"extra":null}],"extra":null}'; -//var b = '{"accounts":[{"address":"TEP9pXcePEALEvTqZq4YFikzBUWVhzkXYk","algorithm":"","contract":{"deployed":false,"parameters":["Signature"],"script":"2102738571174ca5f8eba804075d19b33b987641ba8a30061d94f87dc369d018cd19ac"},"isDefault":false,"key":"6PYVat55KiX14KxjAxPtxVCyiRAuL6HT9HF1cgmacrEsfWn3BQFrAqhMK1","label":"","lock":false,"parameter":""}],"identities":[{"controls":[{"algorithm":"ECDSA","id":"","key":"6PYWozsqytsiUoTfS6TVjn2hcYCdhwLfjiDBpC6pUwbGpBMFKjcvkrbX7S","parameters":{"curve":"secp256r1"}}],"isDefault":false,"label":"","lock":false,"ontid":"did:ont:TXfsPC6H2waHSKC7C6QnYZNiKgQibJeskU"}],"name":"ont","scrypt":{"n":16384,"p":8,"r":8},"version":"v1.0.0"}'; -//a.decrypt( b, "123456" ); - - -// for ( var i=0; i<100; i++ ){ -// var privateKey = utils.ab2hexstring( core.generatePrivateKey() ); -// var a = new Account(); -// var b = a.createSecp256r1( privateKey, "123456", "test" ); -// console.log(a.jsonData.address); -// } \ No newline at end of file + Account, + Identity, + Claim, + Transaction, + Parameter, + ParameterType, + AbiFunction, + AbiInfo, + TransactionBuilder, + core, + utils, + scrypt, + CONST, + Wallet, + SDK, + Token, + OntidContract, + RestClient, + RpcClient, + Web +} + \ No newline at end of file diff --git a/src/network/rest/restClient.ts b/src/network/rest/restClient.ts new file mode 100644 index 00000000..f133313a --- /dev/null +++ b/src/network/rest/restClient.ts @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + +import {TEST_ONT_URL} from '../../consts' +import axios from 'axios' +import { url } from 'inspector'; +import UrlConsts from './urlConsts' + +export default class RestClient { + url : string + version : string = 'v1.0.0' + action : string = 'sendrawtransaction' + + constructor(url ?: string) { + this.url = url || TEST_ONT_URL.REST_URL + } + + concatParams(params : Map) { + let result = '' + if(params.size === 0) { + return '' + } + for ( let key of params.keys() ) { + let value = params.get(key) + if(value) { + value = encodeURIComponent(value) + } + result += `&${key}=${value}` + } + return '?' + result.substr(1) + + } + + getUrl() { + return this.url + } + + sendRawTransaction(hexData : string, preExec : boolean = false, userId ?: string) { + let param = new Map() + if(userId) { + param.set('userid', userId) + } + param.set('preExec', '1') + let url = this.url + UrlConsts.Url_send_transaction + url += this.concatParams(param) + let body = { + "Action" : this.action, + "Version" : this.version, + "Data" : hexData + } + return axios.post(url,body).then(res => { + return res.data + }) + } + + getRawTransaction(txHash : string) { + let param = new Map() + param.set('raw', '1') + let url = this.url + UrlConsts.Url_get_transaction + txHash + url += this.concatParams(param) + return axios.get(url).then(res => { + return res.data + }) + } + + getRawTransactionJson(txHash: string) { + let url = this.url + UrlConsts.Url_get_transaction + txHash + return axios.get(url).then(res => { + return res.data + }) + } + + getGenerateBlockTime() { + let url = this.url + UrlConsts.Url_get_generate_block_time + return axios.get(url).then(res => { + return res.data + }) + } + + getNodeCount() { + let url = this.url + UrlConsts.Url_get_node_count + return axios.get(url).then(res => { + return res.data + }) + } + + getBlockHeight() { + let url = this.url + UrlConsts.Url_get_block_height + return axios.get(url).then(res => { + return res.data + }) + } + + //get block by block height or block hash + getBlock(value : number | string) { + let params = new Map() + params.set('raw', "1") + let url = '' + if(typeof value === 'number') { + url = this.url + UrlConsts.Url_get_block_by_height + value + } else if(typeof value === 'string') { + url = this.url + UrlConsts.Url_get_block_by_hash + value + } + url += this.concatParams(params) + return axios.get(url).then(res => { + return res.data + }) + } + + getContract(codeHash : string) { + let params = new Map() + params.set('raw', '1') + let url = this.url + UrlConsts.Url_get_contract_state + codeHash + url += this.concatParams(params) + console.log('url: '+url) + return axios.get(url).then(res => { + return res.data + }) + } + + getContractJson(codeHash : string) { + let url = this.url + UrlConsts.Url_get_contract_state + codeHash + return axios.get(url).then(res => { + return res.data + }) + } + + getSmartCodeEvent(value : string | number) { + let url = '' + if(typeof value === 'string') { + url = this.url + UrlConsts.Url_get_smartcodeevent_by_txhash + value + } else if(typeof value === 'number') { + url = this.url + UrlConsts.Url_get_smartcodeevent_txs_by_height + value + } + return axios.get(url).then(res => { + return res.data + }) + } + + getBlockHeightByTxHash(hash : string) { + let url = this.url + UrlConsts.Url_get_block_height_by_txhash + hash + return axios.get(url).then(res => { + return res.data + }) + } + + getStorage(codeHash : string, key : string) { + let url = this.url + UrlConsts.Url_get_storage + codeHash + '/' + key + return axios.get(url).then(res => { + return res.data + }) + } + + getMerkleProof(hash : string) { + let url = this.url + UrlConsts.Url_get_merkleproof + hash + console.log('url: '+url) + return axios.get(url).then(res => { + return res.data + }) + } + + getBalance(address : string) { + let url = this.url + UrlConsts.Url_get_account_balance + address + return axios.get(url).then(res => { + return res.data + }) + } + + + getBlockJson(value : number | string) { + let url = '' + if(typeof value === 'number') { + url = this.url + UrlConsts.Url_get_block_by_height + value + } else if (typeof value === 'string') { + url = this.url + UrlConsts.Url_get_block_by_hash + value + } + return axios.get(url).then(res => { + return res.data + }) + } + +} \ No newline at end of file diff --git a/src/network/rest/urlConsts.ts b/src/network/rest/urlConsts.ts new file mode 100644 index 00000000..f3b6694b --- /dev/null +++ b/src/network/rest/urlConsts.ts @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + +export default { + Url_send_transaction : "/api/v1/transaction", + Url_get_transaction : "/api/v1/transaction/", + Url_get_generate_block_time : "/api/v1/node/generateblocktime", + Url_get_node_count : "/api/v1/node/connectioncount", + Url_get_block_height : "/api/v1/block/height", + Url_get_block_by_height : "/api/v1/block/details/height/", + Url_get_block_by_hash : "/api/v1/block/details/hash/", + Url_get_account_balance : "/api/v1/balance/", + Url_get_contract_state : "/api/v1/contract/", + Url_get_smartcodeevent_txs_by_height : "/api/v1/smartcode/event/transactions/", + Url_get_smartcodeevent_by_txhash : "/api/v1/smartcode/event/txhash/", + Url_get_block_height_by_txhash : "/api/v1/block/height/txhash/", + Url_get_storage : "/api/v1/storage/", + Url_get_merkleproof : "/api/v1/merkleproof/" +} \ No newline at end of file diff --git a/src/network/rpc/rpcClient.ts b/src/network/rpc/rpcClient.ts new file mode 100644 index 00000000..56ecd8d5 --- /dev/null +++ b/src/network/rpc/rpcClient.ts @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + + +import {TEST_ONT_URL} from '../../consts' +import axios from 'axios' + +export default class RpcClient { + url : string + + constructor( url ?: string ) { + this.url = url || TEST_ONT_URL.RPC_URL + } + + getUrl() { + return this.url + } + + makeRequest(method : string, ...params : any[]) { + let request = ( {}) + request['jsonrpc'] = '2.0' + request['method'] = method + request['params'] = params + request['id'] = 1 + return request + } + + getBalance(address : string) { + let req = this.makeRequest(address) + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + sendRawTransaction(data : string, preExec : boolean = false) { + let req + if(preExec) { + req = this.makeRequest('sendrawtransaction', data, 1) + } else { + req = this.makeRequest('sendrawtransaction', data) + } + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + getRawTransaction(txHash : string) { + let req = this.makeRequest('getrawtransaction', txHash) + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + getRawTransactionJson(txHash : string) { + let req = this.makeRequest('getrawtransaction', txHash, 1) + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + getGenerateBlockTime() { + let req = this.makeRequest('getgenerateblocktime') + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + getNodeCount() { + let req = this.makeRequest('getconnectioncount') + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + getBlockHeight() { + let req = this.makeRequest('getblockcount') + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + getBlockCount() { + let req = this.makeRequest('getblockcount') + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + //get by block height or block hash + getBlockJson(value : string | number) { + let req = this.makeRequest('getblock', value, 1) + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + getContract(hash : string) { + let req = this.makeRequest('getcontractstate', hash) + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + getContractJson(codeHash : string) { + let req = this.makeRequest('getcontractstate', codeHash, 1) + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + //get by block height or block hash + getBlock(value : string | number) { + let req = this.makeRequest('getblock', value) + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + getSmartCodeEvent(value: string | number) { + let req = this.makeRequest('getsmartcodeevent', value) + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + getBlockHeightByTxHash(txHash : string) { + let req = this.makeRequest('getblockheightbytxhash', txHash) + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + getStorage(codeHash : string, key : string) { + let req = this.makeRequest('getstorage', codeHash, key) + console.log(req) + return axios.post(this.url, req).then(res => { + return res.data + }) + } + + getMerkleProof(hash : string) { + let req = this.makeRequest('getmerkleproof', hash) + console.log(this.url) + console.log(req) + return axios.post(this.url, req).then(res => { + return res.data + }) + } + +} \ No newline at end of file diff --git a/src/network/websocket/websocketClient.ts b/src/network/websocket/websocketClient.ts new file mode 100644 index 00000000..cd778d03 --- /dev/null +++ b/src/network/websocket/websocketClient.ts @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2018 The ontology Authors + * This file is part of The ontology library. + * + * The ontology is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The ontology is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with The ontology. If not, see . + */ + +const WebSocket = require('html5-websocket') +import {TEST_ONT_URL} from '../../consts' + +export default class WebsocketClientApi { + + sendHeartBeat() { + let param = { + "Action" : "heartbeat", + "Version" : "V1.0.0" + } + return JSON.stringify(param) + } + + sendRawTransaction(hexData : string, preExec : boolean = false) { + let param = { + "Action" : "sendrawtransaction", + "Version" : "1.0.0", + "Data" : hexData + } + if(preExec) { + param = Object.assign(param, { "PreExec" : "1" }) + } + console.log('hexData: '+hexData) + return JSON.stringify(param) + } + + getRawTransaction(txHash : string){ + let param = { + "Action": "gettransaction", + "Version": "1.0.0", + "Hash": txHash, + "Raw" : "1" + } + return JSON.stringify(param) + } + + getRawTransactionJson(txHash : string) { + let param = { + "Action": "gettransaction", + "Version": "1.0.0", + "Hash": txHash, + "Raw": "0" + } + return JSON.stringify(param) + } + + getGenerateBlockTime() { + let param = { + "Action": "getgenerateblocktime", + "Version": "1.0.0" + } + return JSON.stringify(param) + } + + getNodeCount() { + let param = { + "Action": "getconnectioncount", + "Version": "1.0.0" + } + return JSON.stringify(param) + } + + getBlockHeight() { + let param = { + "Action": "getblockheight", + "Version": "1.0.0" + } + return JSON.stringify(param) + } + + getBlock(value : number | string) { + let param = {} + if(typeof value === 'number') { + param = { + "Action": "getblockbyheight", + "Version": "1.0.0", + "Height": value, + "Raw": "1" + } + } else if(typeof value === 'string') { + param = { + "Action": "getblockbyhash", + "Version": "1.0.0", + "Hash": value, + "Raw": "1" + } + } + return JSON.stringify(param) + } + + getBlockJson(value : number | string) { + let param = {} + if (typeof value === 'number') { + param = { + "Action": "getblockbyheight", + "Version": "1.0.0", + "Height": value + } + } else if (typeof value === 'string') { + param = { + "Action": "getblockbyhash", + "Version": "1.0.0", + "Hash": value + } + } + return JSON.stringify(param) + } + + getBalance(address : string) { + let param = { + "Action": "getbalance", + "Version": "1.0.0", + "Addr": address + } + return JSON.stringify(param) + } + + getContract(hash : string) { + let param = { + "Action": "getcontract", + "Version": "1.0.0", + "Hash": hash, + "Raw": "1" + } + return JSON.stringify(param) + } + + getContractJson(hash : string) { + let param = { + "Action": "getcontract", + "Version": "1.0.0", + "Hash": hash, + "Raw": "0" + } + return JSON.stringify(param) + } + + getSmartCodeEvent(value : number | string) { + let param = {} + if (typeof value === 'number') { + param = { + "Action": "getsmartcodeeventbyheight", + "Version": "1.0.0", + "Height": value + } + } else if (typeof value === 'string') { + param = { + "Action": "getsmartcodeeventbyhash", + "Version": "1.0.0", + "Hash": value + } + } + return JSON.stringify(param) + } + + getBlockHeightByTxHash(hash: string) { + let param = { + "Action": "getblockheightbytxhash", + "Version": "1.0.0", + "Hash": hash, + } + return JSON.stringify(param) + } + + getStorage(codeHash : string, key : string) { + let param = { + "Action": "getstorage", + "Version": "1.0.0", + "Hash": codeHash, + "Key" : key + } + return JSON.stringify(param) + } + + getMerkleProof(hash : string) { + let param = { + "Action": "getmerkleproof", + "Version": "1.0.0", + "Hash": hash + } + return JSON.stringify(param) + } + + + +} \ No newline at end of file diff --git a/src/transaction/transactionBuilder.ts b/src/transaction/transactionBuilder.ts index 09de5dd7..e401f18e 100644 --- a/src/transaction/transactionBuilder.ts +++ b/src/transaction/transactionBuilder.ts @@ -288,7 +288,7 @@ export function makeDeployTransaction ( deployCode : DeployCode, privateKey : st } export function buildTxParam (tx : Transaction, is_pre_exec : boolean = false) { - let op = is_pre_exec ? { Op:'PreExec'} : {} + let op = is_pre_exec ? { 'PreExec':"1"} : {} let serialized = tx.serialize() return JSON.stringify(Object.assign({}, Default_params, { Data: serialized }, op)) } diff --git a/src/transaction/txSender.ts b/src/transaction/txSender.ts index c170fcb0..c5049977 100644 --- a/src/transaction/txSender.ts +++ b/src/transaction/txSender.ts @@ -17,29 +17,21 @@ */ import {ONT_NETWORK, MAIN_ONT_URL, TEST_ONT_URL} from '../consts' -import {Transaction} from './transaction' -import axios from 'axios' -import { ERROR_CODE } from '../error'; -var WebSocket : any -if(typeof window != 'undefined' && (window as any).WebSocket){ - WebSocket = (window as any).WebSocket -} else { - WebSocket = require('ws') -} +const WebSocket = require('html5-websocket') export default class TxSender { SOCKET_URL : string - constructor (socketUrl : string) { - this.SOCKET_URL = socketUrl + constructor (socketUrl ?: string) { + this.SOCKET_URL = socketUrl || TEST_ONT_URL.SOCKET_URL } - sendTxWithSocket(param : string, callback : (res:any, socket:any) => any) { + sendTxWithSocket(param : string, callback : (err : any, res:any, socket:any) => any) { if(!param) return; const socket = new WebSocket(this.SOCKET_URL) socket.onopen = () => { - console.log('connected') + // console.log('connected') socket.send(param) } socket.onmessage = (event : any) => { @@ -52,23 +44,13 @@ export default class TxSender { //pass socket to let caller decide when to close the it. if(callback) { - callback(res, socket) + callback(null, res, socket) } } - socket.onerror = (event : any) => { + socket.onerror = (err : any) => { //no server or server is stopped - console.log(event) - let res - if (typeof event.data === 'string') { - res = JSON.parse(event.data) - } else { - res = event.data - } - res.Error = ERROR_CODE.NETWORK_ERROR - //pass socket to let caller decide when to close the it. - if (callback) { - callback(res, socket) - } + console.log(err) + callback(err, null, null) socket.close() } } diff --git a/test/deployCodeTx.test.ts b/test/deployCodeTx.test.ts index 6e0d7244..684c04eb 100644 --- a/test/deployCodeTx.test.ts +++ b/test/deployCodeTx.test.ts @@ -86,7 +86,7 @@ const testDeployCodeTx = () => { }) // var param = buildTxParam(tx) - // var callback = function(res, socket) { + // var callback = function(err, res, socket) { // console.log('res: '+ JSON.stringify(res)) // } // txSender.sendTxWithSocket(param, callback) diff --git a/test/restClient.test.ts b/test/restClient.test.ts new file mode 100644 index 00000000..1f376eac --- /dev/null +++ b/test/restClient.test.ts @@ -0,0 +1,147 @@ +import RestClient from '../src/network/rest/restClient' +import { buildGetDDOTx } from '../src/smartcontract/ontidContract'; + +describe('test restClient', () => { + var rest = new RestClient() + + test('test sendRawTransaction', async () => { + let ontid = 'did:ont:TC7ZkUjbiN6yKaAT3hw5VzqLq18Xu8cZJW' + let tx = buildGetDDOTx(ontid) + let res = await rest.sendRawTransaction(tx.serialize(), true) + console.log(res) + expect(res.Result).toBeDefined() + }) + + + + test('test getRawTransaction', async () => { + let txhash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + let res = await rest.getRawTransaction(txhash) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test getRawTransactionJson', async () => { + let txhash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + let res = await rest.getRawTransactionJson(txhash) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test GenerateBlockTime', async () => { + let res = await rest.getGenerateBlockTime() + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test getNodeCount', async () => { + let res = await rest.getNodeCount() + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test getBlockHeight', () => { + return rest.getBlockHeight().then(data => { + console.log(data) + expect(data).toBeDefined() + }) + }) + + test('test getBlock by hash', async () => { + let hash = '54dbc90e2476c7444774814e1ba65c606586fff4cac742d6de7d1e5899993e5c' + let res = await rest.getBlock(hash) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test getBlock by height', async () => { + let height = 1000 + let res = await rest.getBlock(height) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test getBlockJson by hash', async () => { + let hash = '54dbc90e2476c7444774814e1ba65c606586fff4cac742d6de7d1e5899993e5c' + let res = await rest.getBlockJson(hash) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test getBlockJson by height', async () => { + let height = 1000 + let res = await rest.getBlockJson(height) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test getBalance', async () => { + let address = 'TA7T3p6ikRG5s2pAaehUH2XvRCCzvsFmwE' + let res = await rest.getBalance(address) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test getContract', async () => { + let hash = '8055b362904715fd84536e754868f4c8d27ca3f6' + let res = await rest.getContract(hash) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test getContractJson', async () => { + let hash = '8055b362904715fd84536e754868f4c8d27ca3f6' + let res = await rest.getContractJson(hash) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test smartCodeEvent by hash', async () => { + let hash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + let res = await rest.getSmartCodeEvent(hash) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test smartCodeEvent by height', async () => { + let height = 169909 + let res = await rest.getSmartCodeEvent(height) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + + test('test getBlockHeightByTxHash', async () => { + let hash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + let res = await rest.getBlockHeightByTxHash(hash) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + test('test getStorage', async () => { + let codeHash = '8055b362904715fd84536e754868f4c8d27ca3f6' + let key = '2a6469643a6f6e743a5443375a6b556a62694e36794b61415433687735567a714c713138587538635a4a5702' + let res = await rest.getStorage(codeHash, key) + console.log(res) + expect(res.Result).toBeTruthy() + }) + + // test('test with error', async () => { + // let rest = new RestClient('http://192.168.1.1:20334') + // try{ + // await rest.getBlockHeight() + // }catch(err) { + // console.log('err'+JSON.stringify(err)) + // expect(err).toBeDefined() + // } + // }) + + // wait for update this api in testnet + // test('test getMerkleProof', async () => { + // let hash = '58263ab9f6c5fd80549f1868382ae86de67c9c943e727a13cb687e9d3139b6c0' + // let res = await rest.getMerkleProof(hash) + // console.log(res) + // expect(res).toBeDefined() + // } +}) + diff --git a/test/rpcClient.test.ts b/test/rpcClient.test.ts new file mode 100644 index 00000000..4e31e2de --- /dev/null +++ b/test/rpcClient.test.ts @@ -0,0 +1,107 @@ +import RpcClient from '../src/network/rpc/rpcClient' +import { buildGetDDOTx } from '../src/smartcontract/ontidContract'; + +describe('test rpc client', () => { + var rpcClient = new RpcClient() + test('test getBlockHeight', async () => { + let hash = '58263ab9f6c5fd80549f1868382ae86de67c9c943e727a13cb687e9d3139b6c0' + let res = await rpcClient.getBlockHeight() + console.log(res) + expect(res.desc).toEqual('SUCCESS') + }) + + test('test sendRawTransaction', async () => { + let ontid = 'did:ont:TC7ZkUjbiN6yKaAT3hw5VzqLq18Xu8cZJW' + let tx = buildGetDDOTx(ontid) + let res = await rpcClient.sendRawTransaction(tx.serialize(), true) + console.log(res) + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getRawTransaction', async () => { + let txHash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + let res = await rpcClient.getRawTransaction(txHash) + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getGenerateBlockTime', async () => { + let res = await rpcClient.getGenerateBlockTime() + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getNodeCount', async () => { + let res = await rpcClient.getNodeCount() + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getBlockJson', async () => { + let blockHash = '54dbc90e2476c7444774814e1ba65c606586fff4cac742d6de7d1e5899993e5c' + let res = await rpcClient.getBlockJson(blockHash) + console.log(res) + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getContract', async () => { + let codeHash = '8055b362904715fd84536e754868f4c8d27ca3f6' + let res = await rpcClient.getContract(codeHash) + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getContractJson', async () => { + let codeHash = '8055b362904715fd84536e754868f4c8d27ca3f6' + let res = await rpcClient.getContractJson(codeHash) + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getBlock by hash', async () => { + let blockHash = '54dbc90e2476c7444774814e1ba65c606586fff4cac742d6de7d1e5899993e5c' + let res = await rpcClient.getBlock(blockHash) + console.log(res) + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getBlock by height', async () => { + let height = 1000 + let res = await rpcClient.getBlock(height) + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getBlockCount', async () => { + let res = await rpcClient.getBlockCount() + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getSmartCodeEvent by height', async () => { + let height = 170803 + let res = await rpcClient.getSmartCodeEvent(height) + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getSmartCodeEvent by hash', async () => { + let hash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + let res = await rpcClient.getSmartCodeEvent(hash) + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getBlockHeightByHash', async () => { + let hash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + let res = await rpcClient.getBlockHeightByTxHash(hash) + expect(res.desc).toEqual('SUCCESS') + }) + + test('test getStorage', async () => { + let codeHash = '8055b362904715fd84536e754868f4c8d27ca3f6' + let key = '2a6469643a6f6e743a5443375a6b556a62694e36794b61415433687735567a714c713138587538635a4a5702' + let res = await rpcClient.getStorage(codeHash, key) + console.log('getStorage') + console.log(res) + expect(res.result).toBeDefined() + }) + + //wait for update this api in testnet + /* test('test getMerkleProof', async () => { + let hash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + let res = await rpcClient.getMerkleProof(hash) + expect(res.desc).toEqual('SUCCESS') + }) */ +}) \ No newline at end of file diff --git a/test/transfer.test.ts b/test/transfer.test.ts index 241d7f3e..20665d64 100644 --- a/test/transfer.test.ts +++ b/test/transfer.test.ts @@ -52,37 +52,39 @@ const testTransferTx = () => { var value = '300' - var tx = makeTransferTransaction('ONT', accountFrom.hexAddress, accountToHexAddress, value, accountFrom.privateKey) + + var tx = makeTransferTransaction('ONT', accountFrom.hexAddress, addressToU160('TA5uka5Y2PtuWvVRAdpEhddxCtPTpff847'), value, + accountFrom.privateKey) // var tx = makeTransferTransaction('ONT', accHexAddress, accountToHexAddress, value, accPrivateKey) - // var param = buildRestfulParam(tx) + var param = buildRestfulParam(tx) // // console.log('param : ' + JSON.stringify(param)) - // let request = `http://${TEST_NODE}:${HTTP_REST_PORT}${REST_API.sendRawTx}` + let request = `http://${TEST_NODE}:${HTTP_REST_PORT}${REST_API.sendRawTx}` - // axios.post(request, param).then(res => { - // console.log('transfer response: ' + JSON.stringify(res.data)) - // setTimeout( function(){ - // // testGetBalance(accountFrom.address, 'transfer 1 from') - // // testGetBalance(accAddress, 'transfer 1 to') + axios.post(request, param).then(res => { + console.log('transfer response: ' + JSON.stringify(res.data)) + setTimeout( function(){ + // testGetBalance(accountFrom.address, 'transfer 1 from') + // testGetBalance(accAddress, 'transfer 1 to') - // testGetBalance(accAddress, 'transfer 1 from') - // testGetBalance(accountToAddress, 'transfer 1 to') - // }, 8000) - // }).catch(err => { - // console.log(err) - // }) + testGetBalance(accountFrom.address, 'transfer 1 from') + testGetBalance('TA5uka5Y2PtuWvVRAdpEhddxCtPTpff847', 'transfer 1 to') + }, 8000) + }).catch(err => { + console.log(err) + }) - let param = buildTxParam(tx) - var callback = function(res, socket) { - console.log('res : '+JSON.stringify(res)) - } - txSender.sendTxWithSocket(param, callback) + // let param = buildTxParam(tx) + // var callback = function(err, res, socket) { + // console.log('res : '+JSON.stringify(res)) + // } + // txSender.sendTxWithSocket(param, callback) } const testGetBalance = (address, addressName) => { - let request = `https://${TEST_NODE}:${HTTP_REST_PORT}${REST_API.getBalance}/${address}` + let request = `http://${TEST_NODE}:${HTTP_REST_PORT}${REST_API.getBalance}/${address}` axios.get(request).then((res) => { let result = res.data.Result // console.log(result) @@ -99,7 +101,7 @@ testTransferTx() //需要 交易前加上预执行 rpc调用 -// testGetBalance('TA59XsiHbsztPg2ZTLsCknEvsDBGQMUm2T','acc address') +// testGetBalance('TA5uka5Y2PtuWvVRAdpEhddxCtPTpff847','acc address') // var state = new State() // state.from = ab2hexstring(core.generateRandomArray(20)) diff --git a/test/tx.node.ts b/test/tx.node.ts index 9d9bed5d..c7edc5db 100644 --- a/test/tx.node.ts +++ b/test/tx.node.ts @@ -65,7 +65,7 @@ abiInfo = AbiInfo.parseJson(JSON.stringify(json2)) // console.log('privatekey: ' + privateKey) // console.log('publick key: ' + publicKey) -privateKey = '7c47df9664e7db85c1308c080f398400cb24283f5d922e76b478b5429e821b93' +privateKey = '7c47df9664e7db85c1308c080f398400cb24283f5d922e76b478b5429e821b95' publicKey = ab2hexstring(core.getPublicKey(privateKey, true)) pkId = '' // let publicKey2 = ab2hexstring(core.getPublicKey(privateKey, true)) @@ -78,7 +78,7 @@ pkId = '' // privateKey = 'cd19cfe79112f1339749adcb3491595753ea54687e78925cb5e01a6451244406' // ontid = '6469643a6f6e743a626f626162636465636465666768c' -ontid = 'did:ont:TC7ZkUjbiN6yKaAT3hw5VzqLq18Xu8cZJA' +ontid = 'did:ont:TC7ZkUjbiN6yKaAT3hw5VzqLq18Xu8cZJW' pk2 = '035096277bd28ee25aad489a83ca91cfda1f59f2668f95869e3f7de0af0f07fc5c' // recovery = ab2hexstring(core.generateRandomArray(20)) @@ -145,11 +145,12 @@ const callback = function (res, socket) { const testDDOTx = () => { let tx = buildGetDDOTx(ontid) - // let param = buildTxParam(tx, false) + // let param = buildTxParam(tx, true) // console.log('param: '+param) // txSender.sendTxWithSocket(param, callback) + let param = buildRestfulParam(tx) console.log('param: '+JSON.stringify(param)) let url = sendRawTxRestfulUrl(TEST_ONT_URL.REST_URL, true) @@ -185,39 +186,40 @@ const testRegisterOntid = () => { let serialized = tx.serialize() console.log('serialized: '+serialized) - // let param = buildTxParam(tx) + let param = buildTxParam(tx) + sendTx(param) // console.log('param : '+param) // txSender.sendTxWithSocket(param, callback) - let param = buildRestfulParam(tx) - let url = TEST_ONT_URL.sendRawTxByRestful - axios.post(url, param).then((res)=>{ - console.log(res.data) - }) + // let param = buildRestfulParam(tx) + // let url = TEST_ONT_URL.sendRawTxByRestful + // axios.post(url, param).then((res)=>{ + // console.log(res.data) + // }) } const testAddAttribute = () => { - var claimId = 'claim:b5a87bea92d52525b6eba3b670595cf8b9cbb51e972f5cbff499d48677ddee8a', - context = 'claim:staff_authentication8', - issuer = 'did:ont:TVuF6FH1PskzWJAFhWAFg17NSitMDEBNoa' - let path = str2hexstr(claimId) - let type = str2hexstr('JSON') - let data = { - Type : 'JSON', - Value : { - Context: context, - Issuer: issuer - } - } - let value = JSON.stringify(data) - console.log('value: '+value) - value = str2hexstr(value) + // var claimId = 'claim:b5a87bea92d52525b6eba3b670595cf8b9cbb51e972f5cbff499d48677ddee8a', + // context = 'claim:staff_authentication8', + // issuer = 'did:ont:TVuF6FH1PskzWJAFhWAFg17NSitMDEBNoa' + // let path = str2hexstr(claimId) + // let type = str2hexstr('JSON') + // let data = { + // Type : 'JSON', + // Value : { + // Context: context, + // Issuer: issuer + // } + // } + // let value = JSON.stringify(data) + // console.log('value: '+value) + // value = str2hexstr(value) // let value = str2hexstr(issuer) - // let path = str2hexstr('Claim:twitter') - // let type = str2hexstr('String') - // let value = str2hexstr('wang17@twitter') + let path = str2hexstr('Claim:twitter') + let type = str2hexstr('String') + let value = str2hexstr('wang17@twitter') let tx = buildAddAttributeTx(path, value, type, ontid, privateKey ) @@ -344,7 +346,7 @@ const testVerifyOntidClaim = () => { // testAddAttribute() -// testDDOTx() +testDDOTx() // testVerifyOntidClaim() @@ -364,4 +366,4 @@ const testVerifyOntidClaim = () => { // testGetPublicKeyId() -testGetPublicKeyStatus() \ No newline at end of file +// testGetPublicKeyStatus() \ No newline at end of file diff --git a/test/websocketClient.test.ts b/test/websocketClient.test.ts new file mode 100644 index 00000000..87805d09 --- /dev/null +++ b/test/websocketClient.test.ts @@ -0,0 +1,287 @@ +import WebsocketClientApi from '../src/network/websocket/websocketClient' +import { buildGetDDOTx } from '../src/smartcontract/ontidContract'; +import TxSender from '../src/transaction/txSender' +import { TEST_ONT_URL } from '../src/consts'; + +describe('test websocket', () => { + + var wsClient = new WebsocketClientApi() + var txSender = new TxSender(TEST_ONT_URL.SOCKET_URL) + // test('send heartbeat', () => { + // wsClient.sendHeartBeat() + // }) + + test('test sendRawTransaction', ()=> { + let ontid = 'did:ont:TC7ZkUjbiN6yKaAT3hw5VzqLq18Xu8cZJW' + + let tx = buildGetDDOTx(ontid) + let param = wsClient.sendRawTransaction(tx.serialize()) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('sendRawTransaction') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getRawTransaction', () => { + let txhash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + let param = wsClient.getRawTransaction(txhash) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getRawTransaction') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getRawTransactionJson', () => { + let txhash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + let param = wsClient.getRawTransactionJson(txhash) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('sendRawTransactionJson') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getGenerateBlockTime', () => { + let param = wsClient.getGenerateBlockTime() + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getGenerateBlockTime') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getNodeCount', () => { + let param = wsClient.getNodeCount() + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getNodeCount') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getBlockHeight', () => { + let param = wsClient.getBlockHeight() + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getBlockHeight') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getBlock by height', () => { + let height = 171230 + let param = wsClient.getBlock(height) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getBlock by height') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getBlock by hash', () => { + let hash = '54dbc90e2476c7444774814e1ba65c606586fff4cac742d6de7d1e5899993e5c' + let param = wsClient.getBlock(hash) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getBlock by hash') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getBlockJson by height', () => { + let height = 1000 + let param = wsClient.getBlockJson(height) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getBlockJson by height') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getBlockJson by hash', () => { + let hash = '54dbc90e2476c7444774814e1ba65c606586fff4cac742d6de7d1e5899993e5c' + let param = wsClient.getBlockJson(hash) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getBlockJson by hash') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getBalance', () => { + let address = 'TA7T3p6ikRG5s2pAaehUH2XvRCCzvsFmwE' + let param = wsClient.getBalance(address) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getBalance') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getContract', () => { + let codeHash = '8055b362904715fd84536e754868f4c8d27ca3f6' + let param = wsClient.getContract(codeHash) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getContract') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getContractJson', () => { + let codeHash = '8055b362904715fd84536e754868f4c8d27ca3f6' + let param = wsClient.getContractJson(codeHash) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getContractJson') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getSmartCodeEvent by height', () => { + let height = 169909 + let param = wsClient.getSmartCodeEvent(height) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getSmartCodeEvent') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getSmartCodeEvent by txHash', () => { + let hash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + let param = wsClient.getSmartCodeEvent(hash) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getSmartCodeEvent') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getBlockHeightByTxHash', () => { + let hash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + let param = wsClient.getBlockHeightByTxHash(hash) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getBlockHeightByTxHash') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + test('test getStorage', () => { + let codeHash = '8055b362904715fd84536e754868f4c8d27ca3f6' + let key = '2a6469643a6f6e743a5443375a6b556a62694e36794b61415433687735567a714c713138587538635a4a5702' + let param = wsClient.getStorage(codeHash, key) + let callback = function (err, res, socket) { + if (err) { + console.log(err) + return; + } + console.log('getStorage') + console.log(res) + socket.close() + } + txSender.sendTxWithSocket(param, callback) + }) + + // test('test getMerkleProof', () => { + // let hash = '8893c8648d8dfad8f99274e1bdd3abb3cd47ba87cb54543c0594ac9cf7110888' + // let param = wsClient.getMerkleProof(hash) + // txSender.sendTxWithSocket(param, callback) + // }) +}) + + + +// var callback = function (err, res, socket) { +// if (err) { +// console.log(err) +// return; +// } +// console.log(res) +// } +// var wsSocket = new WebsocketClient(callback) + +// wsSocket.sendHeartBeat()