Draft Inverse Bloom Filter

This commit is contained in:
Jim Hamill
2025-01-20 07:47:07 +00:00
parent d6a04f4350
commit 1aebc6da42
21 changed files with 1285 additions and 381 deletions
+54 -34
View File
@@ -1,10 +1,9 @@
import { Bytes } from './bytes.js';
import {
Base58AddressFormatVersion,
addressContentsToLockingBytecode,
lockingBytecodeToAddressContents,
isHex,
binToHex,
hexToBin,
decodeBase58Address,
decodeCashAddress,
disassembleBytecodeBCH,
@@ -27,6 +26,25 @@ export const DEFAULT_ADDRESS_PREFIXES = [
/**
* Address Entity.
*
* @example
*
* ```ts
* // Import our primitives.
* import { Address } from '@xocash/primitives';
*
* // Instantiate from a CashAddr (Legacy Addresses also supported).
* const address = Address.from('bitcoincash:qpmlpygrtzznznhgsl4c245xgmglpfh0vgcqns0q0r');
*
* // Convert to Locking Bytecode.
* console.log(address.toLockscriptBytes());
*
* // Convert to Legacy Address.
* console.log(address.toLegacy());
*
* // Convert to Token Address.
* console.log(address.toTokenAddress());
* ```
*/
export class Address {
protected readonly addressContents: KnownAddressTypeContents;
@@ -81,7 +99,7 @@ export class Address {
.find((result) => typeof result !== 'string');
if (!decodeResult) {
throw new Error('Invalid address format');
throw new Error(`Cannot decode address '${cashAddr}': ${decodeResult}`);
}
// Define the encode type in advance.
@@ -98,7 +116,9 @@ export class Address {
encodeType = decodeResult.payload.length === 32 ? 'P2SH32' : 'P2SH20';
break;
default:
throw new Error(`Unsupported address type: ${decodeResult.type}`);
throw new Error(
`Cannot decode address '${cashAddr}': Unsupported address type '${decodeResult.type}'`,
);
}
// Return new instance of address.
@@ -120,7 +140,9 @@ export class Address {
// If a string is returned, this indicates an error...
if (typeof decodeResult === 'string') {
throw new Error(decodeResult);
throw new Error(
`Cannot decode address '${legacyAddress}': ${decodeResult}`,
);
}
// Define the encode type in advance.
@@ -137,7 +159,9 @@ export class Address {
encodeType = 'P2SH20';
break;
default:
throw new Error(`Unsupported address type: ${decodeResult.version}`);
throw new Error(
`Cannot decode address '${legacyAddress}': Unsupported address type '${decodeResult.version}'`,
);
}
return new this({ payload: decodeResult.payload, type: encodeType });
@@ -146,23 +170,37 @@ export class Address {
/**
* Instantiate an address from Contract Bytecode.
*
* @param contractBytes The contract bytecode
* @param bytes The contract bytecode
*
* @throws {Error} If address cannot be instantiated from Contract Bytecode.
*
* @returns {Address} Instance of Address.
*/
public static fromRedeemScript(
contractBytes: Uint8Array,
bytes: Uint8Array,
type: 'P2SH20' | 'P2SH32' = 'P2SH32',
): Address {
// Do an initial SHA256 on the Contract Bytes.
let payload = sha256.hash(contractBytes);
let payload = sha256.hash(bytes);
if (type === 'P2SH20') {
// Make sure length is 20 bytes.
if (bytes.length !== 20) {
throw new Error(
`Invalid payload length. Received '${bytes.length}', expected 20 for P2SH20`,
);
}
// RIPEMD160 the SHA256 hash.
payload = ripemd160.hash(payload);
} else if (type === 'P2SH32') {
// Make sure length is 32 bytes.
if (bytes.length !== 32) {
throw new Error(
`Invalid payload length. Received '${bytes.length}', expected 32 for P2SH20`,
);
}
// SHA256 Hash the SHA256 hash a seconr time.
payload = sha256.hash(payload);
}
@@ -184,14 +222,8 @@ export class Address {
hex: string,
type: 'P2SH20' | 'P2SH32' = 'P2SH32',
): Address {
if (!isHex(hex)) {
throw new Error('Invalid hex');
}
const contractBytecode = hexToBin(hex);
// Return a new instance of address.
return this.fromRedeemScript(contractBytecode, type);
return this.fromRedeemScript(Bytes.fromHex(hex).toBytes(), type);
}
/**
@@ -224,13 +256,7 @@ export class Address {
* @returns {Address} Instance of Address.
*/
public static fromLockscriptHex(hex: string): Address {
if (!isHex(hex)) {
throw new Error('Invalid hex');
}
const lockScriptBytes = hexToBin(hex);
return this.fromLockscriptBytes(lockScriptBytes);
return this.fromLockscriptBytes(Bytes.fromHex(hex).toBytes());
}
/**
@@ -243,7 +269,7 @@ export class Address {
*
* @returns {Address} Instance of Address.
*/
public static fromHash160(
public static fromHash160Bytes(
hash160: Uint8Array,
type: AddressType = 'P2PKH',
): Address {
@@ -271,13 +297,7 @@ export class Address {
hash160Hex: string,
type: AddressType = 'P2PKH',
): Address {
if (!isHex(hash160Hex)) {
throw new Error('Invalid hex');
}
const hash160Bytes = hexToBin(hash160Hex);
return this.fromHash160(hash160Bytes, type);
return this.fromHash160Bytes(Bytes.fromHex(hash160Hex).toBytes(), type);
}
/**
@@ -373,7 +393,7 @@ export class Address {
* @returns {Uint8Array} The Hash160 of this address.
*/
public toHash160Hex(): string {
return binToHex(this.addressContents.payload);
return Bytes.fromBytes(this.addressContents.payload).toHex();
}
/**
@@ -496,7 +516,7 @@ export class Address {
* @returns {Uint8Array} The lockscript as a hex string.
*/
public toLockscriptHex(): string {
return binToHex(this.toLockscriptBytes());
return Bytes.fromBytes(this.toLockscriptBytes()).toHex();
}
/**