Skip to content
This repository has been archived by the owner on Feb 12, 2023. It is now read-only.

Commit

Permalink
Cell refs fixes and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
romanzaycev committed Jul 11, 2022
1 parent 9e76db3 commit ae1d27c
Show file tree
Hide file tree
Showing 4 changed files with 224 additions and 37 deletions.
1 change: 1 addition & 0 deletions src/Olifanton/Boc/BitString.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Olifanton\Boc;

use ajf\TypedArrays\ArrayBuffer;
use ajf\TypedArrays\Uint8Array;
use Brick\Math\BigInteger;
use Olifanton\Boc\Exceptions\BitStringException;
Expand Down
101 changes: 65 additions & 36 deletions src/Olifanton/Boc/Cell.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,18 @@
use Olifanton\Utils\Exceptions\CryptoException;
use function DeepCopy\deep_copy;

/**
* @property-read BitString $bits
* @property \ArrayObject $refs
*/
class Cell
{
private BitString $bits;

/**
* @var \ArrayObject<Cell>
* @var \ArrayObject
*/
private \ArrayObject $refs;
private \ArrayObject $_refs;

/**
* @var int[]
Expand Down Expand Up @@ -61,7 +65,7 @@ public static function oneFromBoc(string|Uint8Array $serializedBoc): Cell
public function __construct()
{
$this->bits = new BitString(1023);
$this->refs = new \ArrayObject();
$this->_refs = new \ArrayObject();
}

/**
Expand All @@ -75,7 +79,9 @@ public function writeCell(Cell $anotherCell): self
throw new CellException("Cell writing error: " . $e->getMessage(), $e->getCode(), $e);
}

$this->refs = array_merge($this->refs, $anotherCell->refs);
$this->_refs = new \ArrayObject(
array_merge($this->_refs->getArrayCopy(), $anotherCell->_refs->getArrayCopy())
);

return $this;
}
Expand All @@ -84,7 +90,7 @@ public function getMaxLevel(): int
{
$maxLevel = 0;

foreach ($this->refs as $ref) {
foreach ($this->_refs as $ref) {
$rMaxLevel = $ref->getMaxLevel();
$maxLevel = ($rMaxLevel > $maxLevel) ? $rMaxLevel : $maxLevel;
}
Expand All @@ -96,9 +102,14 @@ public function getMaxDepth(): int
{
$maxDepth = 0;

foreach ($this->refs as $ref) {
$rMaxDepth = $ref->getMaxDepth();
$maxDepth = ($rMaxDepth > $maxDepth) ? $rMaxDepth : $maxDepth;
if ($this->_refs->count() > 0) {
foreach ($this->_refs as $ref) {
/** @var Cell $ref */
$rMaxDepth = $ref->getMaxDepth();
$maxDepth = ($rMaxDepth > $maxDepth) ? $rMaxDepth : $maxDepth;
}

$maxDepth++;
}

return $maxDepth;
Expand All @@ -107,7 +118,7 @@ public function getMaxDepth(): int
public function getRefsDescriptor(): Uint8Array
{
return new Uint8Array([
count($this->refs) + (int)$this->isExotic * 8 + $this->getMaxLevel() * 32,
count($this->_refs) + (int)$this->isExotic * 8 + $this->getMaxLevel() * 32,
]);
}

Expand Down Expand Up @@ -150,9 +161,14 @@ public function getRepr(): Uint8Array
$this->getDataWithDescriptors(),
];

foreach ($this->refs as $ri => $ref) {
$reprArray[$ri + 1] = $ref->getMaxDepthAsArray();
$reprArray[$ri + 2] = $ref->hash();
foreach ($this->_refs as $ref) {
/** @var Cell $ref */
$reprArray[] = $ref->getMaxDepthAsArray();
}

foreach ($this->_refs as $ref) {
/** @var Cell $ref */
$reprArray[] = $ref->hash();
}

$x = $reprArray[0];
Expand All @@ -176,7 +192,7 @@ public function getBits(): BitString
*/
public function getRefs(): \ArrayObject
{
return $this->refs;
return $this->_refs;
}

/**
Expand All @@ -198,7 +214,7 @@ public function print(string $indent = ''): string
{
$s = $indent . 'x{' . $this->bits->toHex() . "}\n";

foreach ($this->refs as $ref) {
foreach ($this->_refs as $ref) {
$s .= $ref->print($indent . ' ');
}

Expand All @@ -210,16 +226,6 @@ public function isExplicitlyStoredHashes(): int
return 0;
}

private function getMaxDepthAsArray(): Uint8Array
{
$maxDepth = $this->getMaxDepth();
$d = new Uint8Array([0, 0]);
$d[0] = (int)floor($maxDepth / 256);
$d[1] = $maxDepth % 256;

return $d;
}

/**
* Create BoC Byte array
*
Expand Down Expand Up @@ -260,7 +266,7 @@ public function toBoc(bool $has_idx = true,
$sizeIndex[] = $full_size;
/** @var Cell $cell_ */
$cell_ = $cell_info[1];
$full_size = $full_size + $cell_->bocSerializationSize($cellsIndex, $s_bytes);
$full_size = $full_size + $cell_->bocSerializationSize($cellsIndex);
}

