update

Signed-off-by: Daniel Maricic's avatarDaniel Maricic <[email protected]>
parent 52d74060
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sensio Example</title>
<link
href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk"
crossorigin="anonymous"
>
</head>
<body>
<div class="contaner">
<div class="row">
</div>
</div>
</body>
</html>
\ No newline at end of file
import { ApiPromise } from '@polkadot/api';
// initialise via static create
const api = await ApiPromise.create();
// make a call to retrieve the current network head
api.rpc.chain.subscribeNewHeads((header) => {
console.log(`Chain is at #${header.number}`);
});
This diff is collapsed.
import { hexToString } from '@polkadot/util';
import { api } from '../../../packages/api/src';
async function main(): Promise<void> {
console.time('Setting up the connection');
const api2 = await api();
console.timeEnd('Setting up the connection');
const ops = await api2.query.poe.operations.entries();
ops.forEach(([storageKey, op]) => {
console.log('storage', storageKey.toString());
console.log('hex block number', op.blockNumber.toNumber());
console.log('cid', hexToString(op.op.id.toString()));
});
}
main().then(console.log);
......@@ -34,9 +34,6 @@
"generate:meta": "ts-node --skip-project node_modules/.bin/polkadot-types-from-chain --package . --endpoint ./owlnet.json --output ./src/interfaces",
"update:owlnet": "rm -f ./owlnet.json; curl -H \"Content-Type: application/json\" -d '{\"id\":\"1\", \"jsonrpc\":\"2.0\", \"method\": \"state_getMetadata\", \"params\":[]}' http://localhost:9933 > ./owlnet.json"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
......
import { ApiPromise, Keyring, WsProvider } from '@polkadot/api';
import { KeyringPair } from '@polkadot/keyring/types';
import { hexToString } from '@polkadot/util';
import { customTypesToJSON } from './helpers';
import { DefaultValues } from './interfaces';
import './interfaces/augment-api';
import './interfaces/augment-types';
// our local stuff
......@@ -10,7 +7,7 @@ import * as definitions from './interfaces/definitions';
export let api: ApiPromise;
function showBlockInfo(api: ApiPromise): void {
export function showBlockInfo(api: ApiPromise): void {
// make a call to retrieve the current network head
api.rpc.chain.subscribeNewHeads(async (header) => {
await api.rpc.chain.getBlock(header.hash, async (block) => {
......@@ -19,46 +16,34 @@ function showBlockInfo(api: ApiPromise): void {
const blockNumber = block.block.header.number.toNumber();
console.log('Block is:', blockNumber);
// Extrinsics in the block
// const extrinsics = await block.block.extrinsics;
const extrinsics = block.block.extrinsics;
// Check each extrinsic in the block
// for (const extrinsic of extrinsics) {
// This specific call index [0,1] represents `system.remark`
// console.log(extrinsic.callIndex);
// if (extrinsic.callIndex[0] == 0 && extrinsic.callIndex[1] == 1) {
// console.log(extrinsic);
// Get the byte data from a remark
// const [prefix, buffer] = parsePrefix(extrinsic.args[0]);
// Get sender address
// const sender = extrinsic.signer.toString();
// Route the rest of the buffer to the correct remarkable logic
// }
// }
for (const extrinsic of extrinsics) {
// This specific call index [0,1] represents `system.remark`
console.log(extrinsic.callIndex);
console.log(extrinsic);
}
} catch (error) {
console.error(error);
}
});
});
}
/**
* Constants from PoE Runtime
* @param api
*/
export function constantsForPoe(api: ApiPromise) {
const {
hashAlgo,
hashBits,
encodingAlgo,
encodingPrefix,
}: DefaultValues = api.consts.poe.defaults;
const decoded = {
hashAlgo: hexToString(hashAlgo.toHex()),
hashBits: hashBits.toNumber(),
encodingAlgo: hexToString(encodingAlgo.toHex()),
encodingPrefix: hexToString(encodingPrefix.toHex()),
};
// /**
// * Constants from PoE Runtime
// * @param api
// */
// export function constantsForPoe(api: ApiPromise) {
// const { hashing, encoding }: DefaultValues = api.consts.poe.defaults;
// const decoded = {
// hashAlgo: hexToString(hashing.algo.toHex()),
// hashBits: hashing.bits.toNumber(),
// encodingAlgo: hexToString(encodingAlgo.toHex()),
// encodingPrefix: hexToString(encodingPrefix.toHex()),
// };
return decoded;
}
// return decoded;
// }
export function getAlice(): KeyringPair {
// Construct the keying after the API (crypto has an async init)
......@@ -69,7 +54,7 @@ export function getAlice(): KeyringPair {
return alice;
}
export async function setupConnection(): Promise<ApiPromise> {
export default async function setupConnection(): Promise<ApiPromise> {
// this account ID comes from the customization of substrate-node-template
// https://github.com/polkadot-js/api/blob/master/docs/start/types.extend.md
// const allKnownCustomTypes = Object.assign({}, { Address: 'AccountId', LookupSource: 'AccountId' }, PoECustomTypes);
......@@ -80,12 +65,7 @@ export async function setupConnection(): Promise<ApiPromise> {
{},
);
// console.log('---- CUSTOM TYPES JSON ----\n');
customTypesToJSON(types);
// console.log('\n---- CUSTOM TYPES JSON ----\n');
// Init the provider to connect to the local node
// TODO put this in env or a constant
const provider = new WsProvider(
process.env.BLOCKCHAIN_PROVIDER_SOCKET || 'ws://127.0.0.1:9944',
);
......@@ -101,21 +81,18 @@ export async function setupConnection(): Promise<ApiPromise> {
provider,
});
// Retrieve the chain & node information information via rpc calls
const [chain, nodeName, nodeVersion] = await Promise.all([
api.rpc.system.chain(),
api.rpc.system.name(),
api.rpc.system.version(),
]);
console.log(`Connected to chain ${chain} using ${nodeName} v${nodeVersion}`);
//
// API specific info
//
// showBlockInfo(api);
constantsForPoe(api);
return api;
}
export async function showStatusMessage(api: ApiPromise): Promise<void> {
setInterval(async () => {
const [chain, nodeName, nodeVersion] = await Promise.all([
api.rpc.system.chain(),
api.rpc.system.name(),
api.rpc.system.version(),
]);
console.log(
`Connected to chain ${chain} using ${nodeName} v${nodeVersion}`,
);
}, 2000);
}
export const defaultCreator =
'urn:pgp:d1f5e247a976f1e3c14f0a437a6db9962ef3978e';
import CID from 'cids';
import { Tags } from 'exiftool-vendored';
import { writeFileSync } from 'fs';
import * as imghash from 'imghash';
import msgpack from 'msgpack';
import mh from 'multihashing-async';
export function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function objectToString(o: Record<string, any>): string {
const r = JSON.stringify(o);
// console.log(`\nLength of the json string is ${Buffer.byteLength(r)} bytes`);
return r;
}
export function objectToStringMsgPack(o: Record<string, any>): string {
const r = msgpack.pack(o);
console.log(`\nLength of the json string is ${Buffer.byteLength(r)} bytes`);
return r;
}
export function customTypesToJSON(types) {
return writeFileSync(
'./files/customTypes.json',
JSON.stringify(types, null, 2),
);
}
/**
* Original Document ID sometimes is a UUID without hyphens, this makes it look nice
* later maybe add the is-uuid check https://runkit.com/woss/is-uuid-guid
* @param str string
*/
export function formatToUUID(uuid: string): string {
// return the parse one, no check here
if (uuid.split('-').length === 5) {
return uuid;
}
const r = new RegExp(
/([A-Za-z0-9]{8})([A-Za-z0-9]{4})([A-Za-z0-9]{4})([A-Za-z0-9]{4})([A-Za-z0-9]{12})/gi,
);
const matches = r.exec(uuid) as RegExpExecArray;
if (matches.length !== 6) {
throw new Error('Invalid UUID');
}
const ret = matches.slice(1, matches.length).join('-').toLowerCase();
return ret;
}
// function calculateSimilarity(buf1: Buffer, buf2: Buffer): string {
// const hash1 = imghash.hash('./img1');
// const hash2 = imghash.hash('./img2');
// Promise.all([hash1, hash2]).then((results) => {
// const dist = leven(results[0], results[1]);
// console.log(`Distance between images is: ${dist}`);
// if (dist <= 12) {
// console.log('Images are similar');
// } else {
// console.log('Images are NOT similar');
// }
// });
// return '';
// }
export async function calculateHash(
data: Uint8Array,
algo = 'blake2b',
length = 256,
): Promise<Buffer> {
const hash = await mh(data, `${algo}-${length}`);
return hash;
}
export function createCID(data: Buffer, codec = 'raw'): CID {
return new CID(1, codec, data);
}
/**
* Use only binary ascii representation
* @param b Buffer
*/
export async function calculatePhash(b: Buffer): Promise<string> {
return await imghash.hash(b, 8, 'binary');
}
export function cleanupMetadataTags(tags: Tags): Tags {
return tags;
}
// import { rule } from './runtime/poe/operations/poe-photo';
// import { createRulePayload } from './runtime/poe';
import R from 'ramda';
import { getAlice, setupConnection } from './api';
import { createDefaultRules } from './runtime/poe/helpers';
import { getProofs, getRules } from './runtime/poe/poe';
async function main(): Promise<void> {
try {
// await testStuff();
// return;
const api = await setupConnection();
const alice = getAlice();
const rules = await getRules(api);
setInterval(async () => {
const proofs = await getProofs(api);
console.log('Proofs', proofs);
}, 5000);
if (R.isEmpty(rules) || rules.length !== 3) {
console.log('No rules defined, creating ...');
await createDefaultRules(api, alice);
} else {
const imageRule = rules.find((r) => r.rule.forWhat.isPhoto);
console.log(imageRule);
if (!R.isEmpty(imageRule)) {
// const data = resolve('./assets/test-photos/copyrighted-image.jpg');
// const p = await processRule(data, imageRule, true);
// console.log(p);
// await createClaimTX(api, alice, p);
// await processImageForPoE(resolve('./assets/test-photos/copyrighted-image.dng'));
// await processImageForPoE(resolve('./assets/test-photos/_MG_4991.CR2'));
}
}
} catch (error) {
console.error(error);
}
// to create a poe rule
// formatToUUID('C4CEBFD8B6A782A5E0DC32AFE31D6D09');
}
main()
.catch((e) =>
console.error(
'Something went wrong with the connection or something else',
e,
),
)
.finally();
/**
*
*
* hashes or the KEYS, they are generated by the hasher in rust
*
*
* 0x4089830b5cf7d628521896f0642fffa66893fa5565c375789bd56f57600396a6
* 0x6f53ae14a8d800bd9ba6e87c1d05ed87857d75741d9082616137935d2e173819
* 0x2b522fc050d747a0e71419cca2bb1439f74329f61a22eadcb6a0c18c260f26fa
*/
export { default as api } from './api';
......@@ -6,7 +6,7 @@ import { Compact, Option, U8aFixed, Vec } from '@polkadot/types/codec';
import { Bytes, u16, u64 } from '@polkadot/types/primitive';
import { OperationData, PhashInfo, ProofData, RuleData } from './poe';
import { Extrinsic } from '@polkadot/types/interfaces/extrinsics';
import { AccountId, Balance, Call, ChangesTrieConfiguration, KeyValue, LookupSource, Moment, Perbill } from '@polkadot/types/interfaces/runtime';
import { AccountId, AccountIndex, Address, Balance, Call, ChangesTrieConfiguration, KeyValue, LookupSource, Moment, Perbill } from '@polkadot/types/interfaces/runtime';
import { Key } from '@polkadot/types/interfaces/system';
import { Timepoint } from '@polkadot/types/interfaces/utility';
import { ApiTypes, SubmittableExtrinsic } from '@polkadot/api/types';
......@@ -19,7 +19,7 @@ declare module '@polkadot/api/types/submittable' {
* Exactly as `transfer`, except the origin must be root and the source account may be
* specified.
**/
forceTransfer: AugmentedSubmittable<(source: LookupSource | string | Uint8Array, dest: LookupSource | string | Uint8Array, value: Compact<Balance> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>>;
forceTransfer: AugmentedSubmittable<(source: LookupSource | Address | AccountId | AccountIndex | string | Uint8Array, dest: LookupSource | Address | AccountId | AccountIndex | string | Uint8Array, value: Compact<Balance> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>>;
/**
* Set the balances of a given account.
* This will alter `FreeBalance` and `ReservedBalance` in storage. it will
......@@ -32,7 +32,7 @@ declare module '@polkadot/api/types/submittable' {
* - Contains a limited number of reads and writes.
* # </weight>
**/
setBalance: AugmentedSubmittable<(who: LookupSource | string | Uint8Array, newFree: Compact<Balance> | AnyNumber | Uint8Array, newReserved: Compact<Balance> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>>;
setBalance: AugmentedSubmittable<(who: LookupSource | Address | AccountId | AccountIndex | string | Uint8Array, newFree: Compact<Balance> | AnyNumber | Uint8Array, newReserved: Compact<Balance> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>>;
/**
* Transfer some liquid free balance to another account.
* `transfer` will set the `FreeBalance` of the sender and receiver.
......@@ -53,14 +53,14 @@ declare module '@polkadot/api/types/submittable' {
* check that the transfer will not kill the origin account.
* # </weight>
**/
transfer: AugmentedSubmittable<(dest: LookupSource | string | Uint8Array, value: Compact<Balance> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>>;
transfer: AugmentedSubmittable<(dest: LookupSource | Address | AccountId | AccountIndex | string | Uint8Array, value: Compact<Balance> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>>;
/**
* Same as the [`transfer`] call, but with a check that the transfer will not kill the
* origin account.
* 99% of the time you want [`transfer`] instead.
* [`transfer`]: struct.Module.html#method.transfer
**/
transferKeepAlive: AugmentedSubmittable<(dest: LookupSource | string | Uint8Array, value: Compact<Balance> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>>;
transferKeepAlive: AugmentedSubmittable<(dest: LookupSource | Address | AccountId | AccountIndex | string | Uint8Array, value: Compact<Balance> | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>>;
};
grandpa: {
[index: string]: SubmittableExtrinsicFunction<ApiType>;
......@@ -99,7 +99,7 @@ declare module '@polkadot/api/types/submittable' {
* - One DB change.
* # </weight>
**/
setKey: AugmentedSubmittable<(updated: LookupSource | string | Uint8Array) => SubmittableExtrinsic<ApiType>>;
setKey: AugmentedSubmittable<(updated: LookupSource | Address | AccountId | AccountIndex | string | Uint8Array) => SubmittableExtrinsic<ApiType>>;
/**
* Authenticates the sudo key and dispatches a function call with `Root` origin.
* The dispatch origin for this call must be _Signed_.
......@@ -122,7 +122,7 @@ declare module '@polkadot/api/types/submittable' {
* - Weight of derivative `call` execution + 10,000.
* # </weight>
**/
sudoAs: AugmentedSubmittable<(who: LookupSource | string | Uint8Array, call: Call | { callIndex?: any; args?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>>;
sudoAs: AugmentedSubmittable<(who: LookupSource | Address | AccountId | AccountIndex | string | Uint8Array, call: Call | { callIndex?: any; args?: any } | string | Uint8Array) => SubmittableExtrinsic<ApiType>>;
};
system: {
[index: string]: SubmittableExtrinsicFunction<ApiType>;
......
......@@ -1661,12 +1661,6 @@ declare module '@polkadot/types/types/registry' {
StorageChangeSet: StorageChangeSet;
'Option<StorageChangeSet>': Option<StorageChangeSet>;
'Vec<StorageChangeSet>': Vec<StorageChangeSet>;
Address: Address;
'Option<Address>': Option<Address>;
'Vec<Address>': Vec<Address>;
LookupSource: LookupSource;
'Option<LookupSource>': Option<LookupSource>;
'Vec<LookupSource>': Vec<LookupSource>;
PoeId: PoeId;
'Option<PoeId>': Option<PoeId>;
'Vec<PoeId>': Vec<PoeId>;
......
export const PoECustomTypes = {
Address: 'AccountId',
LookupSource: 'AccountId',
// Address: 'AccountId',
// LookupSource: 'AccountId',
PoeId: 'Vec<u8>',
CreatorId: 'Vec<u8>',
DefaultsHashing: {
......
......@@ -5,9 +5,6 @@ import { Enum, Struct, Vec } from '@polkadot/types/codec';
import { Bytes, bool, i32 } from '@polkadot/types/primitive';
import { AccountId, BlockNumber } from '@polkadot/types/interfaces/runtime';
/** @name Address */
export interface Address extends AccountId {}
/** @name CreatorId */
export interface CreatorId extends Bytes {}
......@@ -47,9 +44,6 @@ export interface ForWhat extends Enum {
readonly isSmartPhone: boolean;
}
/** @name LookupSource */
export interface LookupSource extends AccountId {}
/** @name Operation */
export interface Operation extends Struct {
readonly id: PoeId;
......
import { stringToHex } from '@polkadot/util';
import { Rule } from '../../interfaces';
import { RuleInternalPayload } from './poe';
export function encode(data: string, algo = 'hex', prefix = '0x'): string {
// raw means that multicodec in use is `raw bytes`
// more info here https://github.com/multiformats/cid
// and here https://github.com/multiformats/multicodec/blob/master/table.csv
if (algo !== 'hex' || prefix !== '0x') {
throw new Error('Currently we only support hex encoding');
} else {
return stringToHex(data);
}
}
/**
*
* @param filePath String
* @param writeMetadata Boolean
*/
export async function processRule(
filePath: string,
rulePayload: RuleInternalPayload,
writeMetadata = false,
): Promise<{ payload: string; ruleId: string; proof: string }> {
const { rule, ruleId } = rulePayload;
const { buildParams, createProof } = rule;
const fileBuffer = readFileSync(filePath);
// here process the rule ops
const tags = await exiftool.read(filePath, []);
if (writeMetadata) {
writeFileSync(
'./files/metadata/metadata-jpg.json',
JSON.stringify(tags, null, 2),
);
writeFileSync(
'./files/metadata/metadata-jpg-raw.json',
JSON.stringify(await exiftool.readRaw(filePath, []), null, 2),
);
}
console.log(`\nProcessing image ...`);
console.log(`\r Implementing rule ${ruleId}`);
console.time('executeOps took');
const ops = await executeOps(rule, fileBuffer, tags);
console.timeEnd('executeOps took');
console.time('buildBody took');
const body = buildBody(rule, ops);
console.timeEnd('buildBody took');
console.time('buildPayload took');
const payload = buildPayload(rule, ruleId, body);
console.timeEnd('buildPayload took');
console.time('buildPayload took');
const payloadString = encode(
objectToString(payload),
buildParams.encodeAlgo,
buildParams.prefix,
);
console.timeEnd('buildPayload took');
console.log('\n');
const params = {
payload: payloadString,
proof: encode(
await createCID(
await calculateHash(
stringToU8a(payloadString),
createProof.hashAlgo,
createProof.hashBits,
),
).toString(),
),
ruleId,
};
writeFileSync(
`./files/poe-requests/${params.proof}.json`,
JSON.stringify(
{
debug: { payload },
params,
},
null,
2,
),
);
return params;
}
/**
* Example how to generate params
* import { blake2AsHex } from '@polkadot/util-crypto';
* blake2AsHex('abc'); // => 0xba80a53f981c4d0d
*
* @param proof hex encoded string Vec<u8> in rust.
* Proof is the blake2b-128 hash of the PAYLOAD.
* executed rules result produce the body of the payload,
* then hex encoded using parity scale codec.
* @param payload hex encoded string Vec<u8> in rust. Stringified object that
* implements PoePayload interface.
* @param rule string rule ID from the blockchain DB, or later a 'urn' format
*/
// function createClaim(proof: string, payload: string, ruleId: string): void {
// console.log(proof, payload, ruleId);
// return;
// }
// function createRule(proof: string, payload: string, ruleId: string): void {
// console.log(proof, payload, ruleId);
// return;
// }
/**
* At the end we must get the calculated hashes
* content_hash - hex encoded
* metadata_hash - hex encoded
* perceptual_hash - hex encoded ???
*
* @param {Rule} r
*/
async function executeOps(
r: Rule,
fileBuffer: Buffer,
tags: Tags,
): Promise<string[]> {
const { ops } = r;
return Promise.all(
ops.map(async ({ op, hashAlgo, hashBits, ops }) => {
// eslint-disable-next-line prefer-const
let ret = '',
b,
h,
mh;
switch (op) {
case 'metadata_hash':
b = stringToU8a(objectToString(cleanupMetadataTags(tags)));
mh = await calculateHash(b, hashAlgo, hashBits);
h = await createCID(mh).toString();
if (ops?.length) {
throw new Error(
`ExecuteOps:: OP has more ops, we don't support that just yet.`,
);
}
ret = h;
break;
case 'raw_pixels_hash':
// here we should take the raw pixel hash only
mh = await calculateHash(fileBuffer, hashAlgo, hashBits);
h = await createCID(mh).toString();
if (ops?.length) {
throw new Error(
`ExecuteOps:: OP has more ops, we don't support that just yet.`,
);
}
ret = h;
break;
case 'perceptual_hash':
const phash = await calculatePhash(fileBuffer);
h = phash;
if (ops?.length) {
throw new Error(
`ExecuteOps:: OP has more ops, we don't support that just yet.`,