SHA256
Зафиксировать все текущие изменения проекта
This commit is contained in:
@@ -14,6 +14,8 @@ const MAGIC: &[u8; 5] = b"SHiNE";
|
||||
const FORMAT_MAJOR: u8 = 1;
|
||||
const FORMAT_MINOR: u8 = 0;
|
||||
const MAX_SYNC_SERVERS: usize = 32;
|
||||
const MAX_SESSIONS: usize = 64;
|
||||
const MAX_SESSION_NAME_LEN: usize = 64;
|
||||
const MAX_AUTO_REALLOC_INCREASE: usize = 10_000;
|
||||
const ZERO_HASH: [u8; 32] = [0; 32];
|
||||
const BLOCK_TYPE_ROOT_KEY: u8 = 1;
|
||||
@@ -22,10 +24,23 @@ const BLOCK_TYPE_BLOCKCHAIN_REGISTRY: u8 = 3;
|
||||
const BLOCK_TYPE_SERVER_PROFILE: u8 = 30;
|
||||
const BLOCK_TYPE_ACCESS_SERVERS: u8 = 40;
|
||||
const BLOCK_TYPE_TRUSTED_STATE: u8 = 50;
|
||||
const BLOCK_TYPE_SESSIONS: u8 = 55;
|
||||
const BLOCK_VERSION_0: u8 = 0;
|
||||
const BLOCKCHAIN_TYPE_MAIN_USER: u8 = 1;
|
||||
const SESSIONS_MODE_MIXED: u8 = 1;
|
||||
const SESSIONS_MODE_PDA_ONLY: u8 = 10;
|
||||
const SESSION_TYPE_USER: u8 = 1;
|
||||
const SESSION_TYPE_SUBSERVER: u8 = 100;
|
||||
const LAST_BLOCK_STATE_PREFIX: &[u8] = b"SHiNE_LAST_BLOCK";
|
||||
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct SessionRecord {
|
||||
pub session_type: u8,
|
||||
pub session_version: u8,
|
||||
pub session_name: String,
|
||||
pub session_pub_key: Pubkey,
|
||||
}
|
||||
|
||||
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
|
||||
pub struct UserMutableFields {
|
||||
pub device_key: Pubkey,
|
||||
@@ -42,6 +57,8 @@ pub struct UserMutableFields {
|
||||
pub server_address: String,
|
||||
pub sync_servers: Vec<String>,
|
||||
pub access_servers: Vec<String>,
|
||||
pub sessions_mode: u8,
|
||||
pub sessions: Vec<SessionRecord>,
|
||||
pub trusted_count: u8,
|
||||
}
|
||||
|
||||
@@ -83,6 +100,8 @@ pub struct UserRecord {
|
||||
pub server_address: String,
|
||||
pub sync_servers: Vec<String>,
|
||||
pub access_servers: Vec<String>,
|
||||
pub sessions_mode: u8,
|
||||
pub sessions: Vec<SessionRecord>,
|
||||
pub trusted_count: u8,
|
||||
pub signature: [u8; 64],
|
||||
}
|
||||
@@ -242,7 +261,35 @@ pub fn update_users_economy_config(
|
||||
}
|
||||
|
||||
pub fn create_user_pda(ctx: Context<CreateUserPda>, args: CreateUserPdaArgs) -> Result<()> {
|
||||
validate_login(&args.login)?;
|
||||
let CreateUserPdaArgs {
|
||||
login,
|
||||
root_key,
|
||||
created_at_ms,
|
||||
additional_limit,
|
||||
fields,
|
||||
signature,
|
||||
} = args;
|
||||
let UserMutableFields {
|
||||
device_key,
|
||||
blockchain_public_key,
|
||||
blockchain_name,
|
||||
used_bytes,
|
||||
last_block_number,
|
||||
last_block_hash,
|
||||
last_block_signature,
|
||||
arweave_tx_id,
|
||||
is_server,
|
||||
address_format_type,
|
||||
address_format_version,
|
||||
server_address,
|
||||
sync_servers,
|
||||
access_servers,
|
||||
sessions_mode,
|
||||
sessions,
|
||||
trusted_count,
|
||||
} = fields;
|
||||
|
||||
validate_login(&login)?;
|
||||
require_keys_eq!(
|
||||
ctx.accounts.login_guard_program.key(),
|
||||
Pubkey::from_str(settings::SHINE_LOGIN_GUARD_PROGRAM_ID)
|
||||
@@ -252,17 +299,35 @@ pub fn create_user_pda(ctx: Context<CreateUserPda>, args: CreateUserPdaArgs) ->
|
||||
classify_login_or_fail(
|
||||
&ctx.accounts.login_guard_program.to_account_info(),
|
||||
&ctx.accounts.signer,
|
||||
&args.login,
|
||||
&login,
|
||||
)?;
|
||||
validate_fields(&args.fields)?;
|
||||
validate_fields(&UserMutableFields {
|
||||
device_key,
|
||||
blockchain_public_key,
|
||||
blockchain_name: blockchain_name.clone(),
|
||||
used_bytes,
|
||||
last_block_number,
|
||||
last_block_hash: last_block_hash.clone(),
|
||||
last_block_signature: last_block_signature.clone(),
|
||||
arweave_tx_id: arweave_tx_id.clone(),
|
||||
is_server,
|
||||
address_format_type,
|
||||
address_format_version,
|
||||
server_address: server_address.clone(),
|
||||
sync_servers: sync_servers.clone(),
|
||||
access_servers: access_servers.clone(),
|
||||
sessions_mode,
|
||||
sessions: sessions.clone(),
|
||||
trusted_count,
|
||||
})?;
|
||||
validate_inflow_vault(&ctx.accounts.inflow_vault)?;
|
||||
require!(
|
||||
args.additional_limit % settings::LIMIT_STEP == 0,
|
||||
additional_limit % settings::LIMIT_STEP == 0,
|
||||
ErrCode::InvalidLimitIncrement
|
||||
);
|
||||
let economy = read_users_economy_config(&ctx.accounts.users_economy_config_pda)?;
|
||||
|
||||
let login_seed = login_seed_normalized(&args.login);
|
||||
let login_seed = login_seed_normalized(&login);
|
||||
let (expected_pda, bump) = find_user_pda(ctx.program_id, &login_seed);
|
||||
require_keys_eq!(
|
||||
expected_pda,
|
||||
@@ -276,46 +341,50 @@ pub fn create_user_pda(ctx: Context<CreateUserPda>, args: CreateUserPdaArgs) ->
|
||||
|
||||
let start_balance = economy
|
||||
.start_bonus_limit
|
||||
.checked_add(args.additional_limit)
|
||||
.checked_add(additional_limit)
|
||||
.ok_or(error!(ErrCode::MathOverflow))?;
|
||||
|
||||
let mut record = UserRecord {
|
||||
created_at_ms: args.created_at_ms,
|
||||
updated_at_ms: args.created_at_ms,
|
||||
created_at_ms,
|
||||
updated_at_ms: created_at_ms,
|
||||
record_number: 0,
|
||||
prev_record_hash: ZERO_HASH,
|
||||
login: args.login.clone(),
|
||||
root_key: args.root_key,
|
||||
device_key: args.fields.device_key,
|
||||
login,
|
||||
root_key,
|
||||
device_key,
|
||||
blockchain: BlockchainRecord {
|
||||
blockchain_type: BLOCKCHAIN_TYPE_MAIN_USER,
|
||||
blockchain_name: args.fields.blockchain_name.clone(),
|
||||
blockchain_public_key: args.fields.blockchain_public_key,
|
||||
blockchain_name,
|
||||
blockchain_public_key,
|
||||
paid_limit_bytes: start_balance,
|
||||
used_bytes: args.fields.used_bytes,
|
||||
last_block_number: args.fields.last_block_number,
|
||||
last_block_hash: vec_to_hash32(&args.fields.last_block_hash)?,
|
||||
last_block_signature: vec_to_signature(&args.fields.last_block_signature)?,
|
||||
arweave_tx_id: args.fields.arweave_tx_id.clone(),
|
||||
used_bytes,
|
||||
last_block_number,
|
||||
last_block_hash: vec_to_hash32(&last_block_hash)?,
|
||||
last_block_signature: vec_to_signature(&last_block_signature)?,
|
||||
arweave_tx_id,
|
||||
},
|
||||
is_server: args.fields.is_server,
|
||||
address_format_type: args.fields.address_format_type,
|
||||
address_format_version: args.fields.address_format_version,
|
||||
server_address: args.fields.server_address.clone(),
|
||||
sync_servers: args.fields.sync_servers.clone(),
|
||||
access_servers: args.fields.access_servers.clone(),
|
||||
trusted_count: args.fields.trusted_count,
|
||||
is_server,
|
||||
address_format_type,
|
||||
address_format_version,
|
||||
server_address,
|
||||
sync_servers,
|
||||
access_servers,
|
||||
sessions_mode,
|
||||
sessions,
|
||||
trusted_count,
|
||||
signature: [0; 64],
|
||||
};
|
||||
validate_blockchain_limits(&record.blockchain, 0, 0, true)?;
|
||||
verify_last_block_state_signature(&ctx.accounts.instructions, &record)?;
|
||||
|
||||
let unsigned = serialize_unsigned_record(&record)?;
|
||||
record.signature = verify_record_signature(
|
||||
let unsigned_hash = hashv(&[&unsigned]);
|
||||
drop(unsigned);
|
||||
record.signature = verify_record_signature_hash(
|
||||
&ctx.accounts.instructions,
|
||||
&record.root_key,
|
||||
&args.signature,
|
||||
&unsigned,
|
||||
&signature,
|
||||
unsigned_hash.as_ref(),
|
||||
)?;
|
||||
|
||||
let serialized = serialize_full_record(&record)?;
|
||||
@@ -342,10 +411,7 @@ pub fn create_user_pda(ctx: Context<CreateUserPda>, args: CreateUserPdaArgs) ->
|
||||
|
||||
let total_fee = economy
|
||||
.registration_fee_lamports
|
||||
.checked_add(limit_fee_lamports(
|
||||
args.additional_limit,
|
||||
economy.lamports_per_limit_step,
|
||||
)?)
|
||||
.checked_add(limit_fee_lamports(additional_limit, economy.lamports_per_limit_step)?)
|
||||
.ok_or(error!(ErrCode::MathOverflow))?;
|
||||
transfer_lamports(
|
||||
&ctx.accounts.signer,
|
||||
@@ -396,10 +462,11 @@ pub fn update_user_pda(ctx: Context<UpdateUserPda>, args: UpdateUserPdaArgs) ->
|
||||
);
|
||||
let economy = read_users_economy_config(&ctx.accounts.users_economy_config_pda)?;
|
||||
|
||||
let login_seed = login_seed_normalized(&args.login);
|
||||
let (expected_pda, _) = find_user_pda(ctx.program_id, &login_seed);
|
||||
require_keys_eq!(
|
||||
expected_pda,
|
||||
{
|
||||
let normalized_login = login_seed_normalized(&args.login);
|
||||
find_user_pda(ctx.program_id, &normalized_login).0
|
||||
},
|
||||
ctx.accounts.user_pda.key(),
|
||||
ErrCode::InvalidPdaAddress
|
||||
);
|
||||
@@ -410,7 +477,7 @@ pub fn update_user_pda(ctx: Context<UpdateUserPda>, args: UpdateUserPdaArgs) ->
|
||||
|
||||
let raw = safe_read_pda(&ctx.accounts.user_pda);
|
||||
require!(!raw.is_empty(), ErrCode::EmptyPdaData);
|
||||
let old_record = deserialize_record_from_pda(raw.as_slice())?;
|
||||
let old_record = Box::new(deserialize_record_from_pda(raw.as_slice())?);
|
||||
drop(raw);
|
||||
|
||||
require!(
|
||||
@@ -431,24 +498,21 @@ pub fn update_user_pda(ctx: Context<UpdateUserPda>, args: UpdateUserPdaArgs) ->
|
||||
ErrCode::InvalidVersion
|
||||
);
|
||||
|
||||
let expected_prev_hash = hash_unsigned_record(&old_record)?;
|
||||
let provided_prev_hash = vec_to_hash32(&args.prev_hash)?;
|
||||
let provided_prev_hash = Box::new(vec_to_hash32(&args.prev_hash)?);
|
||||
require!(
|
||||
expected_prev_hash == provided_prev_hash,
|
||||
hash_unsigned_record(&old_record)? == *provided_prev_hash,
|
||||
ErrCode::InvalidPrevHash
|
||||
);
|
||||
|
||||
let new_balance = old_record
|
||||
let new_balance = Box::new(old_record
|
||||
.blockchain
|
||||
.paid_limit_bytes
|
||||
.checked_add(args.additional_limit)
|
||||
.ok_or(error!(ErrCode::MathOverflow))?;
|
||||
.ok_or(error!(ErrCode::MathOverflow))?);
|
||||
require!(
|
||||
new_balance >= old_record.blockchain.paid_limit_bytes,
|
||||
*new_balance >= old_record.blockchain.paid_limit_bytes,
|
||||
ErrCode::BalanceDecrease
|
||||
);
|
||||
let old_used_bytes = old_record.blockchain.used_bytes;
|
||||
let old_last_block_number = old_record.blockchain.last_block_number;
|
||||
let blockchain_state_unchanged = old_record.blockchain.used_bytes == args.fields.used_bytes
|
||||
&& old_record.blockchain.last_block_number == args.fields.last_block_number
|
||||
&& old_record.blockchain.last_block_hash.as_slice() == args.fields.last_block_hash.as_slice()
|
||||
@@ -456,60 +520,60 @@ pub fn update_user_pda(ctx: Context<UpdateUserPda>, args: UpdateUserPdaArgs) ->
|
||||
== args.fields.last_block_signature.as_slice()
|
||||
&& old_record.blockchain.arweave_tx_id == args.fields.arweave_tx_id;
|
||||
|
||||
let mut new_record = UserRecord {
|
||||
created_at_ms: old_record.created_at_ms,
|
||||
updated_at_ms: args.updated_at_ms,
|
||||
record_number: args.version,
|
||||
prev_record_hash: provided_prev_hash,
|
||||
login: old_record.login.clone(),
|
||||
root_key: old_record.root_key,
|
||||
device_key: args.fields.device_key,
|
||||
blockchain: BlockchainRecord {
|
||||
blockchain_type: old_record.blockchain.blockchain_type,
|
||||
blockchain_name: args.fields.blockchain_name.clone(),
|
||||
blockchain_public_key: args.fields.blockchain_public_key,
|
||||
paid_limit_bytes: new_balance,
|
||||
used_bytes: args.fields.used_bytes,
|
||||
last_block_number: args.fields.last_block_number,
|
||||
last_block_hash: vec_to_hash32(&args.fields.last_block_hash)?,
|
||||
last_block_signature: vec_to_signature(&args.fields.last_block_signature)?,
|
||||
arweave_tx_id: args.fields.arweave_tx_id.clone(),
|
||||
},
|
||||
is_server: args.fields.is_server,
|
||||
address_format_type: args.fields.address_format_type,
|
||||
address_format_version: args.fields.address_format_version,
|
||||
server_address: args.fields.server_address.clone(),
|
||||
sync_servers: args.fields.sync_servers.clone(),
|
||||
access_servers: args.fields.access_servers.clone(),
|
||||
trusted_count: args.fields.trusted_count,
|
||||
signature: [0; 64],
|
||||
};
|
||||
require!(
|
||||
new_record.blockchain.blockchain_type == old_record.blockchain.blockchain_type
|
||||
&& new_record.blockchain.blockchain_name == old_record.blockchain.blockchain_name
|
||||
&& new_record.blockchain.blockchain_public_key
|
||||
args.fields.blockchain_name == old_record.blockchain.blockchain_name
|
||||
&& args.fields.blockchain_public_key
|
||||
== old_record.blockchain.blockchain_public_key,
|
||||
ErrCode::ImmutableFieldChanged
|
||||
);
|
||||
validate_blockchain_limits(
|
||||
&new_record.blockchain,
|
||||
old_used_bytes,
|
||||
old_last_block_number,
|
||||
false,
|
||||
)?;
|
||||
drop(old_record);
|
||||
{
|
||||
let candidate_blockchain =
|
||||
build_candidate_blockchain_for_update(&old_record, *new_balance, &args.fields)?;
|
||||
validate_blockchain_limits(
|
||||
&candidate_blockchain,
|
||||
old_record.blockchain.used_bytes,
|
||||
old_record.blockchain.last_block_number,
|
||||
false,
|
||||
)?;
|
||||
}
|
||||
if !blockchain_state_unchanged {
|
||||
verify_last_block_state_signature(&ctx.accounts.instructions, &new_record)?;
|
||||
verify_last_block_state_signature_candidate(
|
||||
&ctx.accounts.instructions,
|
||||
&old_record,
|
||||
args.updated_at_ms,
|
||||
args.version,
|
||||
*provided_prev_hash,
|
||||
*new_balance,
|
||||
&args.fields,
|
||||
)?;
|
||||
}
|
||||
|
||||
let unsigned = serialize_unsigned_record(&new_record)?;
|
||||
new_record.signature = verify_record_signature(
|
||||
&ctx.accounts.instructions,
|
||||
&new_record.root_key,
|
||||
&args.signature,
|
||||
&unsigned,
|
||||
let unsigned = serialize_unsigned_update_candidate(
|
||||
&old_record,
|
||||
args.updated_at_ms,
|
||||
args.version,
|
||||
*provided_prev_hash,
|
||||
*new_balance,
|
||||
&args.fields,
|
||||
)?;
|
||||
let unsigned_hash = hashv(&[&unsigned]);
|
||||
drop(unsigned);
|
||||
let verified_signature = Box::new(verify_record_signature_hash(
|
||||
&ctx.accounts.instructions,
|
||||
&old_record.root_key,
|
||||
&args.signature,
|
||||
unsigned_hash.as_ref(),
|
||||
)?);
|
||||
let mut new_record = build_update_record(
|
||||
&old_record,
|
||||
args.updated_at_ms,
|
||||
args.version,
|
||||
*provided_prev_hash,
|
||||
*new_balance,
|
||||
&args.fields,
|
||||
)?;
|
||||
new_record.signature = *verified_signature;
|
||||
drop(old_record);
|
||||
|
||||
let serialized = serialize_full_record(&new_record)?;
|
||||
ensure_pda_size_and_rent(
|
||||
@@ -533,6 +597,97 @@ pub fn update_user_pda(ctx: Context<UpdateUserPda>, args: UpdateUserPdaArgs) ->
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn build_candidate_blockchain_for_update(
|
||||
old_record: &UserRecord,
|
||||
new_balance: u64,
|
||||
fields: &UserMutableFields,
|
||||
) -> Result<BlockchainRecord> {
|
||||
Ok(BlockchainRecord {
|
||||
blockchain_type: old_record.blockchain.blockchain_type,
|
||||
blockchain_name: fields.blockchain_name.clone(),
|
||||
blockchain_public_key: fields.blockchain_public_key,
|
||||
paid_limit_bytes: new_balance,
|
||||
used_bytes: fields.used_bytes,
|
||||
last_block_number: fields.last_block_number,
|
||||
last_block_hash: vec_to_hash32(&fields.last_block_hash)?,
|
||||
last_block_signature: vec_to_signature(&fields.last_block_signature)?,
|
||||
arweave_tx_id: fields.arweave_tx_id.clone(),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn build_update_record(
|
||||
old_record: &UserRecord,
|
||||
updated_at_ms: u64,
|
||||
version: u32,
|
||||
prev_record_hash: [u8; 32],
|
||||
new_balance: u64,
|
||||
fields: &UserMutableFields,
|
||||
) -> Result<UserRecord> {
|
||||
Ok(UserRecord {
|
||||
created_at_ms: old_record.created_at_ms,
|
||||
updated_at_ms,
|
||||
record_number: version,
|
||||
prev_record_hash,
|
||||
login: old_record.login.clone(),
|
||||
root_key: old_record.root_key,
|
||||
device_key: fields.device_key,
|
||||
blockchain: build_candidate_blockchain_for_update(old_record, new_balance, fields)?,
|
||||
is_server: fields.is_server,
|
||||
address_format_type: fields.address_format_type,
|
||||
address_format_version: fields.address_format_version,
|
||||
server_address: fields.server_address.clone(),
|
||||
sync_servers: fields.sync_servers.clone(),
|
||||
access_servers: fields.access_servers.clone(),
|
||||
sessions_mode: fields.sessions_mode,
|
||||
sessions: fields.sessions.clone(),
|
||||
trusted_count: fields.trusted_count,
|
||||
signature: [0; 64],
|
||||
})
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn verify_last_block_state_signature_candidate(
|
||||
instructions_sysvar: &AccountInfo,
|
||||
old_record: &UserRecord,
|
||||
updated_at_ms: u64,
|
||||
version: u32,
|
||||
prev_record_hash: [u8; 32],
|
||||
new_balance: u64,
|
||||
fields: &UserMutableFields,
|
||||
) -> Result<()> {
|
||||
let candidate = build_update_record(
|
||||
old_record,
|
||||
updated_at_ms,
|
||||
version,
|
||||
prev_record_hash,
|
||||
new_balance,
|
||||
fields,
|
||||
)?;
|
||||
verify_last_block_state_signature(instructions_sysvar, &candidate)
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn serialize_unsigned_update_candidate(
|
||||
old_record: &UserRecord,
|
||||
updated_at_ms: u64,
|
||||
version: u32,
|
||||
prev_record_hash: [u8; 32],
|
||||
new_balance: u64,
|
||||
fields: &UserMutableFields,
|
||||
) -> Result<Vec<u8>> {
|
||||
let candidate = build_update_record(
|
||||
old_record,
|
||||
updated_at_ms,
|
||||
version,
|
||||
prev_record_hash,
|
||||
new_balance,
|
||||
fields,
|
||||
)?;
|
||||
serialize_unsigned_record(&candidate)
|
||||
}
|
||||
|
||||
fn serialize_unsigned_record(record: &UserRecord) -> Result<Vec<u8>> {
|
||||
let login_bytes = record.login.as_bytes();
|
||||
require!(login_bytes.len() <= u8::MAX as usize, ErrCode::InvalidLogin);
|
||||
@@ -551,7 +706,7 @@ fn serialize_unsigned_record(record: &UserRecord) -> Result<Vec<u8>> {
|
||||
out.push(login_bytes.len() as u8);
|
||||
out.extend_from_slice(login_bytes);
|
||||
|
||||
let blocks_count = if record.is_server { 6 } else { 5 };
|
||||
let blocks_count = if record.is_server { 7 } else { 6 };
|
||||
out.push(blocks_count);
|
||||
write_root_key_block(&mut out, record);
|
||||
write_device_key_block(&mut out, record);
|
||||
@@ -560,6 +715,7 @@ fn serialize_unsigned_record(record: &UserRecord) -> Result<Vec<u8>> {
|
||||
write_server_profile_block(&mut out, record)?;
|
||||
}
|
||||
write_access_servers_block(&mut out, record)?;
|
||||
write_sessions_block(&mut out, record)?;
|
||||
write_trusted_state_block(&mut out, record);
|
||||
|
||||
let record_len = out
|
||||
@@ -650,6 +806,29 @@ fn write_access_servers_block(out: &mut Vec<u8>, record: &UserRecord) -> Result<
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_sessions_block(out: &mut Vec<u8>, record: &UserRecord) -> Result<()> {
|
||||
out.push(BLOCK_TYPE_SESSIONS);
|
||||
out.push(BLOCK_VERSION_0);
|
||||
out.push(record.sessions_mode);
|
||||
require!(
|
||||
record.sessions.len() <= MAX_SESSIONS,
|
||||
ErrCode::InvalidRecordData
|
||||
);
|
||||
out.push(record.sessions.len() as u8);
|
||||
for session in &record.sessions {
|
||||
write_session_record(out, session)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_session_record(out: &mut Vec<u8>, session: &SessionRecord) -> Result<()> {
|
||||
out.push(session.session_type);
|
||||
out.push(session.session_version);
|
||||
write_len_prefixed_string(out, &session.session_name)?;
|
||||
out.extend_from_slice(session.session_pub_key.as_ref());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_trusted_state_block(out: &mut Vec<u8>, record: &UserRecord) {
|
||||
out.push(BLOCK_TYPE_TRUSTED_STATE);
|
||||
out.push(BLOCK_VERSION_0);
|
||||
@@ -696,6 +875,19 @@ fn read_blockchain_record(data: &[u8], cursor: &mut usize) -> Result<BlockchainR
|
||||
})
|
||||
}
|
||||
|
||||
fn read_session_record(data: &[u8], cursor: &mut usize) -> Result<SessionRecord> {
|
||||
let session_type = read_u8(data, cursor)?;
|
||||
let session_version = read_u8(data, cursor)?;
|
||||
let session_name = read_len_prefixed_string(data, cursor)?;
|
||||
let session_pub_key = Pubkey::new_from_array(read_fixed_32(data, cursor)?);
|
||||
Ok(SessionRecord {
|
||||
session_type,
|
||||
session_version,
|
||||
session_name,
|
||||
session_pub_key,
|
||||
})
|
||||
}
|
||||
|
||||
fn deserialize_record_from_pda(raw: &[u8]) -> Result<UserRecord> {
|
||||
require!(raw.len() >= 9, ErrCode::InvalidRecordData);
|
||||
require!(&raw[0..5] == MAGIC, ErrCode::InvalidRecordMagic);
|
||||
@@ -727,6 +919,8 @@ fn deserialize_record_from_pda(raw: &[u8]) -> Result<UserRecord> {
|
||||
let mut server_address = String::new();
|
||||
let mut sync_servers = Vec::new();
|
||||
let mut access_servers = Vec::new();
|
||||
let mut sessions_mode = SESSIONS_MODE_MIXED;
|
||||
let mut sessions = Vec::new();
|
||||
let mut trusted_count = 0u8;
|
||||
|
||||
for _ in 0..blocks_count {
|
||||
@@ -771,6 +965,15 @@ fn deserialize_record_from_pda(raw: &[u8]) -> Result<UserRecord> {
|
||||
access_servers.push(read_len_prefixed_string(useful, &mut cursor)?);
|
||||
}
|
||||
}
|
||||
BLOCK_TYPE_SESSIONS => {
|
||||
require!(sessions.is_empty(), ErrCode::InvalidRecordData);
|
||||
sessions_mode = read_u8(useful, &mut cursor)?;
|
||||
let sessions_count = read_u8(useful, &mut cursor)? as usize;
|
||||
require!(sessions_count <= MAX_SESSIONS, ErrCode::InvalidRecordData);
|
||||
for _ in 0..sessions_count {
|
||||
sessions.push(read_session_record(useful, &mut cursor)?);
|
||||
}
|
||||
}
|
||||
BLOCK_TYPE_TRUSTED_STATE => {
|
||||
trusted_count = read_u8(useful, &mut cursor)?;
|
||||
}
|
||||
@@ -778,6 +981,7 @@ fn deserialize_record_from_pda(raw: &[u8]) -> Result<UserRecord> {
|
||||
}
|
||||
}
|
||||
|
||||
validate_sessions_fields(sessions_mode, &sessions)?;
|
||||
let signature = read_fixed_64(useful, &mut cursor)?;
|
||||
require!(cursor == useful.len(), ErrCode::InvalidRecordLength);
|
||||
|
||||
@@ -796,6 +1000,8 @@ fn deserialize_record_from_pda(raw: &[u8]) -> Result<UserRecord> {
|
||||
server_address,
|
||||
sync_servers,
|
||||
access_servers,
|
||||
sessions_mode,
|
||||
sessions,
|
||||
trusted_count,
|
||||
signature,
|
||||
})
|
||||
@@ -809,20 +1015,19 @@ fn hash_unsigned_record(record: &UserRecord) -> Result<[u8; 32]> {
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
fn verify_record_signature(
|
||||
fn verify_record_signature_hash(
|
||||
instructions_sysvar: &AccountInfo,
|
||||
root_key: &Pubkey,
|
||||
signature: &[u8],
|
||||
unsigned: &[u8],
|
||||
message_hash: &[u8],
|
||||
) -> Result<[u8; 64]> {
|
||||
let provided_sig = vec_to_signature(signature)?;
|
||||
let msg_hash = hashv(&[unsigned]);
|
||||
verify_ed25519_signature_instruction(
|
||||
instructions_sysvar,
|
||||
-2,
|
||||
root_key,
|
||||
&provided_sig,
|
||||
msg_hash.as_ref(),
|
||||
message_hash,
|
||||
)?;
|
||||
Ok(provided_sig)
|
||||
}
|
||||
@@ -1007,6 +1212,46 @@ fn validate_fields(fields: &UserMutableFields) -> Result<()> {
|
||||
ErrCode::InvalidRecordData
|
||||
);
|
||||
}
|
||||
validate_sessions_fields(fields.sessions_mode, &fields.sessions)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_sessions_fields(mode: u8, sessions: &[SessionRecord]) -> Result<()> {
|
||||
require!(
|
||||
mode == SESSIONS_MODE_MIXED || mode == SESSIONS_MODE_PDA_ONLY,
|
||||
ErrCode::InvalidRecordData
|
||||
);
|
||||
require!(sessions.len() <= MAX_SESSIONS, ErrCode::InvalidRecordData);
|
||||
|
||||
for i in 0..sessions.len() {
|
||||
validate_session_record(&sessions[i])?;
|
||||
for j in (i + 1)..sessions.len() {
|
||||
require!(
|
||||
sessions[i].session_name != sessions[j].session_name,
|
||||
ErrCode::InvalidRecordData
|
||||
);
|
||||
require!(
|
||||
sessions[i].session_pub_key != sessions[j].session_pub_key,
|
||||
ErrCode::InvalidRecordData
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn validate_session_record(session: &SessionRecord) -> Result<()> {
|
||||
require!(
|
||||
session.session_type == SESSION_TYPE_USER || session.session_type == SESSION_TYPE_SUBSERVER,
|
||||
ErrCode::InvalidRecordData
|
||||
);
|
||||
require!(session.session_version == 1, ErrCode::InvalidRecordData);
|
||||
let bytes = session.session_name.as_bytes();
|
||||
require!(!bytes.is_empty(), ErrCode::InvalidRecordData);
|
||||
require!(bytes.len() <= MAX_SESSION_NAME_LEN, ErrCode::InvalidRecordData);
|
||||
for &b in bytes {
|
||||
let ok = b.is_ascii_alphanumeric() || b == b'_';
|
||||
require!(ok, ErrCode::InvalidRecordData);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
[]
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user