SHA256
Починить native Ed25519 update_user_pda без OOM
This commit is contained in:
@@ -3,10 +3,9 @@ use anchor_lang::prelude::*;
|
||||
use anchor_lang::solana_program::{
|
||||
ed25519_program,
|
||||
hash::hashv,
|
||||
instruction::Instruction,
|
||||
program::{get_return_data, invoke},
|
||||
system_instruction,
|
||||
sysvar::instructions::{load_current_index_checked, load_instruction_at_checked},
|
||||
sysvar::instructions::get_instruction_relative,
|
||||
};
|
||||
use common::utils::{create_pda, safe_read_pda, write_to_pda, ErrCode};
|
||||
use std::str::FromStr;
|
||||
@@ -411,7 +410,8 @@ 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)?;
|
||||
let old_record = deserialize_record_from_pda(raw.as_slice())?;
|
||||
drop(raw);
|
||||
|
||||
require!(
|
||||
old_record.login == args.login,
|
||||
@@ -447,6 +447,14 @@ pub fn update_user_pda(ctx: Context<UpdateUserPda>, args: UpdateUserPdaArgs) ->
|
||||
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()
|
||||
&& old_record.blockchain.last_block_signature.as_slice()
|
||||
== 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,
|
||||
@@ -485,11 +493,14 @@ pub fn update_user_pda(ctx: Context<UpdateUserPda>, args: UpdateUserPdaArgs) ->
|
||||
);
|
||||
validate_blockchain_limits(
|
||||
&new_record.blockchain,
|
||||
old_record.blockchain.used_bytes,
|
||||
old_record.blockchain.last_block_number,
|
||||
old_used_bytes,
|
||||
old_last_block_number,
|
||||
false,
|
||||
)?;
|
||||
verify_last_block_state_signature(&ctx.accounts.instructions, &new_record)?;
|
||||
drop(old_record);
|
||||
if !blockchain_state_unchanged {
|
||||
verify_last_block_state_signature(&ctx.accounts.instructions, &new_record)?;
|
||||
}
|
||||
|
||||
let unsigned = serialize_unsigned_record(&new_record)?;
|
||||
new_record.signature = verify_record_signature(
|
||||
@@ -498,6 +509,7 @@ pub fn update_user_pda(ctx: Context<UpdateUserPda>, args: UpdateUserPdaArgs) ->
|
||||
&args.signature,
|
||||
&unsigned,
|
||||
)?;
|
||||
drop(unsigned);
|
||||
|
||||
let serialized = serialize_full_record(&new_record)?;
|
||||
ensure_pda_size_and_rent(
|
||||
@@ -807,6 +819,7 @@ fn verify_record_signature(
|
||||
let msg_hash = hashv(&[unsigned]);
|
||||
verify_ed25519_signature_instruction(
|
||||
instructions_sysvar,
|
||||
-2,
|
||||
root_key,
|
||||
&provided_sig,
|
||||
msg_hash.as_ref(),
|
||||
@@ -822,6 +835,7 @@ fn verify_last_block_state_signature(
|
||||
let msg_hash = hashv(&[&message]);
|
||||
verify_ed25519_signature_instruction(
|
||||
instructions_sysvar,
|
||||
-1,
|
||||
&record.blockchain.blockchain_public_key,
|
||||
&record.blockchain.last_block_signature,
|
||||
msg_hash.as_ref(),
|
||||
@@ -830,6 +844,7 @@ fn verify_last_block_state_signature(
|
||||
|
||||
fn verify_ed25519_signature_instruction(
|
||||
instructions_sysvar: &AccountInfo,
|
||||
index_relative_to_current: i64,
|
||||
expected_pubkey: &Pubkey,
|
||||
expected_signature: &[u8; 64],
|
||||
expected_message: &[u8],
|
||||
@@ -839,24 +854,14 @@ fn verify_ed25519_signature_instruction(
|
||||
anchor_lang::solana_program::sysvar::instructions::id(),
|
||||
ErrCode::InvalidSignature
|
||||
);
|
||||
let current_ix_index = load_current_index_checked(instructions_sysvar)
|
||||
let ed_ix = get_instruction_relative(index_relative_to_current, instructions_sysvar)
|
||||
.map_err(|_| error!(ErrCode::InvalidSignature))?;
|
||||
require!(current_ix_index > 0, ErrCode::InvalidSignature);
|
||||
for ix_index in 0..current_ix_index {
|
||||
let ed_ix = load_instruction_at_checked(ix_index as usize, instructions_sysvar)
|
||||
.map_err(|_| error!(ErrCode::InvalidSignature))?;
|
||||
if ed_ix.program_id != ed25519_program::id() {
|
||||
continue;
|
||||
}
|
||||
let parsed = parse_ed25519_ix(&ed_ix)?;
|
||||
if parsed.pubkey == *expected_pubkey
|
||||
&& parsed.signature == *expected_signature
|
||||
&& parsed.message == expected_message
|
||||
{
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(error!(ErrCode::InvalidSignature))
|
||||
require_keys_eq!(ed_ix.program_id, ed25519_program::id(), ErrCode::InvalidSignature);
|
||||
let parsed = parse_ed25519_ix(ed_ix.data.as_slice())?;
|
||||
require!(parsed.pubkey == *expected_pubkey, ErrCode::InvalidSignature);
|
||||
require!(parsed.signature == *expected_signature, ErrCode::InvalidSignature);
|
||||
require!(parsed.message == expected_message, ErrCode::InvalidSignature);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn serialize_last_block_state(record: &UserRecord) -> Result<Vec<u8>> {
|
||||
@@ -870,22 +875,15 @@ fn serialize_last_block_state(record: &UserRecord) -> Result<Vec<u8>> {
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
struct ParsedEd25519 {
|
||||
pub pubkey: Pubkey,
|
||||
pub signature: [u8; 64],
|
||||
pub message: Vec<u8>,
|
||||
struct ParsedEd25519Ref<'a> {
|
||||
pubkey: Pubkey,
|
||||
signature: [u8; 64],
|
||||
message: &'a [u8],
|
||||
}
|
||||
|
||||
fn parse_ed25519_ix(ix: &Instruction) -> Result<ParsedEd25519> {
|
||||
require_keys_eq!(
|
||||
ix.program_id,
|
||||
ed25519_program::id(),
|
||||
ErrCode::InvalidSignature
|
||||
);
|
||||
|
||||
let data = &ix.data;
|
||||
fn parse_ed25519_ix<'a>(data: &'a [u8]) -> Result<ParsedEd25519Ref<'a>> {
|
||||
require!(data.len() >= 16, ErrCode::InvalidSignature);
|
||||
require!(data[0] == 1, ErrCode::InvalidSignature); // одна подпись
|
||||
require!(data[0] == 1, ErrCode::InvalidSignature);
|
||||
|
||||
let signature_offset = le_u16(data, 2)? as usize;
|
||||
let signature_ix_index = le_u16(data, 4)?;
|
||||
@@ -917,8 +915,7 @@ fn parse_ed25519_ix(ix: &Instruction) -> Result<ParsedEd25519> {
|
||||
.ok_or(error!(ErrCode::InvalidSignature))?;
|
||||
let message = data
|
||||
.get(message_offset..message_end)
|
||||
.ok_or(error!(ErrCode::InvalidSignature))?
|
||||
.to_vec();
|
||||
.ok_or(error!(ErrCode::InvalidSignature))?;
|
||||
|
||||
let mut signature = [0u8; 64];
|
||||
signature.copy_from_slice(signature_slice);
|
||||
@@ -926,7 +923,7 @@ fn parse_ed25519_ix(ix: &Instruction) -> Result<ParsedEd25519> {
|
||||
<[u8; 32]>::try_from(pubkey_slice).map_err(|_| error!(ErrCode::InvalidSignature))?,
|
||||
);
|
||||
|
||||
Ok(ParsedEd25519 {
|
||||
Ok(ParsedEd25519Ref {
|
||||
pubkey,
|
||||
signature,
|
||||
message,
|
||||
|
||||
Reference in New Issue
Block a user