Tuesday, October 11, 2022

VC redistributable is a critical piece of functionality

Just spent several hours trying to figure out why the freshly-installed ODP.NET 19c fails to load on most of our production servers.

The immediate error that I got in the logs was

Unable to load DLL 'OraOps19.dll': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

Googling for it did not really bring anything that helped: the permissions were ok and the path of the .dll was in the PATH environment variable.

In order to diagnose the problem I turned to the great SysInternals' tool called Process Monitor. After filtering out the extra stuff (a lot of extra stuff :) ) I ended up with a very clear error message:


Going to the Microsoft site, downloading the latest (or the relevant) VC Redistributable quickly fixed the issue.

Tuesday, May 10, 2022

Fix the issue with incorrect BigInteger serialization of MVC

When I wrote an webAPI method that returns a structure with BigInteger in it (used a lot in blockchain development) it turned out that the output looks as follows:



It looks like the default serializer of BigInteger used by the MVC works in a bit strange way.

There was a way of course to add decorators to the BigInteger data members of the structure that I wanted to serialize, but I use Nethereum and the structure was automatically generated by a Nethereum tool (which is quite handy, by the way). So I wanted to find a way to override the default behavior of the JSON serializer for the BigInteger type.

Took me some time to understand how to do it, but in the end it all makes sense and is quite simple:

1. Created a class that inherits from JsonConverter<BigInteger> as follows:

using System.Numerics;

using System.Text.Json;
using System.Text.Json.Serialization;

namespace AkwaWeb
{
    public class BigIntegerJsonConverter : JsonConverter<BigInteger>
    {
        public override BigInteger Read(
                   ref Utf8JsonReader reader,
                   Type typeToConvert,
                   JsonSerializerOptions options) =>
                       BigInteger.Parse(reader.GetString()!);
        public override void Write(
            Utf8JsonWriter writer,
            BigInteger val,
            JsonSerializerOptions options) =>
                writer.WriteStringValue(val.ToString());
    }
}

2. Registered it during the system initialization as follows:

builder.Services.AddMvc().AddJsonOptions(options =>
{
   options.JsonSerializerOptions.Converters.Add(new AkwaWeb.BigIntegerJsonConverter());
});

3. Et voila



Sunday, January 2, 2022

Using WSL for Solana development

Why? Solana tooling for Windows does not allow for BPF builds.

How?

  • Run WSL on Windows
  • If you are behind a company firewall:
    • make sure you have a .pem file of your root certificate. Talk your sysadmin for that. If you have a .cer file - make sure you convert it to .pem
    • Make sure you have an environment variable SSL_CERT_FILE to point at your .pem certificate (use "export SSL_CERT_FILE=" for that from inside your wsl command shell) or event better - add it to your ~/bashrc file
  • sudo apt install build-essential
  • curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
  • sudo apt install pkg-config
  • sudo apt install libudev-dev
  • sudo apt install llvm-dev
  • sudo apt install clang

Build and run solana-bpf-program-template on Windows

It turns out that compiling a very basic solana-bpf-program-template on Windows is not a very easy task to do.

First, it panicked with the following error:

error: failed to run custom build command for `openssl-sys ...

In order to solve this an install of the OpenSSL package is needed. Compiling it may have more tricks in it so I decided to install a pre-built package from here. I went to the "Win64 OpenSSL v1.1.1m" option. either .EXE or .MSI. It's important to select the OpenSSL 1.1.1 and not another version. When installing make sure the environment variable of OPENSSL_DIR is set. If not - please set it manually to the root directory of the installation.

Once this issue was resolved the "cargo build" phase progressed further to halt this time with the following error:

   Compiling soketto v0.7.1
error: failed to run custom build command for `librocksdb-sys v6.20.3`

Caused by:
  process didn't exit successfully: `D:\Projects\solana\solana-bpf-program-template\target\debug\build\librocksdb-sys-67f01990a368d2b7\build-script-build` (exit code: 101)
  --- stderr
  thread 'main' panicked at 'Unable to find libclang: "couldn't find any valid shared libraries matching: ['clang.dll', 'libclang.dll'], set the `LIBCLANG_PATH` environment variable to a path where one of these files can be found (invalid: [])"'

In order to resolve this I had to google the LIBCLANG_PATH to discover that I need the LLVM compiler. It can be downloaded from here  Please make sure that you select registering the environment variables as a part of the installation.

Tuesday, December 14, 2021

Build and run ganache-ui on a new Windows 11 workstation in a corporate environment

Took me about a day to build ganache-ui so I decided to put it here in writing. Hopefully it will save time to somebody
So, let's start. I had a brand-new Windows 11 workstation and Chrome installed
  • Install Git
  • Install node.js
  • Update your npm to the latest version
  • Update your npm-gyp to the latest version with "npm install -g node-gyp@latest"
  • Install windows-build-tools. Although the page says that it's no longer needed - you will need python2 from this package. May be you can install just python 2 and then proceed to the following item
  • Make sure that your python2 path is in your PATH


  • Now go the ganache-ui git and download it with git clone.
    Their git readme page contains pretty good explanations on how to build the ganache-ui project.

  • Open your node command prompt
  • If you are behind a corporate transparent proxy you will need to do the following in the command window:
  • set NODE_TLS_REJECT_UNAUTHORIZED=0
  • npm config set strict-ssl false
  • build ganache-ui
  • Monday, November 29, 2021

    How to prevent messy desktop when the monitor switches off

    A problem that bothered me for a couple of days when I moved on to another worsktation with Windows 10: when you leave your desktop unattended for the power saving to kick in and turn off your monitor - the desktop would go crazy : all windows will be moved and resize as if to fit into a very small desktop size.
    After some googling it turned out that Windows would "lose" the identification of the connected monitor and would switch to another "default" monitor. And will change the layout of the desktop to the size of this "default" monitor. Which turns out to be 1024x768.

    In order to change that the following steps need to be taken:
  • Open RegEdit
  • Go to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\Configuration
  • Find the "default" device.
  • This part is a bit tricky. I first deleted all the keys that were there besides something that looked to me like my SAMSUNG monitor description.
  • Then when my monitor went to sleep again Windows added another key to the registery with the name of NOEDID_8086_9BC5_00000000_00020000_31063...
  • This is the key under which some settings need to be changed:
  • et voila

    Monday, November 22, 2021

    A tiny and very handy CachedValue class

    In server-side programming it happens very often that getting a value takes a lot of time, but the result can be stored for some time. A classical answer to this is of course caching. The class below allows to wrap this in a very simple model.
    
    using System;
    
    namespace IBSoft.Helpers
    {
        public class CachedValue<T>
        {
            private T        value;
            private double   ttlInSeconds;
            private Func<T>  getValue;
            private DateTime expireAt = DateTime.MinValue;
    
            public CachedValue(int ttlInSeconds, Func<T> getValue)
            {
                this.ttlInSeconds = ttlInSeconds;
                this.getValue = getValue;
            }
    
            public T Value
            {
                get
                {
                    if (DateTime.UtcNow > this.expireAt)
                    {
                        T oldValue = this.value;
    
                        this.value = getValue();
    
                        var now = DateTime.UtcNow;
                        this.expireAt = now.AddSeconds(ttlInSeconds);
    
                        if (!this.value.Equals(oldValue))
                            this.LastValueUpdate = now;
                    }
    
                    return this.value;
                }
            }
    
            /// <summary>
            /// set when the value changes
            /// </summary>
            public DateTime LastValueUpdate { get; private set; }
    
            /// <summary>
            /// invalidates the value and causes reload on the next call
            /// </summary>
            public void Invalidate()
            {
                this.expireAt = DateTime.MinValue;
            }
    
            /// <summary>
            /// add implicit type conversion to T so that it's possible to use CacheValue<T> without the need to do cv.Value
            /// </summary>
            /// <param name="cv"></param>
            /// <returns></returns>
            public static implicit operator T(CachedValue<T> cv)
            {
                return cv.Value;
            }
        }
    }