C level serialisation

This commit is contained in:
Florian Förster 2025-12-12 10:58:27 +01:00
parent 61753f03d8
commit 9f73e2c051
4 changed files with 1596 additions and 779 deletions

View File

@ -11,6 +11,6 @@ struct Block {
std::string hash;
Block() : index(0), timestamp(0), nonce(0), data(), prev_hash(), hash() {}
Block(uint64_t idx, double ts, uint64_t n, const std::string& d, const std::string& pre_h, const std::string& h)
Block(uint64_t idx, uint64_t ts, uint64_t n, const std::string& d, const std::string& pre_h, const std::string& h)
: index(idx), timestamp(ts), nonce(n), data(d), prev_hash(pre_h), hash(h) {}
};

View File

@ -4,7 +4,7 @@ from libc cimport stdint
cdef extern from "block.hpp" namespace "":
cdef cppclass Block:
stdint.uint64_t index
double timestamp
stdint.uint64_t timestamp
stdint.uint64_t nonce
string data
string prev_hash

File diff suppressed because it is too large Load Diff

View File

@ -17,18 +17,40 @@ from polluck_blockchain.block cimport Block
from libcpp.unordered_map cimport unordered_map
from libcpp.string cimport string
from libc.stdint cimport uint64_t
from libc.stdlib cimport malloc, free
from libc.string cimport memcpy
from cython.operator import postincrement, dereference
ctypedef unsigned long ULong
ctypedef unordered_map[uint64_t, Block*] BcHashmap
cdef timestamp_to_datetime(double ts):
return datetime.datetime.fromtimestamp(ts, dopt_basics.datetime.TIMEZONE_UTC)
cdef timestamp_to_datetime(uint64_t ts):
return datetime.datetime.fromtimestamp(float(ts), dopt_basics.datetime.TIMEZONE_UTC)
cdef float_to_bytes(double num):
return struct.pack(">d", num)
# cdef float_to_bytes(double num):
# return struct.pack(">d", num)
cdef int serialize_uint32(unsigned char* out, unsigned int v) except -1 nogil:
out[0] = (v >> 24) & 0xFF
out[1] = (v >> 16) & 0xFF
out[2] = (v >> 8) & 0xFF
out[3] = v & 0xFF
cdef int serialize_uint64(unsigned char* out, unsigned long long v) except -1 nogil:
out[0] = (v >> 56) & 0xFF
out[1] = (v >> 48) & 0xFF
out[2] = (v >> 40) & 0xFF
out[3] = (v >> 32) & 0xFF
out[4] = (v >> 24) & 0xFF
out[5] = (v >> 16) & 0xFF
out[6] = (v >> 8) & 0xFF
out[7] = v & 0xFF
cdef struct SerializeResult:
unsigned char *ptr
size_t size
cdef class PyBlock:
cdef:
@ -52,26 +74,19 @@ cdef class PyBlock:
if not from_ptr:
self.BlockC = new Block(
index,
datetime.datetime(2025, 12, 1, 12, 0, 0).timestamp(),
int(datetime.datetime(2025, 12, 1, 12, 0, 0).timestamp()),
nonce,
data.encode("UTF-8"),
previous_hash.encode("UTF-8"),
"".encode("UTF-8"),
)
if self.BlockC == NULL:
raise MemoryError("Allocation of block object failed")
raise MemoryError()
self.ptr_owner = True
def __init__(self, *args, **kwargs):
pass
# self._index = index
# # self._timestamp = dopt_basics.datetime.current_time_tz().timestamp()
# self._timestamp = datetime.datetime(2025, 12, 1, 12, 0, 0).timestamp()
# self._data = data.encode("UTF-8")
# self._prev_hash = previous_hash.encode("UTF-8")
# self._nonce = nonce
# self._hash = "".encode("UTF-8")
def __dealloc__(self):
if self.BlockC is not NULL and self.ptr_owner is True:
@ -144,6 +159,58 @@ cdef class PyBlock:
def hash(self):
return self.BlockC.hash.decode("UTF-8")
cdef SerializeResult bytes_serialize_c(self):
cdef:
size_t total_len
unsigned char* buf
size_t pos = 0
# index (8), timestamp (8), nonce (8), data, prev_hash
total_len = (
<size_t>(8 * 3) +
self.BlockC.data.size() +
self.BlockC.prev_hash.size()
)
buf = <unsigned char*>malloc(total_len * sizeof(unsigned char))
if buf == NULL:
raise MemoryError()
serialize_uint64(buf + pos, self.BlockC.index)
pos += 8
serialize_uint64(buf + pos, self.BlockC.timestamp)
pos += 8
serialize_uint64(buf + pos, self.BlockC.nonce)
pos += 8
# Copy data
memcpy(
buf + pos,
self.BlockC.data.c_str(),
self.BlockC.data.size(),
)
pos += self.BlockC.data.size()
# Copy prev_hash
memcpy(
buf + pos,
self.BlockC.prev_hash.c_str(),
self.BlockC.prev_hash.size(),
)
pos += self.BlockC.prev_hash.size()
return SerializeResult(buf, total_len)
def bytes_serialize(self):
cdef SerializeResult serialize_res
try:
serialize_res = self.bytes_serialize_c()
return serialize_res.ptr[:serialize_res.size]
finally:
free(serialize_res.ptr)
# @hash.setter
# def hash(self, value):
# if not isinstance(value, str):
@ -222,7 +289,7 @@ cdef class Blockchain:
def create_genesis_block(self):
cdef Block *block = new Block(
self._index,
datetime.datetime(2025, 12, 1, 12, 0, 0).timestamp(),
int(datetime.datetime(2025, 12, 1, 12, 0, 0).timestamp()),
0,
"Genesis Block".encode("UTF-8"),
"0".encode("UTF-8"),
@ -242,7 +309,7 @@ cdef class Blockchain:
cdef Block *block = new Block(
new_idx,
datetime.datetime(2025, 12, 1, 12, 0, 0).timestamp(),
int(datetime.datetime(2025, 12, 1, 12, 0, 0).timestamp()),
0,
data.encode("UTF-8"),
prev_hash,