cic-cli/cic/proof.py

182 lines
5.1 KiB
Python
Raw Normal View History

2021-10-09 19:56:29 +02:00
# standard imports
import os
import json
2021-10-09 20:37:54 +02:00
import logging
2021-10-10 21:30:18 +02:00
import tempfile
import cbor2
# external imports
from hexathon import strip_0x
2021-10-19 11:18:22 +02:00
from cic_types import MetadataPointer
from cic_types.processor import generate_metadata_pointer
from cic_types.ext.metadata import MetadataRequestsHandler
2021-10-09 19:56:29 +02:00
# local imports
from .base import *
2021-10-19 11:18:22 +02:00
from cic.output import OutputWriter
2021-10-09 19:56:29 +02:00
2021-10-09 20:37:54 +02:00
logg = logging.getLogger(__name__)
2021-10-09 19:56:29 +02:00
class Proof(Data):
2021-11-29 08:02:12 +01:00
"""Proof handles the immutable token proof data mapped to the initial token deployment.
It processes inputs from the proof.json file in the session directory.
Optionally, attachment objects can be added to the proof. If added, the resulting proof digest will consists of the attachment digests added to the root digest. These are then are deterministically ordered, regardless of which order attachments were given to the constructor.
:param path: Path to settings directory
:type path: str
:param attachments: List of attachment objects to include in the proof
:type attachments: cic.attachment.Attachment
:param writer: Writer interface receiving the output of the processor
:type writer: cic.output.OutputWriter
"""
2021-10-09 19:56:29 +02:00
def __init__(self, path='.', attachments=None, writer=None):
2021-10-09 19:56:29 +02:00
super(Proof, self).__init__()
self.proofs = []
2021-10-09 19:56:29 +02:00
self.namespace = 'ge'
self.description = None
2021-11-29 13:18:28 +01:00
self.issuer = None
2021-10-09 19:56:29 +02:00
self.path = path
self.writer = writer
2021-10-10 21:30:18 +02:00
self.extra_attachments = attachments
self.attachments = {}
2021-10-09 19:56:29 +02:00
self.proof_path = os.path.join(self.path, 'proof.json')
2021-10-10 21:30:18 +02:00
self.temp_proof_path = tempfile.mkstemp()[1]
2021-10-09 19:56:29 +02:00
def load(self):
2021-11-29 08:02:12 +01:00
"""Load proof data from settings.
"""
2021-10-09 20:37:54 +02:00
super(Proof, self).load()
2021-10-09 19:56:29 +02:00
2021-10-09 20:37:54 +02:00
f = open(self.proof_path, 'r')
o = json.load(f)
2021-10-09 19:56:29 +02:00
f.close()
2021-10-09 20:37:54 +02:00
self.set_version(o['version'])
2021-10-09 19:56:29 +02:00
self.description = o['description']
self.namespace = o['namespace']
2021-10-14 15:43:23 +02:00
self.issuer = o['issuer']
self.proofs = o['proofs']
2021-10-09 19:56:29 +02:00
if self.extra_attachments != None:
a = self.extra_attachments.asdict()
for k in a.keys():
self.attachments[k] = a[k]
hshs = self.__get_ordered_hashes()
self.proofs = list(map(strip_0x, hshs))
2021-10-09 19:56:29 +02:00
self.inited = True
def start(self):
2021-11-29 08:02:12 +01:00
"""Initialize proof settings from template.
"""
2021-10-09 19:56:29 +02:00
super(Proof, self).start()
proof_template_file_path = os.path.join(data_dir, 'proof_template_v{}.json'.format(self.version()))
f = open(proof_template_file_path)
o = json.load(f)
f.close()
f = open(self.proof_path, 'w')
2021-10-18 10:47:48 +02:00
json.dump(o, f, sort_keys=True, indent="\t")
2021-10-09 19:56:29 +02:00
f.close()
2021-10-10 21:30:18 +02:00
def asdict(self):
2021-11-29 08:02:12 +01:00
"""Output proof state to dict.
"""
2021-10-10 21:30:18 +02:00
return {
'version': self.version(),
'namespace': self.namespace,
'description': self.description,
2021-10-14 15:43:23 +02:00
'issuer': self.issuer,
'proofs': self.proofs,
2021-10-10 21:30:18 +02:00
}
2021-11-29 08:02:12 +01:00
# TODO: the efficiency of this method could probably be improved.
2021-10-10 21:30:18 +02:00
def __get_ordered_hashes(self):
ks = list(self.attachments.keys())
ks.sort()
return ks
# def get(self):
# hsh = self.hash(b).hex()
# self.attachments[hsh] = self.temp_proof_path
# logg.debug('cbor of {} is {} hashes to {}'.format(v, b.hex(), hsh))
def root(self):
2021-11-29 08:02:12 +01:00
"""Calculate the root digest from the serialized proof object.
"""
2021-10-10 21:30:18 +02:00
v = self.asdict()
#b = cbor2.dumps(v)
b = json.dumps(v)
2021-10-10 21:30:18 +02:00
f = open(self.temp_proof_path, 'w')
2021-10-10 21:30:18 +02:00
f.write(b)
f.close()
2021-11-29 13:18:28 +01:00
b = b.encode('utf-8')
k = self.hash(b)
2021-10-11 19:02:42 +02:00
return (k.hex(), b)
2021-10-11 19:02:42 +02:00
2021-10-21 15:11:05 +02:00
def process(self, token_address=None, token_symbol=None, writer=None):
2021-11-29 08:02:12 +01:00
"""Serialize and publish proof.
See cic.processor.Processor.process
"""
2021-10-11 19:02:42 +02:00
if writer == None:
writer = self.writer
(k, v) = self.root()
writer.write(k, v)
2021-11-29 13:18:28 +01:00
root_key = k
2021-10-11 19:02:42 +02:00
token_symbol_bytes = token_symbol.encode('utf-8')
k = generate_metadata_pointer(token_symbol_bytes, MetadataPointer.TOKEN_PROOF_SYMBOL)
writer.write(k, v)
token_address_bytes = bytes.fromhex(strip_0x(token_address))
k = generate_metadata_pointer(token_address_bytes, MetadataPointer.TOKEN_PROOF)
writer.write(k, v)
# (hsh, hshs) = self.get()
#hshs = list(map(strip_0x, hshs))
# hshs_bin = list(map(bytes.fromhex, hshs))
# hshs_cat = b''.join(hshs_bin)
# f = open(self.temp_proof_path, 'rb')
# v = f.read()
# f.close()
# writer.write(hsh, v)
2021-10-12 14:26:57 +02:00
# r = self.hash(hshs_cat)
# r_hex = r.hex()
2021-10-11 19:02:42 +02:00
#logg.debug('generated proof {} for hashes {}'.format(r_hex, hshs))
2021-10-11 19:02:42 +02:00
#writer.write(r_hex, hshs_cat)
o = self.asdict()
f = open(self.proof_path, 'w')
json.dump(o, f, sort_keys=True, indent="\t")
f.close()
2021-11-29 13:18:28 +01:00
return root_key
2021-10-10 21:30:18 +02:00
2021-10-09 20:37:54 +02:00
def __str__(self):
2021-10-10 14:49:22 +02:00
return "description = {}\n".format(self.description)