Skip to content

Commit

Permalink
(test/names): cutting short effort to handle decoding base58 in tests
Browse files Browse the repository at this point in the history
  • Loading branch information
benjaminbollen committed Apr 30, 2024
1 parent d82a290 commit d9b07ac
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 2 deletions.
82 changes: 82 additions & 0 deletions test/names/Base58Helper.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: AGPL-3.0-only
pragma solidity >=0.8.24;

import "forge-std/console.sol";

/**
* Helper contract to do the base58 decoding in solidity unit tests;
* this should only be used for tests, in production this conversion to bytes
* should be done off-chain with a proper library.
*/
contract Base58Decode {

function base58Decode(string memory source) public view returns (bytes memory) {
bytes memory bSource = bytes(source);
uint256 base = 58;
uint256 result = 0;
uint256 multi = 1;

// Mapping of base58 characters to their integer values
uint8[58] memory base58Map = [
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A,
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
];

// Adjust to ignore the "Qm" prefix if it exists and length is 34 bytes
uint256 startIndex = 0;
if (bSource.length == 46 && bSource[0] == 0x51 && bSource[1] == 0x6D) { // 'Q' == 0x51 and 'm' == 0x6D
startIndex = 2;
} else if (bSource.length != 44) {
revert("Invalid CIDv0 length for IPFS decoding.");
}

console.log("startIndex:", startIndex);
console.log("CIDv0 inside length:", bSource.length);

// for (uint256 i = startIndex; i < bSource.length; i++) {
// uint256 value = indexOf(uint8(bSource[i]), base58Map);
// result += value * multi;
// if (i )
// multi *= base;
// console.log("index:", i - startIndex + 1);
// console.log("charater:", uint8(bSource[i]), "value:", value);
// console.log("result:", result, "multi:", multi);
// }

uint256 j = 0;
for (uint256 i = bSource.length; i > startIndex; i--) {
uint256 value = indexOf(uint8(bSource[i - 1]), base58Map);
result += value * multi;
if (i > startIndex + 1) {
// skip the last iteration to avoid overflow
// 58^44 > 2^256 - 1
multi *= base;
console.log("iteration:", j++);
} else {
console.log("last iteration");
}
console.log("index:", bSource.length - i + 1);
console.log("charater:", uint8(bSource[i - 1]), "value:", value);
console.log("result:", result, "multi:", multi);
}

return toBytes(result);
}

function indexOf(uint8 char, uint8[58] memory map) private pure returns (uint256) {
for(uint i = 0; i < map.length; i++) {
if(map[i] == char) {
return i;
}
}
revert("Character not in base58 map.");
}

function toBytes(uint256 x) private pure returns (bytes memory b) {
b = new bytes(32);
assembly {
mstore(add(b, 32), x)
}
}
}
36 changes: 36 additions & 0 deletions test/names/MockNameRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,40 @@ import "../../src/names/NameRegistry.sol";

contract MockNameRegistry is NameRegistry {
constructor() NameRegistry(IHubV2(address(1))) {}

// External functions

function registerShortNameNoChecks() external {
_registerShortName();
}

function registerShortNameWithNonceNoChecks(uint256 _nonce) external {
_registerShortNameWithNonce(_nonce);
}

function registerCustomNameNoChecks(address _avatar, string calldata _name) external {
if (bytes(_name).length == 0) {
// if name is left empty, it will default to default name "Circles-<base58(short)Name>"
return;
}
if (!isValidName(_name)) {
revert CirclesNamesInvalidName(_avatar, _name, 0);
}
customNames[_avatar] = _name;
}

function registerCustomSymbolNoChecks(address _avatar, string calldata _symbol) external {
if (bytes(_symbol).length == 0) {
// if symbol is left empty, it will default to default symbol "CRC"
return;
}
if (!isValidSymbol(_symbol)) {
revert CirclesNamesInvalidName(_avatar, _symbol, 1);
}
customSymbols[_avatar] = _symbol;
}

function setCidV0DigestNoChecks(address _avatar, bytes32 _dicV0Digest) external {
_setCidV0Digest(_avatar, _dicV0Digest);
}
}
44 changes: 42 additions & 2 deletions test/names/NameRegistry.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,48 @@ pragma solidity >=0.8.24;
import {Test} from "forge-std/Test.sol";
import {StdCheats} from "forge-std/StdCheats.sol";
import "forge-std/console.sol";
import "../setup/HumanRegistration.sol";
import "./MockNameRegistry.sol";
import "./base58Helper.sol";

contract NamesTest is Test {
function setUp() public {}
contract NamesTest is Test, HumanRegistration, Base58Decode {
// Constants

// IPFS hash for Ubuntu 20.04, random CIDv0
string constant IPFS_CID_V0 = "QmPK1s3pNYLi9ERiq3BDxKa4XosgWwFRQUydHUtz4YgpqB";
// using https://cid.ipfs.tech/#QmPK1s3pNYLi9ERiq3BDxKa4XosgWwFRQUydHUtz4YgpqB
// this is the 32 bytes hash digest
bytes32 constant DECODED_UINT = 0x0E7071C59DF3B9454D1D18A15270AA36D54F89606A576DC621757AFD44AD1D2E;

// State variables

MockNameRegistry mockNameRegistry;

bytes32 cidBytes;

// Constructor

constructor() HumanRegistration(4) {}

// Setup

function setUp() public {
mockNameRegistry = new MockNameRegistry();
// Convert CIDv0 to bytes32 (should be done off-chain in production)
console.log("CIDv0 length", bytes(IPFS_CID_V0).length);
cidBytes = convertCidV0ToBytes32(IPFS_CID_V0);
}

// Tests

function testCidV0Digest() public {
mockNameRegistry.setCidV0DigestNoChecks(addresses[0], cidBytes);
}

// Helper functions

function convertCidV0ToBytes32(string memory _cidV0) internal view returns (bytes32) {
bytes memory decodedBytes = base58Decode(_cidV0);
console.log("CIDv0 length:", decodedBytes.length);
}
}

0 comments on commit d9b07ac

Please sign in to comment.