Blog

  • Control flow of promises vs Rx-Observables

    Coming from years of iOS development, I’ve come to be pretty fond of Rx-streams and observables as a way of taming state changes in a frontend-mobile environment. Javascript promises predates the development of Rx frameworks like ReactiveCocoa and RxSwift, so I was a little surprised to learn that Promises don’t offer the lazy evaluation that I’ve come to associate with reactive style programming.

    For example:

    const p = new Promise((resolve) => { // (1)
      console.log("within promise");
      setTimeout(() => {
        resolve("hello world"); // (2)
        console.log("promise resolved");
      }, 3000);
    });
    
    console.log("test begins");
    console.log(await p)
    

    The order the resulting logs are:

    within promise
    test begins
    promise resolved
    hello world
    

    I think several points were surprising at first:

    1. Immediately after the const t is created, the body of the promise closure is evaluated, which means that one cannot create multiple promises and ’then’ only one of the promises, since all of them will be evaluated. This also means that the long running task in the closure must use one of the built in IO or wait methods that can escape Javascript’s single-threadedness.
    2. The ‘resolve’ call only records the response of the function, and the control flow does not return to the ’then’ closure until the body of the promise is completed. It seems this way not because the promise was not resolved by the time ‘resolve’ is called, but because javascript has not finished executing this block of code, and has no way of ‘yielding’ the control flow back to the caller. Another modification makes this clearer:
    const p = new Promise((resolve) => {
      console.log("within promise");
      setTimeout(() => {
        resolve("hello world");
        setTimeout(() => console.log("promise resolved"), 1);
      }, 3000);
    });
    
    console.log("test begins");
    console.log(await p)
    

    Now the order of logs are:

    within promise
    test begins
    hello world
    promise resolved
    

  • Interacting with Simple Contracts on Ethereum

    The truffle project helps one get started in writing contracts, but after the bootstrap and deploying a contract to the testnet, I realized there was less support on how to interact with the contract. Alchemy has a good example in their docs, but I wanted to use the web3.js library maintained by ChainSafe.

    The key parts were:

    1. Getting the compiled json abi from trufflesuite and creating a web3.eth.Contract instance
    2. Creating an account with web3.eth.accounts.privateKeyToAccount
    3. Creating a transaction with the function call encoded by encodeABI
    4. and finally signing the transaction before sending it.
    import Web3 from "web3";
    
    const yourApiKey = "..."
    const web3 = new Web3("https://eth-sepolia.g.alchemy.com/v2/" + yourApiKey);
    
    const privateKey = 'yourPrivateKey'
    const senderAccount = web3.eth.accounts.privateKeyToAccount(privateKey);
    
    const contractAddress = "0xd76E31314D760b51493278C72c22d280C6ba6C4b" # a deployed contract on Sepolia
    
    import SimpleStorage from './build/ethereum-contracts/SimpleStorage.json' assert { type: 'json' }
    const contract = new web3.eth.Contract(SimpleStorage.abi, contractAddress)
    const paymeTransaction = contract.methods.payme();
    
    const transactionObject = {
      from: senderAccount.address,
      to: contractAddress,
      data: paymeTransaction.encodeABI(),
      value: Web3.utils.toWei('0.001', 'ether'),
      gas: 200000,
      maxPriorityFeePerGas: 100000,
      maxFeePerGas: 200000
    };
    
    senderAccount.signTransaction(transactionObject)
      .then((signedTx) => {
        return web3.eth.sendSignedTransaction(signedTx.rawTransaction);
      })
      .then((receipt) => {
        console.log('Transaction successful:', receipt);
      })
      .catch((error) => {
        console.error('Transaction failed:', error);
      });
    

    In the browser environment, somehow the privateKey would be part of a default list of accounts, and the higher level transaction.call() can be used, but I’m unfamiliar with that flow currently.


  • Timezones in Postgres

    There are two representations for timestamp in postgres, timestamp, and timestamptz. Both store dates in the db as UTC, and the only difference between the two is that timestamptz uses to timezone to format the data for display. But I think this obscures what I would say is slightly unintuitive behavior when working with timestamps in postgres.

    Converting between timestamp and timestamptz

    Consider the following query:

    postgres=# select 
    pg_typeof(timestamp '2022-01-01' at time zone 'Pacific/Honolulu'), 
    pg_typeof(timestamptz '2022-01-01' at time zone 'Pacific/Honolulu');
            pg_typeof         |          pg_typeof
    --------------------------+-----------------------------
     timestamp with time zone | timestamp without time zone
    

    I think it makes sense that a timestamp at time zone becomes a timestamptz, but not so much that a timestamptz at time zone would be converted back to a timestamp! This has implications for methods like date or date part, because these operate on the ‘display’ value.

    For example:

    postgres=# select date(timestamptz '2022-01-01T00:00+00:00');
        date
    ------------
     2021-12-31
    

    The reason that the date of this timestamp is December 31st, as opposed to January 1st, is that when converted to the default timezone on my postgres db, the date is December 31st. We can verify this:

    postgres=# select timestamptz '2022-01-01T00:00+00:00';
          timestamptz
    ------------------------
     2021-12-31 19:00:00-05
    (1 row)
    

    This means that the default timezone has a lot of bearing on the output of date, or date_part! Because of this, it’s best not to use timestamptz when dealing with methods like these, as they lead to unexpected outputs.

    Implicit coercion between timestamp and timestamptz

    Let’s create a table with one timestamp field and one timestamptz field.

    postgres=# create table if not exists tt (
    	timestamp_col timestamp
    	timestamptz_col timestamptz
    );
    

    Let’s insert a value without a time zone into both of these fields.

    postgres=# insert into tt(timestamp_col, timestamptz_col)
    values ('2022-01-01T00:00', '2022-01-01T00:00')
    returning *;
        timestamp_col    |    timestamptz_col
    ---------------------+------------------------
     2022-01-01 00:00:00 | 2022-01-01 00:00:00-05
    

    In the timestamp field, the value of UTC midnight, January 1st is recorded, which makes sense. In the timestamptz field however, the value of UTC 5am is actually recorded, because the inserted timestamp is assumed to be in the default time zone of the db.

    postgres=# show timezone;
         TimeZone
    ------------------
     America/New_York
    (1 row)
    

    Now let’s insert a timestamp with a time zone in both of the fields:

    postgres=# insert into tt(timestamp_col, timestamptz_col)
    values ('2022-01-01T00:00+01:00', '2022-01-01T00:00+01:00')
    returning *;
        timestamp_col    |    timestamptz_col
    ---------------------+------------------------
     2022-01-01 00:00:00 | 2021-12-31 18:00:00-05
    

    In the timestamp column, the time zone part of the input is simply dropped, so UTC midnight is saved. In the timestamptz column, we see that the field is set to exactly the same time as the input. Ie, 2022-01-01T00:00+01:00 == 2021-12-31 18:00:00-05.