Exercise – Logging

After learning how logging works, perform the following actions: 

  1. Log the value of greeting_account.counter just before and just after the increment operation
  2. Change the increment operation in the following way: 
    1. if the counter is 0, add 1 to it 
    2. otherwise, multiply the counter by 2 
  3. Verify your solution by compiling the code, deploying it, and running it

:one: Log the value of greeting_account.counter just before and just after the increment operation

Within the main program (main.ts file), I added an additional reportGreetings() call, before calling sayHello() -> so that the structure is:

main.ts

...
  // Find out how many times that account has been greeted BEFORE the incrementor
  await reportGreetings(true);

  // Say hello to an account
  await sayHello();

  // Find out how many times that account has been greeted AFTER the incrementor
  await reportGreetings(false);
...

But it’s useful to differentiate whether the reportGreetings() call is coming before the incrementor or after the incrementor, in the logs.
To do this, the reportGreetings() function should be changed.

The change can be as simple as adding a single boolean argument to the reportGreetings() function to follow the path where if it is before the incrementor, it says so in the logs, and if not then it says after incrementing.

The additional change in the function body is at the final console.log part where we can simple tack on to the end ${beforeIncrement ? "Before the incrementor" : "After the incrementor"}.

So the revised reportGreetings() function looks like this:

hello_world.ts

export async function reportGreetings(beforeIncrement: boolean): Promise<void> {
  const accountInfo = await connection.getAccountInfo(greetedPubkey);
  if (accountInfo === null) {
    throw 'Error: cannot find the greeted account';
  }
  const greeting = borsh.deserialize(
    GreetingSchema,
    GreetingAccount,
    accountInfo.data,
  );
  console.log(
    greetedPubkey.toBase58(),
    'has been greeted',
    greeting.counter,
    'time(s)',
    `${beforeIncrement ? "Before the incrementor" : "After the incrementor"}`
  );
}

And in the main program looks like this:

main.ts

async function main() {
  console.log("Let's say hello to a Solana account...");

  // Establish connection to the cluster
  await establishConnection();

  // Determine who pays for the fees
  await establishPayer();

  // Check if the program has been deployed
  await checkProgram();

  // THIS WAS ADDED
  // Find out how many times that account has been greeted BEFORE the incrementor
  await reportGreetings(true);

  // Say hello to an account
  await sayHello();

  // THIS WAS CHANGED
  // Find out how many times that account has been greeted AFTER the incrementor
  await reportGreetings(false);

  console.log('Success');
}

EDIT
The question specification was not to make different logs on the client, but rather to add system logging, so instead you should need to go to the smart contract located at /src/program-rust/src/lib.rs and in the process_instruction() public function, 4 lines before the end of the function, you should find greeting_account.counter += 1;.
At this point, you should add a msg!("Greeted {} time(s)!", greeting_account.counter); before and after it to have a counter log before and after the increment.

:two: Change the increment operation to: (If the counter is 0, add 1 to it…otherwise, multiply the counter by 2 )

This one is a little harder…

Within the file src/program-rust/src/lib.rs, the entrypoint!(process_instruction); calls the public function process_instruction() which does a whole bunch, including processing the counter increment and storing it.

...
// Increment and store the number of times the account has been greeted
    let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
    greeting_account.counter += 1;

    greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;
...

This can be modified to do a check before the counter increment, such that:

...
    // Increment and store the number of times the account has been greeted
    let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
    if greeting_account.counter == 0 {
        greeting_account.counter += 1;
    } else {
        greeting_account.counter *= 2;
    }
    greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;
...

Doing the check to see if greeting_account.counter != 0 will then double the count and store the number each time the program is run.

1 Like
  1. Log the value of greeting_account.counter just before and just after the increment operation

lib.rs:

    let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
    msg!("Counter before {}: ", greeting_account.counter);    
        greeting_account.counter += 1;
    msg!("Counter after {}: ", greeting_account.counter);    
    greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;
  1. Change the increment operation in the following way:
    if the counter is 0, add 1 to it
    otherwise, multiply the counter by 2