$offset_bits = strlen(decbin($full_size));
Expand Down Expand Up @@ -289,7 +295,7 @@ public function toBoc(bool $has_idx = true,
foreach ($topologicalOrder as $cell_info) {
/** @var Cell $cell_ */
$cell_ = $cell_info[1];
$refcell_ser = $cell_->serializeForBoc($sizeIndex, $s_bytes);
$refcell_ser = $cell_->serializeForBoc($cellsIndex);
$serialization->writeBytes($refcell_ser);
}

Expand All @@ -305,6 +311,29 @@ public function toBoc(bool $has_idx = true,
}
}

public function __get(string $name)
{
if ($name === "bits") {
return $this->getBits();
}

if ($name === "refs") {
return $this->getRefs();
}

throw new \InvalidArgumentException("Unknown property \"${name}\"");
}

private function getMaxDepthAsArray(): Uint8Array
{
$maxDepth = $this->getMaxDepth();
$d = new Uint8Array([0, 0]);
$d[0] = (int)floor($maxDepth / 256);
$d[1] = $maxDepth % 256;

return $d;
}

/**
* @param array<string, int> $cellsIndex
* @throws CellException
Expand All @@ -319,12 +348,12 @@ private function serializeForBoc(array $cellsIndex): Uint8Array
throw new CellException("Cell hashes explicit storing is not implemented");
}

foreach ($this->refs as $ref) {
foreach ($this->_refs as $ref) {
$refHash = $ref->hash();
$refIndexInt = $cellsIndex[Bytes::arrayToBytes($refHash)];
$refIndexHex = dechex($refIndexInt);

if ($refIndexHex % 2) {
if (strlen($refIndexHex) % 2) {
$refIndexHex = "0" . $refIndexHex;
}

Expand All @@ -346,7 +375,7 @@ private function serializeForBoc(array $cellsIndex): Uint8Array
/**
* @throws CellException
*/
private function bocSerializationSize(array $cellsIndex, int $refSize): int
private function bocSerializationSize(array $cellsIndex): int
{
return $this->serializeForBoc($cellsIndex)->length;
}
Expand Down Expand Up @@ -389,14 +418,14 @@ private static function deserializeBoc(string|Uint8Array $serializedBoc): array
for ($ci = $header["cells_num"] - 1; $ci >= 0; $ci--) {
$c = $cells_array[$ci];

for ($ri = 0; $ri < count($c->refs); $ri++) {
for ($ri = 0; $ri < count($c->refs_r); $ri++) {
$r = $c->refs_r[$ri];

if ($r < $ci) {
throw new CellException("Topological order is broken");
}

$c->refs[$ri] = $cells_array[$r];
$c->_refs[$ri] = $cells_array[$r];
}

$c->refs_r = [];
Expand Down Expand Up @@ -618,7 +647,7 @@ private static function treeWalk(Cell $cell,
if (isset($indexHashmap[$cellHash])) {
if ($parentHash) {
if ($indexHashmap[$parentHash] > $indexHashmap[$cellHash]) {
self::moveToEnd($topologicalOrderArray, $indexHashmap, $cellHash);
self::moveToEnd($indexHashmap, $topologicalOrderArray, $cellHash);
}
}

Expand All @@ -631,7 +660,7 @@ private static function treeWalk(Cell $cell,
$indexHashmap[$cellHash] = count($topologicalOrderArray);
$topologicalOrderArray[] = [$cellHash, $cell];

foreach ($cell->refs as $subCell) {
foreach ($cell->_refs as $subCell) {
$res = self::treeWalk($subCell, $topologicalOrderArray, $indexHashmap, $cellHash);
$topologicalOrderArray = $res["topologicalOrderArray"];
$indexHashmap = $res["indexHashmap"];
Expand All @@ -646,8 +675,8 @@ private static function treeWalk(Cell $cell,
/**
* @throws CellException
*/
private static function moveToEnd(array &$topologicalOrderArray,
array &$indexHashmap,
private static function moveToEnd(array &$indexHashmap,
array &$topologicalOrderArray,
string $target): void
{
$targetIndex = $indexHashmap[$target];
Expand All @@ -665,8 +694,8 @@ private static function moveToEnd(array &$topologicalOrderArray,
foreach ($data[1]->refs as $subCell) {
/** @var Cell $subCell */
self::moveToEnd(
$topologicalOrderArray,
$indexHashmap,
$topologicalOrderArray,
Bytes::arrayToBytes($subCell->hash()),
);
}
Expand Down
Loading

0 comments on commit ae1d27c

Please sign in to comment.