Skip to content

Commit 7b246aa

Browse files
committed
[ADD] agregando todos los archivos
0 parents  commit 7b246aa

File tree

17 files changed

+1751
-0
lines changed

17 files changed

+1751
-0
lines changed

.gitignore

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Logs
2+
logs
3+
*.log
4+
npm-debug.log*
5+
yarn-debug.log*
6+
yarn-error.log*
7+
lerna-debug.log*
8+
.pnpm-debug.log*
9+
10+
# Diagnostic reports (https://nodejs.org/api/report.html)
11+
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
12+
13+
# Runtime data
14+
pids
15+
*.pid
16+
*.seed
17+
*.pid.lock
18+
19+
# Directory for instrumented libs generated by jscoverage/JSCover
20+
lib-cov
21+
22+
# Coverage directory used by tools like istanbul
23+
coverage
24+
*.lcov
25+
26+
# nyc test coverage
27+
.nyc_output
28+
29+
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
30+
.grunt
31+
32+
# Bower dependency directory (https://bower.io/)
33+
bower_components
34+
35+
# node-waf configuration
36+
.lock-wscript
37+
38+
# Compiled binary addons (https://nodejs.org/api/addons.html)
39+
build/Release
40+
41+
# Dependency directories
42+
node_modules/
43+
jspm_packages/
44+
45+
# Snowpack dependency directory (https://snowpack.dev/)
46+
web_modules/
47+
48+
# TypeScript cache
49+
*.tsbuildinfo
50+
51+
# Optional npm cache directory
52+
.npm
53+
54+
# Optional eslint cache
55+
.eslintcache
56+
57+
# Optional stylelint cache
58+
.stylelintcache
59+
60+
# Microbundle cache
61+
.rpt2_cache/
62+
.rts2_cache_cjs/
63+
.rts2_cache_es/
64+
.rts2_cache_umd/
65+
66+
# Optional REPL history
67+
.node_repl_history
68+
69+
# Output of 'npm pack'
70+
*.tgz
71+
72+
# Yarn Integrity file
73+
.yarn-integrity
74+
75+
# dotenv environment variable files
76+
.env
77+
.env.development.local
78+
.env.test.local
79+
.env.production.local
80+
.env.local
81+
82+
# parcel-bundler cache (https://parceljs.org/)
83+
.cache
84+
.parcel-cache
85+
86+
# Next.js build output
87+
.next
88+
out
89+
90+
# Nuxt.js build / generate output
91+
.nuxt
92+
dist
93+
94+
# Gatsby files
95+
.cache/
96+
# Comment in the public line in if your project uses Gatsby and not Next.js
97+
# https://nextjs.org/blog/next-9-1#public-directory-support
98+
# public
99+
100+
# vuepress build output
101+
.vuepress/dist
102+
103+
# vuepress v2.x temp and cache directory
104+
.temp
105+
.cache
106+
107+
# Docusaurus cache and generated files
108+
.docusaurus
109+
110+
# Serverless directories
111+
.serverless/
112+
113+
# FuseBox cache
114+
.fusebox/
115+
116+
# DynamoDB Local files
117+
.dynamodb/
118+
119+
# TernJS port file
120+
.tern-port
121+
122+
# Stores VSCode versions used for testing VSCode extensions
123+
.vscode-test
124+
125+
# yarn v2
126+
.yarn/cache
127+
.yarn/unplugged
128+
.yarn/build-state.yml
129+
.yarn/install-state.gz
130+
.pnp.*
131+
132+
build
133+
db

package.json

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"name": "demo-ethereumvirtualmachine",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"build": "tsc",
8+
"pvm": "ts-node ./src/cli"
9+
},
10+
"keywords": [],
11+
"author": "",
12+
"license": "MIT",
13+
"devDependencies": {
14+
"ts-node": "^10.9.1",
15+
"typescript": "^4.9.5"
16+
},
17+
"dependencies": {
18+
"@ethereumjs/trie": "^5.0.4",
19+
"@ethereumjs/util": "^8.0.5",
20+
"@ethersproject/bytes": "^5.7.0",
21+
"abstract-level": "^1.0.3",
22+
"command-line-interface": "^5.0.0",
23+
"level": "^8.0.0",
24+
"memory-level": "^1.0.0"
25+
}
26+
}

