2021-10-09 19:56:29 +02:00
|
|
|
|
# standard imports
|
|
|
|
|
import os
|
|
|
|
|
import json
|
2021-10-22 16:42:38 +02:00
|
|
|
|
import logging
|
|
|
|
|
import base64
|
2021-10-09 19:56:29 +02:00
|
|
|
|
|
2021-10-11 12:23:08 +02:00
|
|
|
|
# external imports
|
|
|
|
|
from cic_types import MetadataPointer
|
|
|
|
|
from cic_types.processor import generate_metadata_pointer
|
2021-10-14 15:43:23 +02:00
|
|
|
|
from cic_types.ext.metadata import MetadataRequestsHandler
|
2021-10-11 12:23:08 +02:00
|
|
|
|
from hexathon import strip_0x
|
|
|
|
|
|
2021-10-09 19:56:29 +02:00
|
|
|
|
# local imports
|
2021-10-10 11:33:30 +02:00
|
|
|
|
from .base import (
|
|
|
|
|
Data,
|
|
|
|
|
data_dir,
|
|
|
|
|
)
|
2021-10-14 15:43:23 +02:00
|
|
|
|
from cic.output import OutputWriter
|
2021-10-22 16:42:38 +02:00
|
|
|
|
logg = logging.getLogger(__name__)
|
2021-10-09 19:56:29 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Meta(Data):
|
2021-11-29 08:02:12 +01:00
|
|
|
|
"""Serialize and publish metadata for token.
|
2021-10-09 19:56:29 +02:00
|
|
|
|
|
2021-11-29 08:02:12 +01:00
|
|
|
|
The token metadata is any mutable data that is not part of the initial token proof, but published simultaneously as the token nonetheless.
|
|
|
|
|
|
|
|
|
|
:param path: Path to settings directory
|
|
|
|
|
:type path: str
|
|
|
|
|
:param writer: Writer interface receiving the output of the processor
|
|
|
|
|
:type writer: cic.output.OutputWriter
|
|
|
|
|
"""
|
2021-10-11 17:39:01 +02:00
|
|
|
|
def __init__(self, path='.', writer=None):
|
2021-10-09 19:56:29 +02:00
|
|
|
|
super(Meta, self).__init__()
|
|
|
|
|
self.name = None
|
2021-10-09 20:37:54 +02:00
|
|
|
|
self.contact = {}
|
2021-10-09 19:56:29 +02:00
|
|
|
|
self.path = path
|
2021-10-11 17:39:01 +02:00
|
|
|
|
self.writer = writer
|
2021-10-09 19:56:29 +02:00
|
|
|
|
self.meta_path = os.path.join(self.path, 'meta.json')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def load(self):
|
2021-11-29 08:02:12 +01:00
|
|
|
|
"""Load metadata from settings.
|
|
|
|
|
"""
|
2021-10-09 19:56:29 +02:00
|
|
|
|
super(Meta, self).load()
|
|
|
|
|
|
2021-10-09 20:37:54 +02:00
|
|
|
|
f = open(self.meta_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.name = o['name']
|
|
|
|
|
self.contact = o['contact']
|
2021-10-09 19:56:29 +02:00
|
|
|
|
|
|
|
|
|
self.inited = True
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def start(self):
|
2021-11-29 08:02:12 +01:00
|
|
|
|
"""Initialize metadata settings from template.
|
|
|
|
|
"""
|
2021-10-09 19:56:29 +02:00
|
|
|
|
super(Meta, self).start()
|
|
|
|
|
|
|
|
|
|
meta_template_file_path = os.path.join(data_dir, 'meta_template_v{}.json'.format(self.version()))
|
|
|
|
|
|
|
|
|
|
f = open(meta_template_file_path)
|
|
|
|
|
o = json.load(f)
|
|
|
|
|
f.close()
|
|
|
|
|
|
|
|
|
|
f = open(self.meta_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-09 20:37:54 +02:00
|
|
|
|
|
|
|
|
|
|
2021-10-11 12:23:08 +02:00
|
|
|
|
def reference(self, token_address):
|
2021-11-29 08:02:12 +01:00
|
|
|
|
"""Calculate the mutable reference for the token metadata.
|
|
|
|
|
"""
|
2021-10-11 12:23:08 +02:00
|
|
|
|
token_address_bytes = bytes.fromhex(strip_0x(token_address))
|
2021-10-15 13:26:28 +02:00
|
|
|
|
return generate_metadata_pointer(token_address_bytes, MetadataPointer.TOKEN_META)
|
2021-10-11 12:23:08 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def asdict(self):
|
2021-11-29 08:02:12 +01:00
|
|
|
|
"""Output proof state to dict.
|
|
|
|
|
"""
|
2021-10-11 12:23:08 +02:00
|
|
|
|
return {
|
|
|
|
|
'name': self.name,
|
|
|
|
|
'contact': self.contact,
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-11 15:28:09 +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 metadata.
|
|
|
|
|
|
|
|
|
|
See cic.processor.Processor.process
|
|
|
|
|
"""
|
2021-10-11 17:39:01 +02:00
|
|
|
|
if writer == None:
|
|
|
|
|
writer = self.writer
|
|
|
|
|
|
2021-10-11 15:28:09 +02:00
|
|
|
|
v = json.dumps(self.asdict())
|
2021-10-21 15:11:05 +02:00
|
|
|
|
|
|
|
|
|
token_address_bytes = bytes.fromhex(strip_0x(token_address))
|
|
|
|
|
k = generate_metadata_pointer(token_address_bytes, MetadataPointer.TOKEN_META)
|
|
|
|
|
writer.write(k, v.encode('utf-8'))
|
|
|
|
|
|
|
|
|
|
token_symbol_bytes = token_symbol.encode('utf-8')
|
|
|
|
|
k = generate_metadata_pointer(token_symbol_bytes, MetadataPointer.TOKEN_META_SYMBOL)
|
2021-10-11 17:39:01 +02:00
|
|
|
|
writer.write(k, v.encode('utf-8'))
|
2021-10-11 15:28:09 +02:00
|
|
|
|
|
|
|
|
|
return (k, v)
|
|
|
|
|
|
2021-10-11 12:23:08 +02:00
|
|
|
|
|
2021-10-09 20:37:54 +02:00
|
|
|
|
def __str__(self):
|
2021-10-10 14:49:22 +02:00
|
|
|
|
s = "contact.name = {}\n".format(self.name)
|
2021-10-09 20:37:54 +02:00
|
|
|
|
|
|
|
|
|
for k in self.contact.keys():
|
|
|
|
|
if self.contact[k] == '':
|
|
|
|
|
continue
|
2021-10-10 14:49:22 +02:00
|
|
|
|
s += "contact.{} = {}\n".format(k.lower(), self.contact[k])
|
2021-10-09 20:37:54 +02:00
|
|
|
|
|
|
|
|
|
return s
|
2021-10-14 15:43:23 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MetadataWriter(OutputWriter):
|
2021-11-29 08:02:12 +01:00
|
|
|
|
"""Custom writer for publishing data under immutable content-addressed pointers in the cic-meta storage backend.
|
|
|
|
|
|
|
|
|
|
Data that is not utf-8 will be converted to base64 before publishing.
|
|
|
|
|
|
|
|
|
|
Implements cic.output.OutputWriter
|
|
|
|
|
"""
|
2021-10-21 15:11:05 +02:00
|
|
|
|
|
2021-10-14 15:43:23 +02:00
|
|
|
|
def write(self, k, v):
|
2021-10-21 15:11:05 +02:00
|
|
|
|
rq = MetadataRequestsHandler(MetadataPointer.NONE, bytes.fromhex(k))
|
2021-10-22 16:42:38 +02:00
|
|
|
|
try:
|
|
|
|
|
v = v.decode('utf-8')
|
|
|
|
|
v = json.loads(v)
|
|
|
|
|
logg.debug('metadatawriter bindecode {} {}'.format(k, v))
|
|
|
|
|
except UnicodeDecodeError:
|
|
|
|
|
v = base64.b64encode(v).decode('utf-8')
|
|
|
|
|
v = json.loads(json.dumps(v))
|
|
|
|
|
logg.debug('metadatawriter b64encode {} {}'.format(k, v))
|
|
|
|
|
r = rq.create(v)
|
|
|
|
|
logg.info('metadata submitted at {}'.format(k))
|
|
|
|
|
return r
|
|
|
|
|
|