Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leicoin pos v2 #24

Merged
merged 6 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "leicoin-node",
"version": "0.5.4",
"version": "0.5.5",
"description": "",
"exports": "./src/index.ts",
"type": "module",
Expand Down
2 changes: 2 additions & 0 deletions scripts/compile/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type PlatformArg = keyof typeof Platforms | "auto";
class CompilerBuilder {

public sourcemap = true;
public minify = true;
public entrypoint = "./src/index.ts";
public outfile = "./build/bin/leicoin-node";
public env: NodeJS.ProcessEnv = {};
Expand All @@ -31,6 +32,7 @@ class CompilerBuilder {
return [
this.baseCommand,
(this.sourcemap ? " --sourcemap" : ""),
(this.minify ? " --minify" : ""),
this.entrypoint,
"--outfile", this.outfile,
...Object.entries(this.env).map(([key, value]) => `--define "Bun.env.${key}='${value}'"`)
Expand Down
2 changes: 1 addition & 1 deletion src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ class CLI {
readonly pos = new Logger("POS", "#0000ff", this.log);
readonly minter = new Logger("MinterClient", "#00ffff", this.log);
readonly api = new Logger("API", "#c724b1", this.log);
readonly data = new Logger("Data", "#1711df", this.log);
readonly data = new Logger("Data", "#FFAD00", this.log);
readonly cmd = new Logger("CLI", "#ffffff", this.log);
readonly leicoin_net = new Logger("LeiCoinNet", "#f47fff", this.log);

Expand Down
2 changes: 1 addition & 1 deletion src/leicoin-net/pipelines/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export default class TransactionPipeline extends Pipeline {

async receive(type: LNPPX, data: Uint) {

const transaction = DataUtils.createInstanceFromJSON(Transaction, data);
const transaction = Transaction.fromDecodedHex(data) as Transaction;

if (!(transaction.txid.toHex() in mempool.transactions)) {

Expand Down
12 changes: 11 additions & 1 deletion src/objects/block.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,17 @@ export class Block {
const data = returnData.data;

if (data && data.version.eq(0)) {
const block = DataUtils.createInstanceFromJSON(Block, data);
const block = new Block(
data.index,
data.slotIndex,
data.hash,
data.previousHash,
data.timestamp,
null as any,
data.signature,
data.transactions,
data.version
);

if (withMinterAddress) {
block.minter = AddressHex.fromSignature(block.calculateHash(), data.signature);
Expand Down
12 changes: 11 additions & 1 deletion src/objects/transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,17 @@ export class Transaction {
if (data && data.version.eq(0)) {

data.senderAddress = null
const instance = DataUtils.createInstanceFromJSON(Transaction, data);
const instance = new Transaction(
data.txid,
null as any,
data.recipientAddress,
data.amount,
data.nonce,
data.timestamp,
data.input,
data.signature,
data.version
)

if (withSenderAddress) {
instance.senderAddress = AddressHex.fromSignature(data.txid, data.signature);
Expand Down
8 changes: 5 additions & 3 deletions src/pos/execution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import cli from "../cli/cli.js";
import { type Block } from "../objects/block.js";
import { Blockchain } from "../storage/blockchain.js";
import mempool from "../storage/mempool.js";
import { VCodes } from "../verification/codes.js";
import { type BlockValidationResult } from "../verification/index.js";


Expand All @@ -10,14 +11,15 @@ export class Execution {
static async executeBlock(block: Block, validationresult: BlockValidationResult) {

if (validationresult.status !== 12000) {
cli.leicoin_net.info(`Block with hash ${block.hash.toHex()} is invalid. Validation Result: ${JSON.stringify(validationresult)}`);
cli.pos.info(`Block with hash ${block.hash.toHex()} is invalid. Validation Result: Code: ${validationresult.status} Message: ${VCodes[validationresult.status]}`);
return;
}

const { targetChain, parentChain } = validationresult;

if (targetChain !== parentChain) { // New fork if targetChain is different from parentChain
//Blockchain.createFork(validationresult.forkchain, validationresult.forkparent, block);
await Blockchain.createFork(validationresult.targetChain, validationresult.parentChain, block);
cli.pos.info(`New Fork ${targetChain} created from ${parentChain} at block ${block.index.toBigInt()}`);
}

Blockchain.chains[targetChain].blocks.addBlock(block);
Expand All @@ -33,7 +35,7 @@ export class Execution {
await Blockchain.wallets.adjustWalletsByBlock(block);
}

cli.leicoin_net.success(`Block on Slot ${block.slotIndex.toBigInt()} with hash ${block.hash.toHex()} has been validated, executed and added to Blockchain.`);
cli.pos.success(`Block on Slot ${block.slotIndex.toBigInt()} with hash ${block.hash.toHex()} has been validated, executed and added to Blockchain. Chain: ${targetChain}`);
}

}
Expand Down
70 changes: 32 additions & 38 deletions src/storage/blockchain.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import BCUtils from "./blockchainUtils.js";
import Chainstate from "./chainstate.js";
import Chain from "./chain.js";
import utils from "../utils/index.js";
import cli from "../cli/cli.js";
import { BasicModuleLike } from "../utils/dataUtils.js";
import { type Block } from "../objects/block.js";

export class Blockchain implements BasicModuleLike<typeof Blockchain> {
public static initialized = false;
Expand Down Expand Up @@ -37,45 +37,39 @@ export class Blockchain implements BasicModuleLike<typeof Blockchain> {
BCUtils.ensureDirectoryExists('/forks', "main");
}

// public async createFork(name: string, parentChain: string, latestBlock: Block) {
// const parentLatestBlock = this.chainstate.getLatestBlockInfo(parentChain);
static async createFork(targetChainID: string, parentChainID: string, baseBlock: Block) {

const parentLatestBlock = this.chainstate.getLatestBlock(parentChainID) as Block;

// if (parentChain !== "main") {
// fs.cpSync(BCUtils.getBlockchainDataFilePath("", parentChain), BCUtils.getBlockchainDataFilePath("", name), { recursive: true });
// fs.unlinkSync(BCUtils.getBlockchainDataFilePath(`/blocks/${parentLatestBlock.index}.lcb`, name));
// }
if (parentChainID !== "main") {
BCUtils.copyChain(parentChainID, targetChainID);
}

// const forkChain = new Chain(name);
// this.chains[name] = forkChain;
// this.chainstate.setChainState({
// parent: {
// name: parentChain
// },
// // base: {
// // index: latestBlock.index,
// // hash: latestBlock.hash,
// // },
// base: latestBlock,
// // previousBlockInfo: {
// // index: latestBlock.index.sub(1),
// // hash: latestBlock.previousHash
// // },
// previousBlockInfo: this.blocks.getBlock(latestBlock.index.sub(1).toHex()).data as Block,
// latestBlockInfo: latestBlock
// });

// for (const transactionData of parentLatestBlock.transactions) {
// const senderWallet = await this.chains[parentChain].wallets.getWallet(transactionData.senderAddress);
// const recipientWallet = await this.chains[parentChain].wallets.getWallet(transactionData.recipientAddress);

// senderWallet.adjustNonce(-1);
// senderWallet.addMoney(transactionData.amount);
// recipientWallet.subtractMoneyIFPossible(transactionData.amount);

// await forkChain.wallets.setWallet(senderWallet);
// await forkChain.wallets.setWallet(recipientWallet);
// }
// }
const forkChain = new Chain(targetChainID);
await forkChain.waitAllinit();

this.chains[targetChainID] = forkChain;
const parentChain = this.chains[parentChainID];

for (const blockIndex = parentLatestBlock.index.clone(); blockIndex.gte(baseBlock.index); blockIndex.isub(1)) {

for (const transactionData of (parentChain.blocks.getBlock(blockIndex).data as Block).transactions) {

const senderWallet = await parentChain.wallets.getWallet(transactionData.senderAddress);
const recipientWallet = await parentChain.wallets.getWallet(transactionData.recipientAddress);

senderWallet.adjustNonce(-1);
senderWallet.addMoney(transactionData.amount);
recipientWallet.subtractMoneyIFPossible(transactionData.amount);

await forkChain.wallets.setWallet(senderWallet);
await forkChain.wallets.setWallet(recipientWallet);
}

forkChain.blocks.deleteBlock(blockIndex, true);
}

}

// public transferForkToMain(fork: string) {

Expand Down
41 changes: 32 additions & 9 deletions src/storage/blockchainUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import path from "path";
import fs from "fs";
import cli from "../cli/cli.js";
import Utils from "../utils/index.js";
import { Uint } from "../binary/uint.js";
import { Uint, type Uint64 } from "../binary/uint.js";
import readline from "readline";

class BCUtils {
Expand All @@ -19,28 +19,47 @@ class BCUtils {
return path.join(Utils.procCWD, this.getRelativePath(subpath, fork));
}

static readFile(filePath: string, fork: string) {
return new Uint(fs.readFileSync(this.getBlockchainDataFilePath(filePath, fork), null));
}

static existsPath(fileORDirPath: string, fork: string) {
return fs.existsSync(this.getBlockchainDataFilePath(fileORDirPath, fork));
}


static readFile(filePath: string, fork: string) {
return new Uint(fs.readFileSync(this.getBlockchainDataFilePath(filePath, fork), null));
}

static writeFile(filePath: string, fork: string, data: Uint) {
return fs.writeFileSync(this.getBlockchainDataFilePath(filePath, fork), data.getRaw());
}

static delFile(filePath: string, fork: string) {
return fs.unlinkSync(this.getBlockchainDataFilePath(filePath, fork));
}


static mkDir(directoryPath: string, fork: string) {
return fs.mkdirSync(this.getBlockchainDataFilePath(directoryPath, fork), { recursive: true });
}

static rmDir(directoryPath: string, fork: string) {
return fs.rmdirSync(this.getBlockchainDataFilePath(directoryPath, fork), { recursive: true });
}


static copyChain(sourceChain: string, targetChain: string) {
fs.cpSync(this.getBlockchainDataFilePath(sourceChain), this.getBlockchainDataFilePath(targetChain), { recursive: true });
}


// Function to ensure the existence of a directory
static ensureDirectoryExists(directoryPath: string, fork: string) {
static ensureDirectoryExists(directoryPath: string, fork: string, silent?: boolean) {
try {
if (!this.existsPath(directoryPath, fork)) {
this.mkDir(directoryPath, fork);
cli.data.info(`Directory ${this.getRelativePath(directoryPath, fork)} was created because it was missing.`);

if ((fork === "main" && silent !== true) || silent === false) {
cli.data.info(`Directory ${this.getRelativePath(directoryPath, fork)} was created because it was missing.`);
}
}
} catch (err: any) {
cli.data.error(`Error ensuring the existence of a directory at ${this.getRelativePath(directoryPath, fork)}: ${err.stack}`);
Expand All @@ -51,13 +70,17 @@ class BCUtils {
static ensureFileExists(
filePath: string,
fork: string,
content: Uint
content: Uint,
silent?: boolean
) {
try {
this.ensureDirectoryExists(path.dirname(filePath), fork)
if (!this.existsPath(filePath, fork)) {
this.writeFile(filePath, fork, content);
cli.data.info(`File ${this.getRelativePath(filePath, fork)} was created because it was missing.`);

if ((fork === "main" && silent !== true) || silent === false) {
cli.data.info(`File ${this.getRelativePath(filePath, fork)} was created because it was missing.`);
}
}

} catch (err: any) {
Expand Down
25 changes: 23 additions & 2 deletions src/storage/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export class BlockDB {
BCUtils.ensureDirectoryExists('/blocks', this.chain);
}

// Function to write a block
public addBlock(block: Block, overwrite = false) {
const blockIndex = block.index.toBigInt().toString();
try {
Expand All @@ -33,7 +32,6 @@ export class BlockDB {
}
}

// Function to read a block
public getBlock(index: Uint64 | string) {
const blockIndex = index instanceof Uint64 ? index.toBigInt().toString() : index;
try {
Expand All @@ -51,6 +49,29 @@ export class BlockDB {
}
}


/**
* WARNING: Deleting Blocks from a chain is risky and should be done with caution. Dont use this method unless you know what you are doing.
*/
public deleteBlock(index: Uint64 | string, silent = false) {
const blockIndex = index instanceof Uint64 ? index.toBigInt().toString() : index;
try {
const blockFilePath = `/blocks/${blockIndex}.lcb`;
if (BCUtils.existsPath(blockFilePath, this.chain)) {
BCUtils.delFile(blockFilePath, this.chain);
return {cb: CB.SUCCESS};
} else {
if (!silent) {
cli.data.error(`Cant Block ${blockIndex} in Chain: ${this.chain}. Block was not found.`);
}
return {cb: CB.NONE};
}
} catch (err: any) {
cli.data.error(`Error deleting block ${blockIndex}: ${err.stack}.`);
return {cb: CB.ERROR};
}
}

/*public getBlockInForks(index: Number, hash: String) {

const forksDirectory = BCUtils.getBlockchainDataFilePath('/forks/');
Expand Down
23 changes: 17 additions & 6 deletions src/storage/chainstate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ class ForkChainstateData {
const data = returnData.data;

if (data) {
const forkChainstateData = DataUtils.createInstanceFromJSON(ForkChainstateData, data);
const forkChainstateData = new ForkChainstateData(
data.stateHash,
data.parentChain,
data.base,
data.latestBlock
)

if (returnLength) {
return {data: forkChainstateData, length: returnData.length};
Expand Down Expand Up @@ -102,7 +107,10 @@ class ChainstateData {
const data = returnData.data;

if (data && data.version.eq(0)) {
return DataUtils.createInstanceFromJSON(ChainstateData, data);
return new ChainstateData(
data.chains,
data.version
)
}
} catch (err: any) {
cli.data.error(`Error loading ForkChainstateData from Decoded Hex: ${err.stack}`);
Expand Down Expand Up @@ -173,7 +181,7 @@ export class Chainstate {
return this.chainStateData.chains[id];
}

public getLatestBlock(chainID = "main"): Block | undefined {
public getLatestBlock(chainID = "main") {
return this.getChainState(chainID)?.latestBlock;
}

Expand Down Expand Up @@ -213,7 +221,8 @@ export class Chainstate {
let previousBlock: Block | null = null;

for (const chain of Object.values(this.getAllChainStates())) {
const chainPreviousBlock = Blockchain.blocks.getBlock(block.index.sub(1)).data;
const chainPreviousBlock = Blockchain.chains[chain.id].blocks.getBlock(block.index.sub(1)).data;

if (chainPreviousBlock?.hash.eq(block.previousHash)) {
parentChain = chain;
previousBlock = chainPreviousBlock;
Expand All @@ -224,7 +233,7 @@ export class Chainstate {
if (!parentChain || !previousBlock)
return { status: 12532 }; // Previous block not found

const targetBlock = Blockchain.blocks.getBlock(block.index).data;
const targetBlock = Blockchain.chains[parentChain.id].blocks.getBlock(block.index).data;

if (targetBlock) {
if (targetBlock?.hash.eq(block.hash))
Expand All @@ -237,4 +246,6 @@ export class Chainstate {

}

export default Chainstate;
export type { ForkChainstateData, ChainstateData };

export default Chainstate;
Loading