Files
grin-web-wallet/scripts/slate_kernel.js
2024-12-20 18:08:44 -08:00

1060 lines
28 KiB
JavaScript
Executable File

// Use strict
"use strict";
// Classes
// Slate kernel class
class SlateKernel {
// Public
// Constructor
constructor(serializedSlateKernelOrFeatures, slateOrFee, lockHeightOrIsMainnet, relativeHeight = Slate.NO_RELATIVE_HEIGHT, excess = SlateKernel.ZERO_EXCESS, excessSignature = SlateKernel.ZERO_EXCESS_SIGNATURE) {
// Reset
this.reset();
// Check if a binary serialized slate kernel is provided
if(serializedSlateKernelOrFeatures instanceof BitReader === true) {
// Get serialized slate kernel
var serializedSlateKernel = serializedSlateKernelOrFeatures;
// Get slate
var slate = slateOrFee;
// Get is mainnet
var isMainnet = lockHeightOrIsMainnet;
// Unserialize the serialized slate kernel
this.unserialize(serializedSlateKernel, slate, isMainnet);
}
// Otherwise check if a serialized slate kernel is provided
else if(Object.isObject(serializedSlateKernelOrFeatures) === true) {
// Get serialized slate kernel
var serializedSlateKernel = serializedSlateKernelOrFeatures;
// Get slate
var slate = slateOrFee;
// Get is mainnet
var isMainnet = lockHeightOrIsMainnet;
// Unserialize the serialized slate kernel
this.unserialize(serializedSlateKernel, slate, isMainnet);
}
// Otherwise check if arguments are provided
else if(typeof serializedSlateKernelOrFeatures === "number") {
// Get features
var features = serializedSlateKernelOrFeatures;
// Get fee
var fee = slateOrFee;
// Get lock height
var lockHeight = lockHeightOrIsMainnet;
// Set features to provided features
this.features = features;
// Set fee to provided fee
this.fee = fee;
// Set lock height to provided lock height
this.lockHeight = lockHeight;
// Set relative height to provided relative height
this.relativeHeight = relativeHeight;
// Set excess to provided excess
this.excess = excess;
// Set excess signature to provided excess signature
this.excessSignature = excessSignature;
// Check if complete
if(this.isComplete() === true) {
// Check if excess signature failed to be verified
if(this.verifyExcessSignature() === false) {
// Throw error
throw "Unsupported kernel.";
}
}
}
// Otherwise
else {
// Throw error
throw "Unsupported kernel.";
}
}
// Serialize
serialize(slateOrVersion, bitWriter) {
// Get slate version
var slateVersion = (slateOrVersion instanceof Slate === true) ? slateOrVersion.getVersion() : slateOrVersion;
// Check slate's version
switch((slateVersion instanceof BigNumber === true) ? slateVersion.toFixed() : slateVersion) {
// Version two and three
case Slate.VERSION_TWO.toFixed():
case Slate.VERSION_THREE.toFixed():
// Create serialized slate kernel
var serializedSlateKernel = {
// Features
"features": SlateKernel.featuresToText(this.getFeatures()),
// Excess signature
"excess_sig": Common.toHexString(this.getExcessSignature()),
// Excess
"excess": Common.toHexString(this.getExcess())
};
// Check features
switch(this.getFeatures()) {
// Coinbase features
case SlateKernel.COINBASE_FEATURES:
// Set serialized slate kernel's fee to zero
serializedSlateKernel["fee"] = (new BigNumber(0)).toFixed();
// Set serialized slate kernel's lock height to no lock height
serializedSlateKernel["lock_height"] = Slate.NO_LOCK_HEIGHT.toFixed();
// Break
break;
// Plain features
case SlateKernel.PLAIN_FEATURES:
// Set serialized slate kernel's fee to fee
serializedSlateKernel["fee"] = this.getFee().toFixed();
// Set serialized slate kernel's lock height to no lock height
serializedSlateKernel["lock_height"] = Slate.NO_LOCK_HEIGHT.toFixed();
// Break
break;
// Height locked features
case SlateKernel.HEIGHT_LOCKED_FEATURES:
// Set serialized slate kernel's fee to fee
serializedSlateKernel["fee"] = this.getFee().toFixed();
// Set serialized slate kernel's lock height to lock height
serializedSlateKernel["lock_height"] = this.getLockHeight().toFixed();
// Break
break;
// No recent duplicate features
case SlateKernel.NO_RECENT_DUPLICATE_FEATURES:
// Set serialized slate kernel's fee to fee
serializedSlateKernel["fee"] = this.getFee().toFixed();
// Set serialized slate kernel's relative height to relative height
serializedSlateKernel["relative_height"] = this.getRelativeHeight().toFixed();
// Break
break;
}
// Return serialized slate kernel
return serializedSlateKernel;
// Version Slatepack
case Slate.VERSION_SLATEPACK:
// Try
try {
// Check features
switch(this.getFeatures()) {
// Plain features
case SlateKernel.PLAIN_FEATURES:
// Write fee
Slate.compactUint64(this.getFee(), true, bitWriter);
// Break
break;
// Default
default:
// Throw error
throw "Unsupported features.";
}
// Write excess
bitWriter.setBytes(this.getExcess());
// Write excess signature
bitWriter.setBytes(this.getExcessSignature());
}
// Catch errors
catch(error) {
// Throw error
throw "Unsupported kernel.";
}
// Break
break;
// Default
default:
// Throw error
throw "Unsupported slate version.";
}
}
// Get transaction
getTransaction() {
// Create transaction
var transaction = {
// Excess signature
"excess_sig": Common.toHexString(this.getExcessSignature()),
// Excess
"excess": Common.toHexString(this.getExcess())
};
// Check features
switch(this.getFeatures()) {
// Coinbase features
case SlateKernel.COINBASE_FEATURES:
// Set transaction's features
transaction["features"] = {
// Feature
[SlateKernel.featuresToText(this.getFeatures())]: {}
};
// Break
break;
// Plain features
case SlateKernel.PLAIN_FEATURES:
// Set transaction's features
transaction["features"] = {
// Feature
[SlateKernel.featuresToText(this.getFeatures())]: {
// Fee
"fee": this.getFee()
}
};
// Break
break;
// Height locked features
case SlateKernel.HEIGHT_LOCKED_FEATURES:
// Set transaction's features
transaction["features"] = {
// Feature
[SlateKernel.featuresToText(this.getFeatures())]: {
// Fee
"fee": this.getFee(),
// Lock height
"lock_height": this.getLockHeight()
}
};
// Break
break;
// No recent duplicate features
case SlateKernel.NO_RECENT_DUPLICATE_FEATURES:
// Set transaction's features
transaction["features"] = {
// Feature
[SlateKernel.featuresToText(this.getFeatures())]: {
// Fee
"fee": this.getFee(),
// Relative height
"relative_height": this.getRelativeHeight()
}
};
// Break
break;
}
// Return transaction
return transaction;
}
// Get features
getFeatures() {
// Return features
return this.features;
}
// Get fee
getFee() {
// Return fee
return this.fee;
}
// Get lock height
getLockHeight() {
// Return lock height
return this.lockHeight;
}
// Relative height
getRelativeHeight() {
// Return relative height
return this.relativeHeight;
}
// Get excess signature
getExcessSignature() {
// Return excess signature
return this.excessSignature;
}
// Set excess signature
setExcessSignature(excessSignature) {
// Set excess signature
this.excessSignature = excessSignature;
// Check if complete
if(this.isComplete() === true) {
// Check if excess signature failed to be verified
if(this.verifyExcessSignature() === false) {
// Return false
return false;
}
}
// Return true
return true;
}
// Get excess
getExcess() {
// Return excess
return this.excess;
}
// Set excess
setExcess(excess) {
// Set excess
this.excess = excess;
}
// Is plain
isPlain() {
// Return if features is plain
return this.getFeatures() === SlateKernel.PLAIN_FEATURES;
}
// Is coinbase
isCoinbase() {
// Return if features is coinbase
return this.getFeatures() === SlateKernel.COINBASE_FEATURES;
}
// Is height locked
isHeightLocked() {
// Return if features is height locked
return this.getFeatures() === SlateKernel.HEIGHT_LOCKED_FEATURES;
}
// Is no recent duplicate
isNoRecentDuplicate() {
// Return if features is no recent duplicate
return this.getFeatures() === SlateKernel.NO_RECENT_DUPLICATE_FEATURES;
}
// Get hash
getHash() {
// Check features
switch(this.getFeatures()) {
// Coinbase features
case SlateKernel.COINBASE_FEATURES:
// Return hash
return new Hash([
// Features
new Uint8Array([this.getFeatures()]),
// Zero fee
(new BigNumber(0)).toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT64),
// No lock height
Slate.NO_LOCK_HEIGHT.toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT64),
// Excess
this.getExcess(),
// Excess signature
this.getExcessSignature()
]);
// Plain features
case SlateKernel.PLAIN_FEATURES:
// Return hash
return new Hash([
// Features
new Uint8Array([this.getFeatures()]),
// Fee
this.getFee().toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT64),
// No lock height
Slate.NO_LOCK_HEIGHT.toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT64),
// Excess
this.getExcess(),
// Excess signature
this.getExcessSignature()
]);
// Height locked features
case SlateKernel.HEIGHT_LOCKED_FEATURES:
// Return hash
return new Hash([
// Features
new Uint8Array([this.getFeatures()]),
// Fee
this.getFee().toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT64),
// Lock height
this.getLockHeight().toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT64),
// Excess
this.getExcess(),
// Excess signature
this.getExcessSignature()
]);
// No recent duplicate features
case SlateKernel.NO_RECENT_DUPLICATE_FEATURES:
// Return hash
return new Hash([
// Features
new Uint8Array([this.getFeatures()]),
// Fee
this.getFee().toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT64),
// Relative height
this.getRelativeHeight().toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT64),
// Excess
this.getExcess(),
// Excess signature
this.getExcessSignature()
]);
}
}
// Is equal to
isEqualTo(slateKernel) {
// Check if features aren't equal
if(this.getFeatures() !== slateKernel.getFeatures())
// Return false
return false;
// Check if feed aren't equal
if(this.getFee().isEqualTo(slateKernel.getFee()) === false)
// Return false
return false;
// Check if lock heights aren't equal
if(this.getLockHeight().isEqualTo(slateKernel.getLockHeight()) === false)
// Return false
return false;
// Check if relative heights aren't equal
if((this.getRelativeHeight() === Slate.NO_RELATIVE_HEIGHT && slateKernel.getRelativeHeight() !== Slate.NO_RELATIVE_HEIGHT) || (this.getRelativeHeight() !== Slate.NO_RELATIVE_HEIGHT && slateKernel.getRelativeHeight() === Slate.NO_RELATIVE_HEIGHT) || (this.getRelativeHeight() !== Slate.NO_RELATIVE_HEIGHT && this.getRelativeHeight().isEqualTo(slateKernel.getRelativeHeight()) === false))
// Return false
return false;
// Check if excess signatures aren't equal
if(Common.arraysAreEqual(this.getExcessSignature(), slateKernel.getExcessSignature()) === false)
// Return false
return false;
// Check if excesses aren't equal
if(Common.arraysAreEqual(this.getExcess(), slateKernel.getExcess()) === false)
// Return false
return false;
// Return true
return true;
}
// Is complete
isComplete() {
// Return if excess signature exists exists
return Common.arraysAreEqual(this.getExcessSignature(), SlateKernel.ZERO_EXCESS_SIGNATURE) === false;
}
// Signature message
static signatureMessage(features, fee = new BigNumber(0), lockHeight = Slate.NO_LOCK_HEIGHT, relativeHeight = Slate.NO_RELATIVE_HEIGHT) {
// Check features
switch(features) {
// Coinbase features
case SlateKernel.COINBASE_FEATURES:
// Set data to features
var data = new Uint8Array([features]);
// Break
break;
// Plain features
case SlateKernel.PLAIN_FEATURES:
// Set data to features followed by the fee
var data = Common.mergeArrays([
// Features
new Uint8Array([features]),
// Fee
fee.toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT64)
]);
// Break
break;
// Height locked features
case SlateKernel.HEIGHT_LOCKED_FEATURES:
// Set data to features followed by the fee followed by the lock height
var data = Common.mergeArrays([
// Features
new Uint8Array([features]),
// Fee
fee.toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT64),
// Lock height
lockHeight.toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT64)
]);
// Break
break;
// No recent duplicate features
case SlateKernel.NO_RECENT_DUPLICATE_FEATURES:
// Set data to features followed by the fee followed by the relative height
var data = Common.mergeArrays([
// Features
new Uint8Array([features]),
// Fee
fee.toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT64),
// Relative height
relativeHeight.toBytes(BigNumber.BIG_ENDIAN, Common.BYTES_IN_A_UINT16)
]);
// Break
break;
}
// Return creating a signature message from the data
return Crypto.signatureMessage(data);
}
// Features to text
static featuresToText(features) {
// Check features
switch(features) {
// Plain features
case SlateKernel.PLAIN_FEATURES:
// Return plain text
return "Plain";
// Coinbase features
case SlateKernel.COINBASE_FEATURES:
// Return coinbase text
return "Coinbase";
// Height locked features
case SlateKernel.HEIGHT_LOCKED_FEATURES:
// Return height locked text
return "HeightLocked";
// No recent duplicate features
case SlateKernel.NO_RECENT_DUPLICATE_FEATURES:
// Return no recent duplicate text
return "NoRecentDuplicate";
// Default
default:
// Return unsupported features
return SlateKernel.UNSUPPORTED_FEATURES;
}
}
// Plain features
static get PLAIN_FEATURES() {
// Return plain features
return 0;
}
// Coinbase features
static get COINBASE_FEATURES() {
// Return coinbase features
return SlateKernel.PLAIN_FEATURES + 1;
}
// Height locked features
static get HEIGHT_LOCKED_FEATURES() {
// Return height locked features
return SlateKernel.COINBASE_FEATURES + 1;
}
// No recent duplicate features
static get NO_RECENT_DUPLICATE_FEATURES() {
// Return height locked features
return SlateKernel.HEIGHT_LOCKED_FEATURES + 1;
}
// Zero excess
static get ZERO_EXCESS() {
// No zero excess
return (new Uint8Array(Crypto.COMMIT_LENGTH)).fill(0);
}
// Zero excess signature
static get ZERO_EXCESS_SIGNATURE() {
// No zero excess signature
return (new Uint8Array(Crypto.SINGLE_SIGNER_SIGNATURE_LENGTH)).fill(0);
}
// Transaction features length
static get TRANSACTION_FEATURES_LENGTH() {
// Return transaction features length
return 1;
}
// Private
// Reset
reset() {
// Set features to plain features
this.features = SlateKernel.PLAIN_FEATURES;
// Set fee to minimum fee
this.fee = new BigNumber(Slate.MINIMUM_FEE);
// Set lock height to no lock height
this.lockHeight = Slate.NO_LOCK_HEIGHT;
// Set relative height to no relative height
this.relativeHeight = Slate.NO_RELATIVE_HEIGHT;
// Set excess signature to zero signature
this.excessSignature = SlateKernel.ZERO_EXCESS_SIGNATURE;
// Set excess to zero excess
this.excess = SlateKernel.ZERO_EXCESS;
}
// Unserialize
unserialize(serializedSlateKernel, slate, isMainnet) {
// Check slate's version
switch((slate.getVersion() instanceof BigNumber === true) ? slate.getVersion().toFixed() : slate.getVersion()) {
// Version two and three
case Slate.VERSION_TWO.toFixed():
case Slate.VERSION_THREE.toFixed():
// Check if serialized slate kernel's features isn't supported
if("features" in serializedSlateKernel === false || SlateKernel.textToFeatures(serializedSlateKernel["features"]) === SlateKernel.UNSUPPORTED_FEATURES || SlateKernel.textToFeatures(serializedSlateKernel["features"]) === SlateKernel.COINBASE_FEATURES) {
// Throw error
throw "Unsupported kernel.";
}
// Set features to serialized slate kernel's features
this.features = SlateKernel.textToFeatures(serializedSlateKernel["features"]);
// Check features
switch(this.getFeatures()) {
// Plain features
case SlateKernel.PLAIN_FEATURES:
// Check if serialized slate kernel's fee isn't supported
if("fee" in serializedSlateKernel === false || (Common.isNumberString(serializedSlateKernel["fee"]) === false && serializedSlateKernel["fee"] instanceof BigNumber === false) || (new BigNumber(serializedSlateKernel["fee"])).isInteger() === false || (new BigNumber(serializedSlateKernel["fee"])).isLessThan(Slate.MINIMUM_FEE) === true) {
// Throw error
throw "Unsupported kernel.";
}
// Set fee to serialized slate kernel's fee
this.fee = new BigNumber(serializedSlateKernel["fee"]);
// Break
break;
// Height locked features
case SlateKernel.HEIGHT_LOCKED_FEATURES:
// Check if serialized slate kernel's fee isn't supported
if("fee" in serializedSlateKernel === false || (Common.isNumberString(serializedSlateKernel["fee"]) === false && serializedSlateKernel["fee"] instanceof BigNumber === false) || (new BigNumber(serializedSlateKernel["fee"])).isInteger() === false || (new BigNumber(serializedSlateKernel["fee"])).isLessThan(Slate.MINIMUM_FEE) === true) {
// Throw error
throw "Unsupported kernel.";
}
// Set fee to serialized slate kernel's fee
this.fee = new BigNumber(serializedSlateKernel["fee"]);
// Check if serialized slate kernel's lock height isn't supported
if("lock_height" in serializedSlateKernel === false || (Common.isNumberString(serializedSlateKernel["lock_height"]) === false && serializedSlateKernel["lock_height"] instanceof BigNumber === false) || (new BigNumber(serializedSlateKernel["lock_height"])).isInteger() === false || (new BigNumber(serializedSlateKernel["lock_height"])).isLessThan(Slate.NO_LOCK_HEIGHT) === true) {
// Throw error
throw "Unsupported kernel.";
}
// Set lock height to serialized slate kernel's lock height
this.lockHeight = new BigNumber(serializedSlateKernel["lock_height"]);
// Break
break;
// No recent duplicate features
case SlateKernel.NO_RECENT_DUPLICATE_FEATURES:
// Check if no recent duplicate kernels isn't enabled
if(Consensus.isNoRecentDuplicateKernelsEnabled(isMainnet) === false) {
// Throw error
throw "Unsupported kernel.";
}
// Check if serialized slate kernel's fee isn't supported
if("fee" in serializedSlateKernel === false || (Common.isNumberString(serializedSlateKernel["fee"]) === false && serializedSlateKernel["fee"] instanceof BigNumber === false) || (new BigNumber(serializedSlateKernel["fee"])).isInteger() === false || (new BigNumber(serializedSlateKernel["fee"])).isLessThan(Slate.MINIMUM_FEE) === true) {
// Throw error
throw "Unsupported kernel.";
}
// Set fee to serialized slate kernel's fee
this.fee = new BigNumber(serializedSlateKernel["fee"]);
// Check if serialized slate kernel's relative height isn't supported
if("relative_height" in serializedSlateKernel === false || (Common.isNumberString(serializedSlateKernel["relative_height"]) === false && serializedSlateKernel["relative_height"] instanceof BigNumber === false) || (new BigNumber(serializedSlateKernel["relative_height"])).isInteger() === false || (new BigNumber(serializedSlateKernel["relative_height"])).isLessThan(SlateKernel.MINIMUM_RECENT_HEIGHT) === true || (new BigNumber(serializedSlateKernel["relative_height"])).isGreaterThan(SlateKernel.MAXIMUM_RECENT_HEIGHT) === true) {
// Throw error
throw "Unsupported kernel.";
}
// Set relative height to serialized slate kernel's relative height
this.relativeHeight = new BigNumber(serializedSlateKernel["relative_height"]);
// Break
break;
}
// Check if serialized slate kernel's excess signature isn't supported
if("excess_sig" in serializedSlateKernel === false || Common.isHexString(serializedSlateKernel["excess_sig"]) === false || Secp256k1Zkp.isValidSingleSignerSignature(Common.fromHexString(serializedSlateKernel["excess_sig"])) !== true) {
// Throw error
throw "Unsupported kernel.";
}
// Set excess signature to serialized slate kernel's excess signature
this.excessSignature = Secp256k1Zkp.singleSignerSignatureFromData(Common.fromHexString(serializedSlateKernel["excess_sig"]));
// Check if excess signature isn't a valid signature
if(this.getExcessSignature() === Secp256k1Zkp.OPERATION_FAILED) {
// Throw error
throw "Unsupported kernel.";
}
// Check if serialized slate kernel's excess isn't supported
if("excess" in serializedSlateKernel === false || Common.isHexString(serializedSlateKernel["excess"]) === false || Common.hexStringLength(serializedSlateKernel["excess"]) !== Crypto.COMMIT_LENGTH || (Common.arraysAreEqual(Common.fromHexString(serializedSlateKernel["excess"]), SlateKernel.ZERO_EXCESS) === false && Secp256k1Zkp.isValidCommit(Common.fromHexString(serializedSlateKernel["excess"])) !== true)) {
// Throw error
throw "Unsupported kernel.";
}
// Set excess to serialized slate kernel's excess
this.excess = Common.fromHexString(serializedSlateKernel["excess"]);
// Break
break;
// Version Slatepack
case Slate.VERSION_SLATEPACK:
// Get bit reader
var bitReader = serializedSlateKernel;
// Try
try {
// Set fee to serialized slate kernel's fee
this.fee = Slate.uncompactUint64(bitReader, true);
// Check if serialized slate kernel's fee isn't supported
if(this.getFee().isLessThan(Slate.MINIMUM_FEE) === true) {
// Throw error
throw "Unsupported kernel.";
}
// Set excess to serialized slate kernel's excess
this.excess = bitReader.getBytes(Crypto.COMMIT_LENGTH);
// Check if excess is invalid
if(Common.arraysAreEqual(this.excess, SlateKernel.ZERO_EXCESS) === false && Secp256k1Zkp.isValidCommit(this.excess) !== true) {
// Throw error
throw "Unsupported kernel.";
}
// Check if serialized slate kernel's excess signature is invalid
var excessSignature = bitReader.getBytes(Crypto.SINGLE_SIGNER_SIGNATURE_LENGTH);
if(Secp256k1Zkp.isValidSingleSignerSignature(excessSignature) !== true) {
// Throw error
throw "Unsupported kernel.";
}
// Set excess signature to serialized slate kernel's excess signature
this.excessSignature = Secp256k1Zkp.singleSignerSignatureFromData(excessSignature);
// Check if excess signature isn't a valid signature
if(this.getExcessSignature() === Secp256k1Zkp.OPERATION_FAILED) {
// Throw error
throw "Unsupported kernel.";
}
}
// Catch errors
catch(error) {
// Throw error
throw "Unsupported kernel.";
}
// Break
break;
// Default
default:
// Throw error
throw "Unsupported kernel.";
}
// Check if complete
if(this.isComplete() === true) {
// Check if excess signature failed to be verified
if(this.verifyExcessSignature() === false) {
// Throw error
throw "Unsupported kernel.";
}
}
}
// Verify excess signature
verifyExcessSignature() {
// Try
try {
// Get message to sign
var messageToSign = SlateKernel.signatureMessage(this.getFeatures(), this.getFee(), this.getLockHeight(), this.getRelativeHeight());
}
// Catch errors
catch(error) {
// Return false
return false;
}
// Create a public key from the excess
var publicKey = Secp256k1Zkp.pedersenCommitToPublicKey(this.getExcess());
// Check if the public key isn't a valid public key
if(publicKey === Secp256k1Zkp.OPERATION_FAILED) {
// Return false
return false;
}
// Check if partial signature doesn't verify the excess
if(Secp256k1Zkp.verifySingleSignerSignature(this.getExcessSignature(), messageToSign, Secp256k1Zkp.NO_PUBLIC_NONCE, publicKey, publicKey, false) !== true) {
// Return false
return false;
}
// Return true
return true;
}
// Text to feature
static textToFeatures(text) {
// Check text
switch(text) {
// Plain text
case "Plain":
// Return plain features
return SlateKernel.PLAIN_FEATURES;
// Coinbase text
case "Coinbase":
// Return coinbase features
return SlateKernel.COINBASE_FEATURES;
// Height locked text
case "HeightLocked":
// Return height locked features
return SlateKernel.HEIGHT_LOCKED_FEATURES;
// No recent duplicate text
case "NoRecentDuplicate":
// Return no recent duplicate features
return SlateKernel.NO_RECENT_DUPLICATE_FEATURES;
// Default
default:
// Return unsupported features
return SlateKernel.UNSUPPORTED_FEATURES;
}
}
// Unsupported features
static get UNSUPPORTED_FEATURES() {
// Return unsupported features
return SlateKernel.NO_RECENT_DUPLICATE_FEATURES + 1;
}
// Minimum recent height
static get MINIMUM_RECENT_HEIGHT() {
// Return minimum recent height
return 1;
}
// Maximum recent height
static get MAXIMUM_RECENT_HEIGHT() {
// Return maximum recent height
return Consensus.BLOCK_HEIGHT_WEEK;
}
}
// Main function
// Set global object's slate kernel
globalThis["SlateKernel"] = SlateKernel;