Repository: skalenetwork/IMA (language: python)

Issue:
ticket-1553 Fixed frong non-BN argument of PoW mined transaction sent to skaled
Fixed frong non-BN argument of PoW mined transaction sent to skaled


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/comprehensive.yml b/.github/workflows/comprehensive.yml
index d5d4d324c..d35d46307 100644
--- a/.github/workflows/comprehensive.yml
+++ b/.github/workflows/comprehensive.yml
@@ -86,22 +86,21 @@ jobs:
         echo ------------ lscpu
         lscpu || true
 
-    - name: UPDATE - system deps and install libc6, net-tools, btrfs-progs, zip, unzip, bash, procps
+    - name: UPDATE - system deps and install libc6, net-tools, btrfs-progs, zip, unzip, bash, procps, curl
       run: |
         sudo apt-get update
         sudo apt-get install libc6 net-tools btrfs-progs zip unzip
         sudo apt-get install bash
         sudo apt-get install procps
+        sudo apt-get install curl
 
-    - name: INIT - install docker with compose
+    - name: INIT - install docker
       run: |
-        echo " --------------------------- remove old packages ------------------------------------------------------------------------------------------------------ "
         sudo apt-get remove docker* containerd* || true
-        echo " --------------------------- install containerd.io ---------------------------------------------------------------------------------------------------- "
-        sudo apt-get install containerd.io
-        echo " --------------------------- install docker.io -------------------------------------------------------------------------------------------------------- "
-        echo " --------------------------- install docker-compose --------------------------------------------------------------------------------------------------- "
-        sudo apt-get install docker-compose
+        curl -fsSL https://get.docker.com -o install-docker.sh
+        sudo sh install-docker.sh
+        docker --version
+        docker-compose --version
 
     - name: INIT - reconfigure docker and restart its daemon
       run: |
diff --git a/agent/loop.mjs b/agent/loop.mjs
index 957d28337..0aaeaacef 100644
--- a/agent/loop.mjs
+++ b/agent/loop.mjs
@@ -408,6 +408,14 @@ async function singleTransferLoopPartS2S( optsLoop, strLogPrefix ) {
     return b3;
 }
 
