Зафиксировать все текущие изменения проекта

This commit is contained in:
AidarKC
2026-06-04 22:27:09 +04:00
parent 624557ebfd
commit 60049442f1
9 changed files with 1526 additions and 182 deletions
+153 -85
View File
@@ -1,6 +1,7 @@
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import {
ComputeBudgetProgram,
Ed25519Program,
PublicKey,
SYSVAR_INSTRUCTIONS_PUBKEY,
@@ -21,8 +22,10 @@ const BLOCK_TYPE_BLOCKCHAIN_REGISTRY = 3;
const BLOCK_TYPE_SERVER_PROFILE = 30;
const BLOCK_TYPE_ACCESS_SERVERS = 40;
const BLOCK_TYPE_TRUSTED_STATE = 50;
const BLOCK_TYPE_SESSIONS = 55;
const BLOCK_VERSION_0 = 0;
const BLOCKCHAIN_TYPE_MAIN_USER = 1;
const SESSIONS_MODE_MIXED = 1;
const LIMIT_STEP = 10_000n;
const START_BONUS_LIMIT = 100_000n;
@@ -32,6 +35,13 @@ const SHINE_PAYMENTS_PROGRAM_ID = new PublicKey(
);
const SHINE_PAYMENTS_INFLOW_VAULT_SEED = "shine_payments_inflow_vault";
type SessionRecord = {
sessionType: number;
sessionVersion: number;
sessionName: string;
sessionPubKey: PublicKey;
};
type MutableFields = {
deviceKey: PublicKey;
blockchainPublicKey: PublicKey;
@@ -42,10 +52,13 @@ type MutableFields = {
lastBlockSignature: Buffer;
arweaveTxId: string;
isServer: boolean;
serverKey: PublicKey;
addressFormatType: number;
addressFormatVersion: number;
serverAddress: string;
syncServers: string[];
accessServers: string[];
sessionsMode: number;
sessions: SessionRecord[];
trustedCount: number;
};
@@ -69,10 +82,13 @@ type UnsignedRecord = {
arweaveTxId: string;
};
isServer: boolean;
serverKey: PublicKey;
addressFormatType: number;
addressFormatVersion: number;
serverAddress: string;
syncServers: string[];
accessServers: string[];
sessionsMode: number;
sessions: SessionRecord[];
trustedCount: number;
};
@@ -98,7 +114,7 @@ function serializeUnsignedRecord(r: UnsignedRecord): Buffer {
out.push(MAGIC);
out.push(Buffer.from([FORMAT_MAJOR]));
out.push(Buffer.from([FORMAT_MINOR]));
out.push(Buffer.alloc(2, 0)); // record_len placeholder
out.push(Buffer.alloc(2, 0));
out.push(u64le(r.createdAtMs));
out.push(u64le(r.updatedAtMs));
@@ -106,7 +122,7 @@ function serializeUnsignedRecord(r: UnsignedRecord): Buffer {
out.push(r.prevRecordHash);
out.push(strBytes(r.login));
out.push(Buffer.from([r.isServer ? 6 : 5]));
out.push(Buffer.from([r.isServer ? 7 : 6]));
out.push(Buffer.from([BLOCK_TYPE_ROOT_KEY, BLOCK_VERSION_0]));
out.push(r.rootKey.toBuffer());
out.push(Buffer.from([BLOCK_TYPE_DEVICE_KEY, BLOCK_VERSION_0]));
@@ -129,21 +145,23 @@ function serializeUnsignedRecord(r: UnsignedRecord): Buffer {
if (r.isServer) {
out.push(Buffer.from([BLOCK_TYPE_SERVER_PROFILE, BLOCK_VERSION_0, 1]));
out.push(r.serverKey.toBuffer());
out.push(Buffer.from([r.addressFormatType, r.addressFormatVersion]));
out.push(strBytes(r.serverAddress));
out.push(Buffer.from([r.syncServers.length]));
for (const s of r.syncServers) {
out.push(strBytes(s));
}
for (const s of r.syncServers) out.push(strBytes(s));
}
out.push(Buffer.from([BLOCK_TYPE_ACCESS_SERVERS, BLOCK_VERSION_0]));
out.push(Buffer.from([r.accessServers.length]));
for (const s of r.accessServers) {
out.push(strBytes(s));
out.push(Buffer.from([BLOCK_TYPE_ACCESS_SERVERS, BLOCK_VERSION_0, r.accessServers.length]));
for (const s of r.accessServers) out.push(strBytes(s));
out.push(Buffer.from([BLOCK_TYPE_SESSIONS, BLOCK_VERSION_0, r.sessionsMode, r.sessions.length]));
for (const s of r.sessions) {
out.push(Buffer.from([s.sessionType, s.sessionVersion]));
out.push(strBytes(s.sessionName));
out.push(s.sessionPubKey.toBuffer());
}
out.push(Buffer.from([BLOCK_TYPE_TRUSTED_STATE, BLOCK_VERSION_0]));
out.push(Buffer.from([r.trustedCount]));
out.push(Buffer.from([BLOCK_TYPE_TRUSTED_STATE, BLOCK_VERSION_0, r.trustedCount]));
const unsigned = Buffer.concat(out);
const recordLen = unsigned.length + 64;
@@ -191,9 +209,7 @@ describe("shine_users e2e", () => {
SHINE_PAYMENTS_PROGRAM_ID
);
const economyAi = await provider.connection.getAccountInfo(
usersEconomyConfigPda
);
const economyAi = await provider.connection.getAccountInfo(usersEconomyConfigPda);
if (!economyAi) {
await program.methods
.initUsersEconomyConfig()
@@ -207,10 +223,28 @@ describe("shine_users e2e", () => {
const root = anchor.web3.Keypair.generate();
const blockchain = anchor.web3.Keypair.generate();
const deviceKey = anchor.web3.Keypair.generate().publicKey;
const serverKey1 = anchor.web3.Keypair.generate().publicKey;
const serverKey2 = anchor.web3.Keypair.generate().publicKey;
const blockchainName = `${login}-001`;
const createFields: MutableFields = {
deviceKey,
blockchainPublicKey: blockchain.publicKey,
blockchainName,
usedBytes: 0n,
lastBlockNumber: 0,
lastBlockHash: ZERO_HASH,
lastBlockSignature: Buffer.alloc(64, 0),
arweaveTxId: "",
isServer: true,
addressFormatType: 1,
addressFormatVersion: 0,
serverAddress: "https://srv-1.local",
syncServers: ["sync_srv_1", "sync_srv_2"],
accessServers: ["access_srv_1"],
sessionsMode: SESSIONS_MODE_MIXED,
sessions: [],
trustedCount: 0,
};
const createdAtMs = BigInt(Date.now());
const additionalLimitCreate = 20_000n;
expect(additionalLimitCreate % LIMIT_STEP).eq(0n);
@@ -228,27 +262,29 @@ describe("shine_users e2e", () => {
blockchainName,
blockchainPublicKey: blockchain.publicKey,
paidLimitBytes: START_BONUS_LIMIT + additionalLimitCreate,
usedBytes: 0n,
lastBlockNumber: 0,
lastBlockHash: ZERO_HASH,
usedBytes: createFields.usedBytes,
lastBlockNumber: createFields.lastBlockNumber,
lastBlockHash: createFields.lastBlockHash,
lastBlockSignature: Buffer.alloc(64, 0),
arweaveTxId: "",
arweaveTxId: createFields.arweaveTxId,
},
isServer: true,
serverKey: serverKey1,
serverAddress: "https://srv-1.local",
syncServers: ["sync_srv_1", "sync_srv_2"],
accessServers: ["access_srv_1"],
trustedCount: 0,
isServer: createFields.isServer,
addressFormatType: createFields.addressFormatType,
addressFormatVersion: createFields.addressFormatVersion,
serverAddress: createFields.serverAddress,
syncServers: createFields.syncServers,
accessServers: createFields.accessServers,
sessionsMode: createFields.sessionsMode,
sessions: createFields.sessions,
trustedCount: createFields.trustedCount,
};
const createLastBlockHash = sha256(serializeLastBlockState(createRecord));
const createLastBlockEdIx = Ed25519Program.createInstructionWithPrivateKey({
privateKey: blockchain.secretKey,
message: createLastBlockHash,
});
createRecord.blockchain.lastBlockSignature = extractSigFromEdIx(
Buffer.from(createLastBlockEdIx.data)
);
createRecord.blockchain.lastBlockSignature = extractSigFromEdIx(Buffer.from(createLastBlockEdIx.data));
createFields.lastBlockSignature = createRecord.blockchain.lastBlockSignature;
const createUnsigned = serializeUnsignedRecord(createRecord);
const createHash = sha256(createUnsigned);
@@ -265,22 +301,28 @@ describe("shine_users e2e", () => {
createdAtMs: new anchor.BN(createdAtMs.toString()),
additionalLimit: new anchor.BN(additionalLimitCreate.toString()),
fields: {
deviceKey,
blockchainPublicKey: blockchain.publicKey,
blockchainName,
usedBytes: new anchor.BN(
createRecord.blockchain.usedBytes.toString()
),
lastBlockNumber: createRecord.blockchain.lastBlockNumber,
lastBlockHash: createRecord.blockchain.lastBlockHash,
lastBlockSignature: createRecord.blockchain.lastBlockSignature,
arweaveTxId: "",
isServer: true,
serverKey: serverKey1,
serverAddress: "https://srv-1.local",
syncServers: ["sync_srv_1", "sync_srv_2"],
accessServers: ["access_srv_1"],
trustedCount: 0,
deviceKey: createFields.deviceKey,
blockchainPublicKey: createFields.blockchainPublicKey,
blockchainName: createFields.blockchainName,
usedBytes: new anchor.BN(createFields.usedBytes.toString()),
lastBlockNumber: createFields.lastBlockNumber,
lastBlockHash: createFields.lastBlockHash,
lastBlockSignature: createFields.lastBlockSignature,
arweaveTxId: createFields.arweaveTxId,
isServer: createFields.isServer,
addressFormatType: createFields.addressFormatType,
addressFormatVersion: createFields.addressFormatVersion,
serverAddress: createFields.serverAddress,
syncServers: createFields.syncServers,
accessServers: createFields.accessServers,
sessionsMode: createFields.sessionsMode,
sessions: createFields.sessions.map((s) => ({
sessionType: s.sessionType,
sessionVersion: s.sessionVersion,
sessionName: s.sessionName,
sessionPubKey: s.sessionPubKey,
})),
trustedCount: createFields.trustedCount,
},
signature: createSig,
})
@@ -293,10 +335,7 @@ describe("shine_users e2e", () => {
})
.instruction();
await provider.sendAndConfirm(
new Transaction().add(createEdIx, createLastBlockEdIx, createIx),
[]
);
await provider.sendAndConfirm(new Transaction().add(createEdIx, createLastBlockEdIx, createIx), []);
const createAcc = await provider.connection.getAccountInfo(userPda);
expect(createAcc).not.eq(null);
@@ -304,6 +343,26 @@ describe("shine_users e2e", () => {
const additionalLimitUpdate = 30_000n;
expect(additionalLimitUpdate % LIMIT_STEP).eq(0n);
const updatedDeviceKey = anchor.web3.Keypair.generate().publicKey;
const updateFields: MutableFields = {
deviceKey: updatedDeviceKey,
blockchainPublicKey: blockchain.publicKey,
blockchainName,
usedBytes: 512n,
lastBlockNumber: 1,
lastBlockHash: sha256(Buffer.from("first-shine-block")),
lastBlockSignature: Buffer.alloc(64, 0),
arweaveTxId: "",
isServer: true,
addressFormatType: 1,
addressFormatVersion: 0,
serverAddress: "https://srv-2.local",
syncServers: ["sync_srv_3"],
accessServers: ["access_srv_2", "access_srv_3"],
sessionsMode: SESSIONS_MODE_MIXED,
sessions: [],
trustedCount: 0,
};
const updateRecord: UnsignedRecord = {
createdAtMs,
@@ -312,34 +371,35 @@ describe("shine_users e2e", () => {
prevRecordHash: sha256(createUnsigned),
login,
rootKey: root.publicKey,
deviceKey: anchor.web3.Keypair.generate().publicKey,
deviceKey: updatedDeviceKey,
blockchain: {
blockchainType: BLOCKCHAIN_TYPE_MAIN_USER,
blockchainName,
blockchainPublicKey: blockchain.publicKey,
paidLimitBytes:
START_BONUS_LIMIT + additionalLimitCreate + additionalLimitUpdate,
usedBytes: 512n,
lastBlockNumber: 1,
lastBlockHash: sha256(Buffer.from("first-shine-block")),
paidLimitBytes: START_BONUS_LIMIT + additionalLimitCreate + additionalLimitUpdate,
usedBytes: updateFields.usedBytes,
lastBlockNumber: updateFields.lastBlockNumber,
lastBlockHash: updateFields.lastBlockHash,
lastBlockSignature: Buffer.alloc(64, 0),
arweaveTxId: "",
arweaveTxId: updateFields.arweaveTxId,
},
isServer: true,
serverKey: serverKey2,
serverAddress: "https://srv-2.local",
syncServers: ["sync_srv_3"],
accessServers: ["access_srv_2", "access_srv_3"],
trustedCount: 0,
isServer: updateFields.isServer,
addressFormatType: updateFields.addressFormatType,
addressFormatVersion: updateFields.addressFormatVersion,
serverAddress: updateFields.serverAddress,
syncServers: updateFields.syncServers,
accessServers: updateFields.accessServers,
sessionsMode: updateFields.sessionsMode,
sessions: updateFields.sessions,
trustedCount: updateFields.trustedCount,
};
const updateLastBlockHash = sha256(serializeLastBlockState(updateRecord));
const updateLastBlockEdIx = Ed25519Program.createInstructionWithPrivateKey({
privateKey: blockchain.secretKey,
message: updateLastBlockHash,
});
updateRecord.blockchain.lastBlockSignature = extractSigFromEdIx(
Buffer.from(updateLastBlockEdIx.data)
);
updateRecord.blockchain.lastBlockSignature = extractSigFromEdIx(Buffer.from(updateLastBlockEdIx.data));
updateFields.lastBlockSignature = updateRecord.blockchain.lastBlockSignature;
const updateUnsigned = serializeUnsignedRecord(updateRecord);
const updateHash = sha256(updateUnsigned);
@@ -359,22 +419,28 @@ describe("shine_users e2e", () => {
prevHash: sha256(createUnsigned),
additionalLimit: new anchor.BN(additionalLimitUpdate.toString()),
fields: {
deviceKey: updateRecord.deviceKey,
blockchainPublicKey: updateRecord.blockchain.blockchainPublicKey,
blockchainName,
usedBytes: new anchor.BN(
updateRecord.blockchain.usedBytes.toString()
),
lastBlockNumber: updateRecord.blockchain.lastBlockNumber,
lastBlockHash: updateRecord.blockchain.lastBlockHash,
lastBlockSignature: updateRecord.blockchain.lastBlockSignature,
arweaveTxId: "",
isServer: true,
serverKey: serverKey2,
serverAddress: "https://srv-2.local",
syncServers: ["sync_srv_3"],
accessServers: ["access_srv_2", "access_srv_3"],
trustedCount: 0,
deviceKey: updateFields.deviceKey,
blockchainPublicKey: updateFields.blockchainPublicKey,
blockchainName: updateFields.blockchainName,
usedBytes: new anchor.BN(updateFields.usedBytes.toString()),
lastBlockNumber: updateFields.lastBlockNumber,
lastBlockHash: updateFields.lastBlockHash,
lastBlockSignature: updateFields.lastBlockSignature,
arweaveTxId: updateFields.arweaveTxId,
isServer: updateFields.isServer,
addressFormatType: updateFields.addressFormatType,
addressFormatVersion: updateFields.addressFormatVersion,
serverAddress: updateFields.serverAddress,
syncServers: updateFields.syncServers,
accessServers: updateFields.accessServers,
sessionsMode: updateFields.sessionsMode,
sessions: updateFields.sessions.map((s) => ({
sessionType: s.sessionType,
sessionVersion: s.sessionVersion,
sessionName: s.sessionName,
sessionPubKey: s.sessionPubKey,
})),
trustedCount: updateFields.trustedCount,
},
signature: updateSig,
})
@@ -387,8 +453,10 @@ describe("shine_users e2e", () => {
})
.instruction();
const updateComputeIx = ComputeBudgetProgram.setComputeUnitLimit({ units: 800_000 });
const updateHeapIx = ComputeBudgetProgram.requestHeapFrame({ bytes: 262_144 });
await provider.sendAndConfirm(
new Transaction().add(updateEdIx, updateLastBlockEdIx, updateIx),
new Transaction().add(updateComputeIx, updateHeapIx, updateEdIx, updateLastBlockEdIx, updateIx),
[]
);