src/classes/execution/errors.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
class InvalidBytecode extends Error {}
2+
3+
class InvalidProgramCounterIndex extends Error {}
4+
5+
class UnknownOpcode extends Error {}
6+
7+
class InvalidJump extends Error {}
8+
9+
class OutofGas extends Error {}
10+
11+
export { InvalidBytecode, InvalidProgramCounterIndex, UnknownOpcode, InvalidJump, OutofGas };

src/classes/execution/index.ts

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
import { Trie } from "@ethereumjs/trie";
2+
import { isHexString, arrayify, hexlify } from "@ethersproject/bytes";
3+
import Opcodes from "../../opcodes";
4+
import Instruction from "../instruction";
5+
import Memory from "../memory";
6+
import Stack from "../stack";
7+
import {
8+
InvalidBytecode,
9+
InvalidJump,
10+
InvalidProgramCounterIndex,
11+
OutofGas,
12+
UnknownOpcode,
13+
} from "./errors";
14+
15+
class ExecutionContext {
16+
private readonly code: Uint8Array;
17+
public stack: Stack;
18+
public memory: Memory;
19+
private pc: number;
20+
private stopped: boolean;
21+
public output: bigint = BigInt(0);
22+
public storage: Trie;
23+
public readonly originalStorage: Trie;
24+
public gas: bigint;
25+
26+
constructor(code: string, gas: bigint, storage: Trie) {
27+
if (!isHexString(code) || code.length % 2 !== 0)
28+
throw new InvalidBytecode();
29+
this.code = arrayify(code);
30+
this.stack = new Stack();
31+
this.memory = new Memory();
32+
this.pc = 0;
33+
this.stopped = false;
34+
this.storage = storage;
35+
this.originalStorage = storage.copy()
36+
this.gas = gas;
37+
}
38+
39+
public stop(): void {
40+
this.stopped = true;
41+
}
42+
43+
public async run() {
44+
while (!this.stopped) {
45+
const currentPc = this.pc;
46+
47+
const instruction = this.fetchInstruction();
48+
const currentAvailableGas = this.gas;
49+
const { gasFee } = await instruction.execute(this);
50+
51+
console.info(`${instruction.name}\t @pc=${currentPc}\t gas=${currentAvailableGas}\t const=${gasFee}`);
52+
53+
this.memory.print();
54+
this.stack.print();
55+
console.log("");
56+
}
57+
58+
console.log("Output:\t", hexlify(this.output));
59+
console.log("Root:\t", hexlify(this.storage.root()));
60+
}
61+
62+
public useGas(fee: number) {
63+
this.gas -= BigInt(fee);
64+
if(this.gas < 0) throw new OutofGas();
65+
}
66+
67+
private fetchInstruction(): Instruction {
68+
if (this.pc >= this.code.length) return Opcodes[0];
69+
70+
if (this.pc < 0) throw new InvalidProgramCounterIndex();
71+
72+
const opcode = this.readBytesFromCode(1);
73+
74+
const instruction = Opcodes[Number(opcode)];
75+
76+
if (!instruction) throw new UnknownOpcode();
77+
78+
return instruction;
79+
}
80+
81+
public readBytesFromCode(bytes = 1): bigint {
82+
const hexValues = this.code.slice(this.pc, this.pc + bytes); // Recortar un pedazo the tamaño bytes
83+
const values = BigInt(hexlify(hexValues));
84+
85+
this.pc += bytes;
86+
87+
return values;
88+
}
89+
90+
public jump(destination: bigint): void {
91+
if (!this.isValidJump(destination)) throw new InvalidJump();
92+
this.pc = Number(destination);
93+
}
94+
95+
private isValidJump(destination: bigint): boolean {
96+
return this.code[Number(destination) - 1] === Opcodes[0x5b].opcode;
97+
}
98+
}
99+
100+
export default ExecutionContext;

