diff --git a/src/consts.ts b/src/consts.ts index d1dd9a2c..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' @@ -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..db207ad5 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 { buildRestfulParam, sendRawTxRestfulUrl} from './transaction/transactionBuilder' import axios from 'axios' import { DDO } from './transaction/ddo' +import { getPublicKeyStatus, buildGetDDOTx } from './smartcontract/ontidContract' +import { verifyLeafHashInclusion } from './merkle' var ec = require('elliptic').ec var wif = require('wif') @@ -249,4 +251,113 @@ 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 + } + }) +} + +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.Result + }) +} + +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 + } + 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) { + 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/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 new file mode 100644 index 00000000..1470a445 --- /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 = Math.floor( leafIndex / 2 ) + lastNode = Math.floor( 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/data/IdContract.avm b/src/smartcontract/data/IdContract.avm new file mode 100644 index 00000000..cd2dc3b3 Binary files /dev/null and b/src/smartcontract/data/IdContract.avm differ 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 f1255149..00000000 Binary files a/src/smartcontract/data/idContract.avm and /dev/null differ diff --git a/src/smartcontract/data/idContract_v0.2.avm b/src/smartcontract/data/idContract_v0.2.avm deleted file mode 100644 index f7245b07..00000000 Binary files a/src/smartcontract/data/idContract_v0.2.avm and /dev/null differ diff --git a/src/smartcontract/ontidContract.ts b/src/smartcontract/ontidContract.ts new file mode 100644 index 00000000..fa2c6548 --- /dev/null +++ b/src/smartcontract/ontidContract.ts @@ -0,0 +1,185 @@ + +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 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 +} + +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/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 38b9fef9..09de5dd7 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,72 +293,12 @@ 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) { +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/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/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 92bb9a21..9d9bed5d 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, buildGetPublicKeyIdTx, buildGetPublicKeyStatusTx} from '../src/smartcontract/ontidContract' import {Transaction} from '../src/transaction/transaction' import InvokeCode from '../src/transaction/payload/invokeCode' import { Identity } from '../src/identity' @@ -33,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' @@ -53,6 +55,7 @@ var pk2: string var ontid: string var oldrecovery : string var newrecovery : string +var pkId : string var abiInfo: AbiInfo var identity: Identity @@ -63,12 +66,13 @@ 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)) +pkId = '' +// 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) @@ -237,91 +241,66 @@ 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 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) +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) + }) +} - let serialized = tx.serialize() - // console.log('add pk tx: ' + serialized) - - let param = JSON.stringify(Object.assign({}, Default_params, { Data: serialized })) +const testAddPK = () => { + 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 +344,7 @@ const testVerifyOntidClaim = () => { // testAddAttribute() -testDDOTx() +// testDDOTx() // testVerifyOntidClaim() @@ -383,4 +362,6 @@ testDDOTx() // testChangeRecovery() +// testGetPublicKeyId() +testGetPublicKeyStatus() \ No newline at end of file