lib.rs:

 let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
    msg!("Counter before {}: ", greeting_account.counter);    
    if greeting_account.counter == 0{
        greeting_account.counter += 1;
    } else {
    greeting_account.counter *= 2;
    }
    msg!("Counter after {}: ", greeting_account.counter);    
    greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;
2 Likes

main.ts

/**
 * Hello world
 */

import {
  establishConnection,
  establishPayer,
  checkProgram,
  sayHello,
  reportGreetings,
} from './hello_world';

async function main() {
  console.log("Let's say hello to a Solana account...");

  // Establish connection to the cluster
  await establishConnection();
  
  // Determine who pays for the fees
  await establishPayer();
  
  // Check if the program has been deployed
  await checkProgram();
  
  await reportGreetings();//1
  
  // Say hello to an account
  await sayHello();

  // Find out how many times that account has been greeted
  await reportGreetings();//2

  console.log('Success');
}

main().then(
  () => process.exit(),
  err => {
    console.error(err);
    process.exit(-1);
  },
);

lib.rs

use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    program_error::ProgramError,
    pubkey::Pubkey,
};

/// Define the type of state stored in accounts
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct GreetingAccount {
    /// number of greetings
    pub counter: u32,
}

// Declare and export the program's entrypoint
entrypoint!(process_instruction);

// Program entrypoint's implementation
pub fn process_instruction(
    program_id: &Pubkey, // Public key of the account the hello world program was loaded into
    accounts: &[AccountInfo], // The account to say hello to
    _instruction_data: &[u8], // Ignored, all helloworld instructions are hellos
) -> ProgramResult {
    msg!("Hello World Rust program entrypoint");

    // Iterating accounts is safer than indexing
    let accounts_iter = &mut accounts.iter();

    // Get the account to say hello to
    let account = next_account_info(accounts_iter)?;

    // The account must be owned by the program in order to modify its data
    if account.owner != program_id {
        msg!("Greeted account does not have the correct program id");
        return Err(ProgramError::IncorrectProgramId);
    }

    // Increment and store the number of times the account has been greeted
    let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
    if greeting_account.counter==0 {greeting_account.counter += 1;}
    else {greeting_account.counter *=2}
    greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;

    msg!("Greeted {} time(s)!", greeting_account.counter);

    Ok(())
}

// Sanity tests
#[cfg(test)]
mod test {
    use super::*;
    use solana_program::clock::Epoch;
    use std::mem;

    #[test]
    fn test_sanity() {
        let program_id = Pubkey::default();
        let key = Pubkey::default();
        let mut lamports = 0;
        let mut data = vec![0; mem::size_of::<u32>()];
        let owner = Pubkey::default();
        let account = AccountInfo::new(
            &key,
            false,
            true,
            &mut lamports,
            &mut data,
            &owner,
            false,
            Epoch::default(),
        );
        let instruction_data: Vec<u8> = Vec::new();

        let accounts = vec![account];

        assert_eq!(
            GreetingAccount::try_from_slice(&accounts[0].data.borrow())
                .unwrap()
                .counter,
            0
        );
        process_instruction(&program_id, &accounts, &instruction_data).unwrap();
        assert_eq!(
            GreetingAccount::try_from_slice(&accounts[0].data.borrow())
                .unwrap()
                .counter,
            1
        );
        process_instruction(&program_id, &accounts, &instruction_data).unwrap();
        assert_eq!(
            GreetingAccount::try_from_slice(&accounts[0].data.borrow())
                .unwrap()
                .counter,
            2
        );
    }
}

1 Like
// Increment and store the number of times the account has been greeted
    let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
    msg!("Counter before: {}", greeting_account.counter);

    greeting_account.counter += 1;
    
    msg!("Counter after: {}", greeting_account.counter);

    greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;

    msg!("Greeted {} time(s)!", greeting_account.counter);
