@btc-vision/btc-runtime
Version:
Bitcoin Smart Contract Runtime
114 lines (93 loc) • 3.46 kB
text/typescript
import { Blockchain } from '../env';
import { encodePointerUnknownLength } from '../math/abi';
import { BytesWriter } from '../buffer/BytesWriter';
import { u256 } from '@btc-vision/as-bignum/assembly';
import { Address } from '../types/Address';
export class Nested<T> {
public parentKey: Uint8Array;
public pointer: u16;
constructor(
parent: Uint8Array,
pointer: u16,
) {
this.pointer = pointer;
this.parentKey = parent;
}
public set(key: Uint8Array, value: T): this {
const keyHash: Uint8Array = this.getKeyHash(key);
Blockchain.setStorageAt(keyHash, this.from(value));
return this;
}
public get(key: Uint8Array): T {
const keyHash: Uint8Array = this.getKeyHash(key);
return this.toValue(Blockchain.getStorageAt(keyHash));
}
public has(key: Uint8Array): bool {
const mergedKey: Uint8Array = this.getKeyHash(key);
return Blockchain.hasStorageAt(mergedKey);
}
public delete(_key: Uint8Array): bool {
throw new Error('Method not implemented.');
}
public clear(): void {
throw new Error('Clear method not implemented.');
}
/**
* Converts raw bytes from storage into type T.
*/
private toValue(value: Uint8Array): T {
// Check T's compile-time type ID
if (idof<T>() == idof<u256>()) {
// We know T is u256
return changetype<T>(u256.fromUint8ArrayBE(value));
} else if (idof<T>() == idof<Uint8Array>()) {
// We know T is Uint8Array
return changetype<T>(value);
} else if (idof<T>() == idof<Address>()) {
// We know T is Address
return changetype<T>(value);
} else if (isInteger<T>()) {
// For a simple integer, just pull out the first byte
return value[0] as T;
} else if (isString<T>()) {
// T is a string
return changetype<T>(String.UTF8.decode(value.buffer));
}
throw new Error('Unsupported type');
}
/**
* Converts type T into raw bytes for storage.
*/
private from(value: T): Uint8Array {
if (idof<T>() == idof<u256>()) {
// Cast T to u256, then convert to bytes
return changetype<u256>(value).toUint8Array(true);
} else if (idof<T>() == idof<Uint8Array>()) {
// Just return it
return changetype<Uint8Array>(value);
} else if (idof<T>() == idof<Address>()) {
// Address is already bytes
return changetype<Uint8Array>(value);
} else if (isInteger<T>()) {
const writer = new BytesWriter(sizeof<T>());
writer.write<T>(value);
return writer.getBuffer();
} else if (isString<T>()) {
const str = changetype<string>(value);
return Uint8Array.wrap(String.UTF8.encode(str));
}
throw new Error('Unsupported type');
}
private getKeyHash(key: Uint8Array): Uint8Array {
const writer: BytesWriter = new BytesWriter(key.byteLength + this.parentKey.byteLength);
writer.writeBytes(this.parentKey);
writer.writeBytes(key);
return this.encodePointer(writer);
}
private encodePointer(writer: BytesWriter): Uint8Array {
return encodePointerUnknownLength(this.pointer, writer.getBuffer());
}
}