Skip to content

Commit

Permalink
rearrange for release / mock deploys (#110)
Browse files Browse the repository at this point in the history
* rearrange for mock deploys

* buildweb

* buildweb

* clean

* finalize

* clean

* force gh pages build

* clean

* Create CNAME

* gardening

* gardening

* style

* fix command

* demo

* Move cid (#112)

* fix CID utils for lock location
move CID utils to app
lib uses release pack

* update output

Co-authored-by: stobiewan <[email protected]>

* clean

* trace walk

* dont overwrite dmap with mock dmap

* Remove ethers from main (#118)

* use RPC calls in place of ethers in main.js

* add address to dmap facade

Co-authored-by: stobiewan <[email protected]>

* Remove Ethers Dependencies (#117)

* very rough utils file; replace BigNumber, toHexString, and hexZeroPad in dmap.js

* no typescript; replace BigNumber, toHexString, hexZeroPad

* replace keccak256 with base js-sha3 wrapper for strings

* remove dependency on ethers abi encoder

* homegrown calldata for funcs with bytes32 args; no more ethers for dmap

* clean up utils file

* consolidate

* consolidate

* fix tests for combined utils (#119)

Co-authored-by: stobiewan <[email protected]>

* cut ipfs http client (#120)

Co-authored-by: stobiewan <[email protected]>

* use infura if no node and no window.ethereum (#121)

Co-authored-by: stobiewan <[email protected]>

* cut buffer and first half of dependencies (#122)

Co-authored-by: stobiewan <[email protected]>

* readme

* clean walk output

* include address in page

Co-authored-by: stobiewan <[email protected]>
Co-authored-by: stobiewan <[email protected]>
Co-authored-by: dmfxyz <[email protected]>
  • Loading branch information
4 people authored May 16, 2022
1 parent 5d9510a commit a7f7833
Show file tree
Hide file tree
Showing 19 changed files with 2,757 additions and 44,101 deletions.
191 changes: 140 additions & 51 deletions dmap.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
const kek = require('js-sha3')
const ebnf = require('ebnf')
const ethers = require('ethers')
const multiformats = require('multiformats')

const pack = require('./pack/premap.dpack.json')
const artifact = require('./pack/Dmap.json')
const pack = require('./pack/dmap.json')
const artifact = require('./pack/ipfs/Dmap.json')

const abi = artifact.abi
const dmap_i = new ethers.utils.Interface(abi)
const dmap_address = pack.objects.dmap.address

const fail =s=> { throw new Error(s) }
const need =(b,s)=> b || fail(s)

const coder = ethers.utils.defaultAbiCoder
const keccak256 = ethers.utils.keccak256
const prefLenIndex = 2

module.exports = lib = {}

lib.address = dmap_address
Expand Down Expand Up @@ -43,8 +36,8 @@ lib.parse =s=> {
}

lib.get = async (dmap, slot) => {
const nextslot = ethers.utils.hexZeroPad(
ethers.BigNumber.from(slot).add(1).toHexString(), 32
const nextslot = hexZeroPad(
hexlify(BigInt(slot) + BigInt(1)), 32
)
let meta, data
await Promise.all(
Expand All @@ -53,28 +46,24 @@ lib.get = async (dmap, slot) => {
dmap.provider.getStorageAt(dmap.address, nextslot)
]
).then(res => [meta, data] = res)
const resdata = dmap_i.encodeFunctionResult("get", [meta, data])
const res = dmap_i.decodeFunctionResult("get", resdata)
return res
return [meta, data]
}

lib.getByZoneAndName = async (dmap, zone, name) => {
const slot = keccak256(coder.encode(["address", "bytes32"], [zone, name]))
const slot = keccak256(encodeZoneAndName(zone, name));
return lib.get(dmap, slot)
}

lib.set = async (dmap, name, meta, data) => {
const calldata = dmap_i.encodeFunctionData("set", [name, meta, data])
const calldata = encodeFunctionCallBytes32Args("set(bytes32,bytes32,bytes32)", [name, meta, data])
return dmap.signer.sendTransaction({to: dmap.address, data: calldata})
}

const slotabi = ["function slot(bytes32 s) external view returns (bytes32)"]
const slot_i = new ethers.utils.Interface(slotabi)
// const slotabi = ["function slot(bytes32 s) external view returns (bytes32)"]
// const slot_i = new ethers.utils.Interface(slotabi)
lib.slot = async (dmap, slot) => {
const val = await dmap.provider.getStorageAt(dmap.address, slot)
const resdata = slot_i.encodeFunctionResult("slot", [val])
const res = slot_i.decodeFunctionResult("slot", resdata)
return res[0]
return val
}


Expand All @@ -87,47 +76,147 @@ lib.walk = async (dmap, path) => {
if (zone === '0x' + '00'.repeat(20)) {
fail(`zero register`)
}
const fullname = '0x' + Buffer.from(step.name).toString('hex') + '00'.repeat(32-step.name.length);
const fullname = '0x' + lib._strToHex(step.name) + '00'.repeat(32-step.name.length);
[meta, data] = await lib.getByZoneAndName(dmap, zone, fullname)
if (step.locked) {
need(ctx.locked, `Encountered ':' in unlocked subpath`)
need((Buffer.from(meta.slice(2), 'hex')[31] & lib.FLAG_LOCK) !== 0, `Entry is not locked`)
need((lib._hexToArrayBuffer(meta)[31] & lib.FLAG_LOCK) !== 0, `Entry is not locked`)
ctx.locked = true
}
ctx.locked = step.locked
}
return {meta, data}
}

lib.prepareCID = (cidStr, lock) => {
const cid = multiformats.CID.parse(cidStr)
need(cid.multihash.size <= 32, `Hash exceeds 256 bits`)
const prefixLen = cid.byteLength - cid.multihash.size
const meta = new Uint8Array(32).fill(0)
const data = new Uint8Array(32).fill(0)

data.set(cid.bytes.slice(-cid.multihash.size), 32 - cid.multihash.size)
meta.set(cid.bytes.slice(0, prefixLen), 32 - prefixLen)
if (lock) meta[0] |= lib.FLAG_LOCK
meta[prefLenIndex] = prefixLen
return [meta, data]
lib.walk2 = async (dmap, path) => {
if ( path.length > 0 && ![':', '.'].includes(path.charAt(0))) path = ':' + path
let [meta, data] = await lib.get(dmap, '0x' + '00'.repeat(32))
let ctx = {locked: path.charAt(0) === ':'}
const trace = [[meta,data]]
for (const step of lib.parse(path)) {
zone = data.slice(0, 21 * 2)
if (zone === '0x' + '00'.repeat(20)) {
fail(`zero register`)
}
const fullname = '0x' + lib._strToHex(step.name) + '00'.repeat(32-step.name.length);
[meta, data] = await lib.getByZoneAndName(dmap, zone, fullname)
trace.push([meta,data])
if (step.locked) {
need(ctx.locked, `Encountered ':' in unlocked subpath`)
need((lib._hexToArrayBuffer(meta)[31] & lib.FLAG_LOCK) !== 0, `Entry is not locked`)
ctx.locked = true
}
ctx.locked = step.locked
}
return trace
}

lib.unpackCID = (metaStr, dataStr) => {
const meta = Buffer.from(metaStr.slice(2), 'hex')
const data = Buffer.from(dataStr.slice(2), 'hex')
const prefixLen = meta[prefLenIndex]
const specs = multiformats.CID.inspectBytes(meta.slice(-prefixLen))
const hashLen = specs.digestSize
const cidBytes = new Uint8Array(prefixLen + hashLen)

cidBytes.set(meta.slice(-prefixLen), 0)
cidBytes.set(data.slice(32 - hashLen), prefixLen)
const cid = multiformats.CID.decode(cidBytes)
return cid.toString()
lib._hexToArrayBuffer = hex => {
const bytes = []
for (let c = 2; c < hex.length; c += 2)
bytes.push(parseInt(hex.slice(c, c + 2), 16))
return new Uint8Array(bytes)
}

lib.readCID = async (dmap, path) => {
const packed = await lib.walk(dmap, path)
return lib.unpackCID(packed.meta, packed.data)
lib._strToHex = str => {
let codes = str.split('').map(c => c.charCodeAt(0))
return codes.map(c => c.toString(16)).join('')
}

// GLOBAL TODO: !DMFXYZ! error and bounds checking for inputs
const HexCharacters = "0123456789abcdef";

function hexZeroPad(value, length) {
if (typeof(value) !== "string") {
value = hexlify(value);
}

if (value.length > 2 * length + 2) {
throw "Value too big"
}

while (value.length < 2 * length + 2) {
value = "0x0" + value.substring(2);
}

return value;
}

function hexlify(value) {

if (typeof(value) === "number") {
let hex = "";
while (value) {
hex = HexCharacters[value & 0xf] + hex;
value = Math.floor(value / 16); // can bitshift instead
}

if (hex.length) {
if (hex.length % 2) {
hex = "0" + hex;
}
return "0x" + hex;
}

return "0x00";
}

if (typeof(value) === "bigint") {
value = value.toString(16);
if (value.length % 2) {
return ("0x0" + value);
}
return "0x" + value;
}

if (typeof(value) === 'string') {
return lib._strToHex(value);
}
}

// Assumes value is a hex encoded string for now, or already a byte array
function keccak256(value) {

if (typeof(value) == "string") {
return "0x" + kek.keccak256(new Uint8Array(_toBytes(value)));
}
// add back in prefix and return as unsigned 1byte int array
return "0x" + kek.keccak256(value);
}

function encodeZoneAndName(zone, name) {
// zone should be an address, start by zero-padding 12 bytes
let params = '0x' + '00'.repeat(12);
if (zone.length == 0) {
params = params + '00'.repeat(20);
} else {
params = params + zone.slice(2); // assume has leading 0x, prob shouldn't do this
}
if (name.length == 0 || name == null) {
params = params + '00'.repeat(32);
} else if (typeof(name) == 'object') {
params = params + name.toString('hex');
} else {
// if already a hex string, just drop the 0x
params = params + name.slice(2);
}
return params;
}

function encodeFunctionCallBytes32Args(signature, args) {
// calculate function selector as first 4 bytes of hashed signature
// keccak256 returns a string, so we take the first 10 characters
let data = keccak256(signature).slice(0, 10)
for (arg of args) {
typeof arg == 'object' ? data += arg.toString('hex') : data += arg.slice(2)
}
return data;

}

function _toBytes(value) {
if (typeof(value) == 'string') {
return lib._hexToArrayBuffer(value)
}
return value
}
1 change: 1 addition & 0 deletions docs/CNAME
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dmap.sh
Loading

0 comments on commit a7f7833

Please sign in to comment.