// Increment and store the number of times the account has been greeted
    let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
    msg!("Counter before: {}", greeting_account.counter);

    if greeting_account.counter == 0 {
        greeting_account.counter += 1;
    } else {
        greeting_account.counter *= 2;
    }
    msg!("Counter after: {}", greeting_account.counter);

    greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;

    msg!("Greeted {} time(s)!", greeting_account.counter);

compiling the code
:white_check_mark: npm run build:program-rust
deploying the code
:ballot_box_with_check: solana program deploy dist/program/helloworld.so
running the code
:heavy_check_mark: npm start

Program log: Counter before: 0
Program log: Counter after: 1
Program log: Greeted 1 time(s)!

:heavy_check_mark: npm start

Program log: Counter before: 1
Program log: Counter after: 2
Program log: Greeted 2 time(s)!

:heavy_check_mark: npm start

Program log: Counter before: 2
Program log: Counter after: 4
Program log: Greeted 4 time(s)!

:heavy_check_mark: npm start

Program log: Counter before: 4
Program log: Counter after: 8
Program log: Greeted 8 time(s)!
1 Like

this is my code, i try use a one global variable on blockchain, but solana program destabilizes me (I think in solidity method)
my first try is comment

lib.rs

/// Define the type of state stored in accounts
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct GreetingAccount {
    /// number of greetings
    pub counter: u32,
    // previs number greetings
    //-->pub previs_counter: u32,
}

// Declare and export the program's entrypoint
entrypoint!(process_instruction);

// Program entrypoint's implementation
pub fn process_instruction(
    program_id: &Pubkey, // Public key of the account the hello world program was loaded into
    accounts: &[AccountInfo], // The account to say hello to
    _instruction_data: &[u8], // Ignored, all helloworld instructions are hellos
) -> ProgramResult {
    msg!("Hello World Rust program entrypoint");

    // Iterating accounts is safer than indexing
    let accounts_iter = &mut accounts.iter();

    // Get the account to say hello to
    let account = next_account_info(accounts_iter)?;

    // The account must be owned by the program in order to modify its data
    if account.owner != program_id {
        msg!("Greeted account does not have the correct program id");
        return Err(ProgramError::IncorrectProgramId);
    }

    let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
    let mut previus: u32;
    match greeting_account.counter {
        0 => {
            //greeting_account.previs_counter = greeting_account.counter;
            previus = greeting_account.counter;
            greeting_account.counter += 1;
        }
        _ => {
            //greeting_account.previs_counter = greeting_account.counter;
            previus = greeting_account.counter;
            greeting_account.counter *= 2;
        }
    }
    greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;

    msg!(
        "Greeted {} time(s)!, previs counter is {}",
        greeting_account.counter,
        previus //greeting_account.previs_counter
    );

    Ok(())
}

client:

class GreetingAccount {
  counter = 0;
  previs_counter = 0;
  constructor(fields: {counter: number,previs_counter: number } | undefined = undefined) {
    if (fields) {
      this.counter = fields.counter;
      this.previs_counter = fields.previs_counter;
    }
  }
}

/**
 * Borsh schema definition for greeting accounts
 */
const GreetingSchema = new Map([
  [GreetingAccount, {kind: 'struct', fields: [['counter', 'u32'],['previs_counter','u32']]}],
]);

this return “SERIALIZE or DESERIALIZE error”

  • Log the value of greeting_account.counter just before and just after the increment operation
    please note that i didn’t reset the counter but i reset the deployment with
    npm run clean:program-rust
 let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
    // check the  count before
    msg!("Before greeting counter: {}", greeting_account.counter); 
  • Change the increment operation in the following way:
    1. if the counter is 0, add 1 to it
    2. otherwise, multiply the counter by 2
// if 0, change to 1 else x2
    if  (greeting_account.counter ==0) {
        greeting_account.counter +=1;
    } else { greeting_account.counter *=2;    
    }
    //greeting_account.counter += 1;
  • deploy