+function printLoopPartSkippedWarning( strLoopPartName ) {
+    if( log.verboseGet() >= log.verboseReversed().warning ) {
+        log.write( strLogPrefix + cc.warning( "Skipped " ) + cc.notice( strLoopPartName ) +
+            cc.warning( " transfer loop part due to other single " +
+            "transfer loop is in progress right now" ) + "\n" );
+    }
+}
+
 export async function singleTransferLoop( optsLoop ) {
     const imaState = state.get();
     const strLogPrefix = cc.attention( "Single Loop in " ) +
@@ -415,32 +423,58 @@ export async function singleTransferLoop( optsLoop ) {
     try {
         if( log.verboseGet() >= log.verboseReversed().debug )
             log.write( strLogPrefix + cc.debug( imaHelperAPIs.longSeparator ) + "\n" );
-        if( ( optsLoop.enableStepOracle && imaState.loopState.oracle.isInProgress ) ||
-            ( optsLoop.enableStepM2S && imaState.loopState.m2s.isInProgress ) ||
-            ( optsLoop.enableStepS2M && imaState.loopState.s2m.isInProgress ) ||
-            ( optsLoop.enableStepS2S && imaState.loopState.s2s.isInProgress )
-        ) {
-            imaState.loopState.oracle.wasInProgress = false;
-            imaState.loopState.m2s.wasInProgress = false;
-            imaState.loopState.s2m.wasInProgress = false;
-            imaState.loopState.s2s.wasInProgress = false;
-            if( log.verboseGet() >= log.verboseReversed().warning ) {
-                log.write( strLogPrefix + cc.warning( "Skipped due to other single " +
-                    "transfer loop is in progress right now" ) + "\n" );
-            }
-            return true;
-        }
-        const b0 = await singleTransferLoopPartOracle( optsLoop, strLogPrefix );
-        const b1 = await singleTransferLoopPartM2S( optsLoop, strLogPrefix );
-        const b2 = await singleTransferLoopPartS2M( optsLoop, strLogPrefix );
-        const b3 = await singleTransferLoopPartS2S( optsLoop, strLogPrefix );
+        let b0 = false, b1 = false, b2 = false, b3 = false;
+        // Oracle loop part:
+        if( optsLoop.enableStepOracle ) {
+            if( imaState.loopState.oracle.isInProgress ) {
+                imaState.loopState.oracle.wasInProgress = false;
+                printLoopPartSkippedWarning( "Oracle" );
+                b0 = true;
+            } else
+                b0 = await singleTransferLoopPartOracle( optsLoop, strLogPrefix );
+        } else
+            b0 = true;
+        // M2S loop part:
+        if( optsLoop.enableStepM2S ) {
+            if( imaState.loopState.m2s.isInProgress ) {
+                imaState.loopState.m2s.wasInProgress = false;
+                printLoopPartSkippedWarning( "M2S" );
+                b1 = true;
+            } else
+                b1 = await singleTransferLoopPartM2S( optsLoop, strLogPrefix );
+        } else
+            b1 = true;
+        // S2M loop part:
+        if( optsLoop.enableStepS2M ) {
+            if( imaState.loopState.s2m.isInProgress ) {
+                imaState.loopState.s2m.wasInProgress = false;
+                printLoopPartSkippedWarning( "S2M" );
+                b2 = true;
+            } else
+                b2 = await singleTransferLoopPartS2M( optsLoop, strLogPrefix );
+        } else
+            b2 = true;
+        // S2S loop part:
+        if( optsLoop.enableStepS2S ) {
+            if( imaState.loopState.s2s.isInProgress ) {
+                imaState.loopState.s2s.wasInProgress = false;
+                printLoopPartSkippedWarning( "S2S" );
+                b3 = true;
+            } else
+                b3 = await singleTransferLoopPartS2S( optsLoop, strLogPrefix );
+        } else
+            b3 = true;
+        // Final status check loop part:
         const bResult = b0 && b1 && b2 && b3;
-        if( log.verboseGet() >= log.verboseReversed().notice )
-            log.write( strLogPrefix + cc.debug( "Completed: " ) + cc.tf( bResult ) + "\n" );
+        if( log.verboseGet() >= log.verboseReversed().notice ) {
+            log.write( strLogPrefix +
+                cc.debug( "Final completion status for all performed transfer loop parts is " ) +
+                cc.tf( bResult ) + "\n" );
+        }
         return bResult;
     } catch ( err ) {
         if( log.verboseGet() >= log.verboseReversed().error ) {
-            log.write( strLogPrefix + cc.fatal( "Exception in single transfer loop: " ) +
+            log.write( strLogPrefix + cc.fatal( "Exception in transfer loop: " ) +
                 cc.warning( owaspUtils.extractErrorMessage( err ) ) +
                 cc.error( ", stack is: " ) + "\n" + cc.stack( err.stack ) + "\n" );
         }
diff --git a/npms/skale-ima/imaTx.mjs b/npms/skale-ima/imaTx.mjs
index b0b80c7e8..ff6d0b342 100644
--- a/npms/skale-ima/imaTx.mjs
+++ b/npms/skale-ima/imaTx.mjs
@@ -277,7 +277,8 @@ async function payedCallSGX( optsPayedCall ) {
         encoding: "utf-8"
     };
     const rv = childProcessModule.spawnSync( strCmd, joSpawnOptions );
-    optsPayedCall.joReceipt = JSON.parse( rv.stdout.toString( "utf8" ) );
+    const strStdOutFromExternalInvocation = rv.stdout.toString( "utf8" );
+    optsPayedCall.joReceipt = JSON.parse( strStdOutFromExternalInvocation.toString( "utf8" ) );
     if( log.verboseGet() >= log.verboseReversed().trace ) {
         optsPayedCall.details.write( optsPayedCall.strLogPrefix +
             cc.debug( "Result from external SGX signer is: " ) +
@@ -530,7 +531,7 @@ export async function checkTransactionToSchain(
                 throw new Error(
                     "Failed to compute gas price with PoW-mining (2), got zero value" );
             }
-            unsignedTx.gasPrice = powNumber.toHexString();
+            unsignedTx.gasPrice = owaspUtils.toBN( powNumber.toHexString() );
             if( log.verboseGet() >= log.verboseReversed().trace ) {
                 details.write( strLogPrefix + cc.success( "Success, finally (after PoW-mining) " +
                     "modified unsigned transaction is " ) + cc.j( unsignedTx ) + "\n" );
diff --git a/npms/skale-ima/index.mjs b/npms/skale-ima/index.mjs
index d4bd0fcd7..930765d15 100644
--- a/npms/skale-ima/index.mjs
+++ b/npms/skale-ima/index.mjs
@@ -1561,11 +1561,11 @@ export async function doAllS2S( // s-chain --> s-chain
         let s = cc.debug( "Stats for S2S steps in " ) +
             threadInfo.threadDescription() + cc.debug( ": " );
         if( cntOK > 0 ) {
-            s += " " + cc.info( cntOK ) +
+            s += " " + cc.info( cntOK ) + " " +
                 cc.success( "S-Chain(s) processed OKay" ) + cc.debug( ", " );
         }
         if( cntFail > 0 ) {
-            s += " " + cc.info( cntFail ) +
+            s += " " + cc.info( cntFail ) + " " +
                 cc.error( "S-Chain(s) failed" );
         }
         log.write( s + "\n" );
diff --git a/npms/skale-observer/observer.mjs b/npms/skale-observer/observer.mjs
index 68384cfeb..41a10f63b 100644
--- a/npms/skale-observer/observer.mjs
+++ b/npms/skale-observer/observer.mjs
@@ -648,6 +648,49 @@ export async function loadCachedSChainsSimplified( addressFrom, opts ) {
     return arrSChains;
 }
 
+async function checkWhetherSChainIsConnected( strSChainName, joMessageProxySChain, opts ) {
+    let isConnected = false, isQueryPassed = false;
+    const cntAttempts = (
+        "cntAttemptsCheckConnectedState" in opts &&
+        typeof opts.cntAttemptsCheckConnectedState == "number" &&
+        opts.cntAttemptsCheckConnectedState > 0 )
+        ? opts.cntAttemptsCheckConnectedState : 3;
+    for( let idxAttempt = 0; idxAttempt < cntAttempts; ++ idxAttempt ) {
+        try {
+            isConnected =
+                await joMessageProxySChain.callStatic.isConnectedChain( strSChainName );
+            isQueryPassed = true;
+            break;
+        } catch ( err ) {
+            isConnected = false;
+            if( opts && opts.details ) {
+                if( log.verboseGet() >= log.verboseReversed().error ) {
+                    opts.details.write( cc.error( "Failed attempt " ) +
+                        cc.info( idxAttempt ) + cc.error( " of " ) +
+                        cc.info( cntAttempts ) +
+                        cc.error( " to query connected state of " ) +
+                        cc.info( strSChainName ) + cc.debug( " and S-Chain, got error: " ) +
+                        cc.warning( owaspUtils.extractErrorMessage( err ) ) +
+                        cc.error( ", stack is: " ) + "\n" + cc.stack( err.stack ) + "\n" );
+                }
+            }
+        }
+    }
+    if( opts && opts.details ) {
+        if( ! isQueryPassed ) {
+            if( log.verboseGet() >= log.verboseReversed().warning ) {
+                opts.details.write( cc.debug( "Will assume S-Chain " ) +
+                    cc.info( strSChainName ) + cc.debug( " connected status: " ) +
+                    cc.yn( isConnected ) + "\n" );
+            }
+        } else if( log.verboseGet() >= log.verboseReversed().trace ) {
+            opts.details.write( cc.debug( "Got S-Chain " ) + cc.info( strSChainName ) +
+                cc.debug( " connected status: " ) + cc.yn( isConnected ) + "\n" );
+        }
+    }
+    return isConnected;
+}
+
 export async function loadSChainsConnectedOnly( strChainNameConnectedTo, opts ) {
     if( ! opts.imaState ) {
         throw new Error( "Cannot load S-Chains in observer, no imaState is provided in " +
@@ -691,7 +734,6 @@ export async function loadSChainsConnectedOnly( strChainNameConnectedTo, opts )
             }
             if( opts && opts.bStopNeeded )
                 break;
-
             if( strChainNameConnectedTo == strSChainName ) {
                 if( opts && opts.details ) {
                     if( log.verboseGet() >= log.verboseReversed().trace ) {
@@ -709,14 +751,8 @@ export async function loadSChainsConnectedOnly( strChainNameConnectedTo, opts )
                         cc.info( strChainNameConnectedTo ) + cc.debug( "..." ) + "\n" );
                 }
             }
-            const isConnected =
-                await joMessageProxySChain.callStatic.isConnectedChain( strSChainName );
-            if( opts && opts.details ) {
-                if( log.verboseGet() >= log.verboseReversed().trace ) {
-                    opts.details.write( cc.debug( "Got S-Chain " ) + cc.info( strSChainName ) +
-                        cc.debug( " connected status: " ) + cc.yn( isConnected ) + "\n" );
-                }
-            }
+            const isConnected = await checkWhetherSChainIsConnected(
+                strSChainName, joMessageProxySChain, opts );
             if( ! isConnected )
                 continue;
             const joSChain = await loadSChain( idxSChain, strSChainHash, null, cntSChains, opts );
@@ -768,12 +804,8 @@ export async function checkConnectedSChains( strChainNameConnectedTo, arrSChains
                     opts.imaState.chainProperties.sc.joAbiIMA.message_proxy_chain_abi,
                     ethersProvider
                 );
-            joSChain.isConnected =
-                await joMessageProxySChain.callStatic.isConnectedChain( strChainNameConnectedTo );
-            if( opts && opts.details ) {
-                if( log.verboseGet() >= log.verboseReversed().trace )
-                    opts.details.write( cc.debug( "Got " ) + cc.yn( joSChain.isConnected ) + "\n" );
-            }
+            joSChain.isConnected = await checkWhetherSChainIsConnected(
+                strChainNameConnectedTo, joMessageProxySChain, opts );
         } catch ( err ) {
             if( opts && opts.details ) {
                 if( log.verboseGet() >= log.verboseReversed().error ) {


Test patch:
diff --git a/.github/workflows/container-test.yml b/.github/workflows/container-test.yml
index 9b401417d..94fe0ffa9 100644
--- a/.github/workflows/container-test.yml
+++ b/.github/workflows/container-test.yml
@@ -86,22 +86,21 @@ jobs:
         echo ------------ lscpu
         lscpu || true
 
-    - name: UPDATE - system deps and install libc6, net-tools, btrfs-progs, zip, unzip, bash, procps
+    - name: UPDATE - system deps and install libc6, net-tools, btrfs-progs, zip, unzip, bash, procps, curl
       run: |
         sudo apt-get update
         sudo apt-get install libc6 net-tools btrfs-progs zip unzip
         sudo apt-get install bash
         sudo apt-get install procps
+        sudo apt-get install curl
 
-    - name: INIT - install docker with compose
+    - name: INIT - install docker
       run: |
-        echo " --------------------------- remove old packages ------------------------------------------------------------------------------------------------------ "
         sudo apt-get remove docker* containerd* || true
-        echo " --------------------------- install containerd.io ---------------------------------------------------------------------------------------------------- "
-        sudo apt-get install containerd.io
-        echo " --------------------------- install docker.io -------------------------------------------------------------------------------------------------------- "
-        echo " --------------------------- install docker-compose --------------------------------------------------------------------------------------------------- "
-        sudo apt-get install docker-compose
+        curl -fsSL https://get.docker.com -o install-docker.sh
+        sudo sh install-docker.sh
+        docker --version
+        docker-compose --version
 
     - name: INIT - reconfigure docker and restart its daemon
       run: |