Синхронизировать регистр логинов и доработать UI каналов

This commit is contained in:
AidarKC
2026-08-19 14:30:29 +04:00
parent e8a4713f6e
commit ce30b77328
29 changed files with 6729 additions and 815 deletions
+21 -10
View File
@@ -721,6 +721,8 @@ export async function getShineBlockchainUsage({ login, solanaEndpoint }) {
paidLimitBytes: bch.paidLimitBytes,
usedBytes: bch.usedBytes,
leftBytes,
blockchainName: String(bch.blockchainName || ''),
arweaveTxId: String(bch.arweaveTxId || ''),
lastBlockNumber: bch.lastBlockNumber,
lastBlockHashHex: Array.from(bch.lastBlockHash).map((x) => x.toString(16).padStart(2, '0')).join(''),
};
@@ -762,9 +764,10 @@ async function attachSolanaLogs(error, connection) {
}
async function buildCreateContext({ login, keyBundle, solanaEndpoint }) {
const rawLogin = String(login || '').trim();
const cleanLogin = normalizeLogin(login);
const endpoint = String(solanaEndpoint || '').trim();
if (!cleanLogin) throw new Error('Не указан логин');
if (!rawLogin || !cleanLogin) throw new Error('Не указан логин');
if (!endpoint) throw new Error('Не указан Solana RPC endpoint');
const solana = await loadSolanaLib();
@@ -791,6 +794,7 @@ async function buildCreateContext({ login, keyBundle, solanaEndpoint }) {
const clientKeypair = solana.Keypair.fromSeed(clientSeed32);
return {
rawLogin,
cleanLogin,
endpoint,
solana,
@@ -832,18 +836,19 @@ async function createShineUserPdaOnSolana({
}
const cleanLogin = ctx.cleanLogin;
const displayLogin = ctx.rawLogin;
const cleanPromoCode = String(promoCode || '').trim();
const blockchainName = `${cleanLogin}-001`;
const zeroHash32 = new Uint8Array(32);
const createdAtMs = BigInt(Date.now());
const startBonusLimit = parseUsersEconomyConfig(ecoAccount.data).startBonusLimit;
const lastBlockStateBytes = buildLastBlockStateBytes(cleanLogin, blockchainName, 0, zeroHash32, 0n);
const lastBlockStateBytes = buildLastBlockStateBytes(displayLogin, blockchainName, 0, zeroHash32, 0n);
const lastBlockStateHash = await sha256Bytes(lastBlockStateBytes);
const lastBlockSig64 = await signBytes(ctx.bchPrivKey, lastBlockStateHash);
const initialState = createPdaState({
login: cleanLogin,
login: displayLogin,
createdAtMs,
updatedAtMs: createdAtMs,
recordNumber: 0,
@@ -910,7 +915,7 @@ async function createShineUserPdaOnSolana({
});
}
const ixData = serializeCreateUserPdaArgs({
login: cleanLogin,
login: displayLogin,
recoveryKey32: ctx.recoveryKey32,
rootKey32: ctx.rootKey32,
createdAtMs,
@@ -1028,6 +1033,7 @@ export async function updateShineUserPdaOnSolana({
nextUsedBytes,
nextLastBlockNumber,
nextLastBlockHashHex,
nextArweaveTxId,
serverProfile,
accessServers,
trustedCount,
@@ -1043,6 +1049,7 @@ export async function updateShineUserPdaOnSolana({
const effectiveUsed = nextUsedBytes == null ? currentBch.usedBytes : BigInt(nextUsedBytes);
const effectiveLastNum = nextLastBlockNumber == null ? currentBch.lastBlockNumber : Number(nextLastBlockNumber);
const effectiveLastHash = parseHex32(nextLastBlockHashHex) || currentBch.lastBlockHash;
const effectiveArweaveTxId = nextArweaveTxId == null ? currentBch.arweaveTxId : String(nextArweaveTxId || '').trim();
if (effectiveLastHash.length !== 32) throw new Error('last block hash должен быть 32 байта');
const rootPriv = await importPkcs8Ed25519(rootPrivatePkcs8B64);
@@ -1060,7 +1067,7 @@ export async function updateShineUserPdaOnSolana({
const clientKeypair = solana.Keypair.fromSeed(clientSeed32);
const lastBlockStateBytes = buildLastBlockStateBytes(
cleanLogin,
current.login,
currentBch.blockchainName,
effectiveLastNum,
effectiveLastHash,
@@ -1085,7 +1092,10 @@ export async function updateShineUserPdaOnSolana({
const updatedAtMs = BigInt(Date.now());
const newPaid = currentBch.paidLimitBytes + addLimit;
const newRecordNumber = current.recordNumber + 1;
const prevHash = await sha256Bytes(serializeUnsignedRecordFromState(current));
// Для prev_hash нужно хэшировать точную unsigned-часть текущей PDA,
// а не пересобирать её из распарсенного состояния: иначе можно получить
// несовпадение байт и InvalidPrevHash в on-chain программе.
const prevHash = await sha256Bytes(current.unsignedBytes || serializeUnsignedRecordFromState(current));
const nextServerProfile = serverProfile
? {
@@ -1097,7 +1107,7 @@ export async function updateShineUserPdaOnSolana({
: current.serverProfile;
const nextState = createPdaState({
login: cleanLogin,
login: current.login,
createdAtMs: current.createdAtMs,
updatedAtMs,
recordNumber: newRecordNumber,
@@ -1113,7 +1123,7 @@ export async function updateShineUserPdaOnSolana({
lastBlockNumber: effectiveLastNum,
lastBlockHash: effectiveLastHash,
lastBlockSignature: lastBlockSig64,
arweaveTxId: currentBch.arweaveTxId,
arweaveTxId: effectiveArweaveTxId,
}),
isServer: Boolean(nextServerProfile),
addressFormatType: nextServerProfile?.addressFormatType ?? 0,
@@ -1131,7 +1141,7 @@ export async function updateShineUserPdaOnSolana({
const rootSig64 = await signBytes(rootPriv, unsignedNextHash);
const ixData = serializeUpdateUserPdaArgs({
login: cleanLogin,
login: current.login,
recoveryKey32: current.recoveryKey,
rootKey32: current.rootKey,
createdAtMs: current.createdAtMs,
@@ -1146,7 +1156,7 @@ export async function updateShineUserPdaOnSolana({
lastBlockNumber: effectiveLastNum,
lastBlockHash32: effectiveLastHash,
lastBlockSignature64: lastBlockSig64,
arweaveTxId: currentBch.arweaveTxId,
arweaveTxId: effectiveArweaveTxId,
isServer: nextState.isServer,
addressFormatType: nextState.addressFormatType,
addressFormatVersion: nextState.addressFormatVersion,
@@ -1205,6 +1215,7 @@ export async function updateShineUserPdaOnSolana({
leftBytes: newPaid > effectiveUsed ? (newPaid - effectiveUsed) : 0n,
lastBlockNumber: effectiveLastNum,
lastBlockHashHex: Array.from(effectiveLastHash).map((x) => x.toString(16).padStart(2, '0')).join(''),
arweaveTxId: effectiveArweaveTxId,
};
}