$:example-helloworld owner$ npm start

> [email protected] start
> ts-node src/client/main.ts

Let's say hello to a Solana account...
Connection to cluster established: http://127.0.0.1:8899 { 'feature-set': 1775889670, 'solana-core': '1.13.6' }
Using account Bgh5zzbom3aVX13NZuTMWcyTPZ3RXhaduxziHvyevByj containing 499999998.36896455 SOL to pay for fees
Using program 5nP39viHhDaSEg8PLA1Z5x5uBE5WRDSiRBNeynkjPxmt
Saying hello to 919eWMfU2TLuVrqXE5VHx3PrwUeSF9CtPDEANMqGZB1h
919eWMfU2TLuVrqXE5VHx3PrwUeSF9CtPDEANMqGZB1h has been greeted 16 time(s)
Success

  • From logs:
 Program log: Before greeting counter: 0
    Program log: Greeted 1 time(s)!
    Program 5nP39viHhDaSEg8PLA1Z5x5uBE5WRDSiRBNeynkjPxmt consumed 29713 of 200000 compute units
Transaction executed in slot 6130:
--
Program log: Before greeting counter: 1
    Program log: Greeted 2 time(s)!
    Program 5nP39viHhDaSEg8PLA1Z5x5uBE5WRDSiRBNeynkjPxmt consumed 29715 of 200000 compute units
    Program 5nP39viHhDaSEg8PLA1Z5x5uBE5WRDSiRBNeynkjPxmt success
Transaction executed in slot 6158:
--
Program log: Before greeting counter: 8
    Program log: Greeted 16 time(s)!
    Program 5nP39viHhDaSEg8PLA1Z5x5uBE5WRDSiRBNeynkjPxmt consumed 29726 of 200000 compute units
    Program 5nP39viHhDaSEg8PLA1Z5x5uBE5WRDSiRBNeynkjPxmt success

although i got stuck in the deploy helloworld.so for a little bit but troubleshooting help… pretty much a hard course but this task wasn’t that difficult to track where to setup the counter changes… (using my just learned javascript if/else)

1 Like
    // Increment and store the number of times the account has been greeted
    let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;

    msg!("Greeting counter before is: {}", greeting_account.counter);
    
    greeting_account.counter = if greeting_account.counter == 0 
        {1} else {greeting_account.counter * 2};

    msg!("Greeting counter after is: {}", greeting_account.counter);
    
    greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;

    msg!("Greeted {} time(s)!", greeting_account.counter);

The 1st time output:

Lets say hello to a Solana account...
Connection to cluster established: http://localhost:8899 { 'feature-set': 4033350765, 'solana-core': '1.16.20' }
Using account Bti9XR2wmcoyLD4YkH8KDwL9Dtk9NQtb5xNMHboFy67J containing 3.43202564 SOL to pay for fees
Using program BriMeDA8hJHgEDC4ohYe2rGu7syGDJTsEHncuZ8m7oAg
Creating account 9yorvewJgjwThJkFjeNP3Tq4SWcPZj3WF4nSnDijWTXD to say hello to
Saying hello to 9yorvewJgjwThJkFjeNP3Tq4SWcPZj3WF4nSnDijWTXD
9yorvewJgjwThJkFjeNP3Tq4SWcPZj3WF4nSnDijWTXD has been greeted 1 time(s)
Success

The 2nd time output:

9yorvewJgjwThJkFjeNP3Tq4SWcPZj3WF4nSnDijWTXD has been greeted 2 time(s)
Success

The 3rd time output:

9yorvewJgjwThJkFjeNP3Tq4SWcPZj3WF4nSnDijWTXD has been greeted 4 time(s)
Success

…and the The 4th time output:

9yorvewJgjwThJkFjeNP3Tq4SWcPZj3WF4nSnDijWTXD has been greeted 8 time(s)
Success

So far so good as expected!