src/classes/instruction/errors.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
class NotImplementedError extends Error {}
2+
3+
export { NotImplementedError };

src/classes/instruction/index.ts

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import ExecutionContext from "../execution";
2+
import { NotImplementedError } from "./errors";
3+
4+
interface ExecutionResult {
5+
gasFee: number;
6+
}
7+
8+
class Instruction {
9+
public readonly opcode: number;
10+
public readonly name: string;
11+
public readonly execute: (ctx: ExecutionContext) => Promise<ExecutionResult>;
12+
13+
constructor(
14+
opcode: number,
15+
name: string,
16+
gasFee: ((ctx: ExecutionContext) => Promise<number>) | number,
17+
execute: (ctx: ExecutionContext) => void
18+
) {
19+
this.opcode = opcode;
20+
this.name = name;
21+
this.execute = async (ctx: ExecutionContext) => {
22+
const gasFeeFunction =
23+
typeof gasFee == "function" ? gasFee : () => gasFee;
24+
25+
const effectGasFee = await gasFeeFunction(ctx);
26+
ctx.useGas(effectGasFee); //primero usemos el gas
27+
28+
await execute(ctx);
29+
30+
return {
31+
gasFee: effectGasFee,
32+
};
33+
};
34+
}
35+
}
36+
37+
export default Instruction;

src/classes/memory/errors.ts

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
class OffsetValueError extends Error {
2+
constructor(offset: bigint, value: bigint) {
3+
super(
4+
`Memory access with offset: ${offset} and value ${value} is not valid`
5+
);
6+
}
7+
}
8+
9+
class InvalidMemoryOffset extends OffsetValueError {}
10+
11+
class InvalidMemoryValue extends OffsetValueError {}
12+
13+
export { OffsetValueError, InvalidMemoryOffset, InvalidMemoryValue };

src/classes/memory/index.ts

+56
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { hexlify } from "@ethersproject/bytes";
2+
import { MAX_UINT256 } from "../../constants";
3+
import { InvalidMemoryOffset, InvalidMemoryValue } from "./errors";
4+
5+
class Memory {
6+
private memory: bigint[];
7+
8+
constructor() {
9+
this.memory = [];
10+
}
11+
12+
public store(offset: bigint, value: bigint): void {
13+
if (offset < 0 || offset > MAX_UINT256)
14+
throw new InvalidMemoryOffset(offset, value);
15+
16+
if (value < 0 || value > MAX_UINT256)
17+
throw new InvalidMemoryValue(offset, value);
18+
19+
this.memory[Number(offset)] = value;
20+
}
21+
22+
public load(offset: bigint): bigint {
23+
if (offset < 0 || offset > MAX_UINT256)
24+
throw new InvalidMemoryOffset(offset, BigInt(0));
25+
26+
if (offset >= this.memory.length) return BigInt(0);
27+
28+
return this.memory[Number(offset)];
29+
}
30+
31+
public memoryExpansionCost(offset: bigint): bigint {
32+
const newMemoryCost = this.memoryCost(offset + BigInt(32));
33+
const lastMemoryCost = this.memoryCost(BigInt(this.memory.length));
34+
35+
const cost = newMemoryCost - lastMemoryCost;
36+
37+
return cost < 0 ? BigInt(0) : cost;
38+
}
39+
40+
private memoryCost(memorySize: bigint): bigint {
41+
const memoryByteSize = memorySize * BigInt(32);
42+
const memorySizeWord = (memoryByteSize + BigInt(31)) / BigInt(32);
43+
const memoryCost =
44+
memorySizeWord ** BigInt(2) / BigInt(512) + BigInt(3) * memorySizeWord;
45+
return memoryCost;
46+
}
47+
48+
public print(): void {
49+
console.log(
50+
`Memory:\t`,
51+
this.memory.map((value) => hexlify(value))
52+
);
53+
}
54+
}
55+
56+
export default Memory;

0 commit comments

Comments
 (0)