Selaa lähdekoodia

Terra contract deployment moved to a separate k8s job (#130)

* Terra contract deployment moved to a separate k8s job

* terra-contracts job moved to the terrad stateful set as a sidecar, terra test addresses added to DEVELOP.md
Yuriy Savchenko 5 vuotta sitten
vanhempi
sitoutus
e8b411107d

+ 8 - 0
DEVELOP.md

@@ -127,3 +127,11 @@ using `kubectl exec solana-devnet-0 -c setup cli airdrop solana-devnet:9900` (se
 | `0xe78A0F7E598Cc8b0Bb87894B0F60dD2a88d6a8Ab` | Wrapped asset contract                                |
 | `0xCfEB869F69431e42cdB54A4F4f105C19C080A601` | Example ERC20 token                                   |
 | `0xf5b1d8fab1054b9cf7db274126972f97f9d42a11` | Wrapped asset address for the 6qRhs8oA... SPL token   |
+
+**Terra**
+
+| Account                                        | Description                                         |
+|------------------------------------------------|-----------------------------------------------------|
+| `terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v` | Main test account                                   |
+| `terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5` | Test token account to send via bridge               |
+| `terra174kgn5rtw4kf6f938wm7kwh70h2v4vcfd26jlc` | Bridge contract instance                            |

+ 8 - 2
Tiltfile

@@ -154,8 +154,14 @@ k8s_resource("web", port_forwards=[
 
 docker_build(
     ref = "terra-image",
-    context = "./terra/docker",
-    dockerfile = "terra/docker/Dockerfile",
+    context = "./terra/devnet",
+    dockerfile = "terra/devnet/Dockerfile",
+)
+
+docker_build(
+    ref = "terra-contracts",
+    context = "./terra",
+    dockerfile = "./terra/Dockerfile",
 )
 
 k8s_yaml("devnet/terra-devnet.yaml")

+ 2 - 0
devnet/terra-devnet.yaml

@@ -89,5 +89,7 @@ spec:
           httpGet:
             port: 26657
         resources: {}
+      - name: terra-contracts
+        image: terra-contracts
       restartPolicy: Always
   serviceName: terra-terrad

+ 3 - 0
terra/.dockerignore

@@ -0,0 +1,3 @@
+target
+tools/node_modules
+tools/dist

+ 26 - 0
terra/Dockerfile

@@ -0,0 +1,26 @@
+# This is a multi-stage docker file, first stage builds contracts
+# And the second one creates node.js environment to deploy them
+FROM cosmwasm/workspace-optimizer:0.10.4 AS builder
+ADD Cargo.lock /code/
+ADD Cargo.toml /code/
+ADD contracts /code/contracts
+RUN optimize_workspace.sh
+
+# Contract deployment stage
+FROM node:14
+
+RUN npm update && npm i -g typescript ts-node
+
+WORKDIR /app/tools
+
+COPY --from=builder /code/artifacts /app/artifacts
+ADD ./artifacts/cw20_base.wasm /app/artifacts/
+ADD ./tools /app/tools
+
+RUN chmod +x /app/tools/deploy.sh
+
+RUN npm install
+
+RUN ts-node --version
+
+ENTRYPOINT /app/tools/deploy.sh

+ 8 - 2
terra/Tiltfile

@@ -2,8 +2,14 @@
 
 docker_build(
     ref = "terra-image",
-    context = "./docker",
-    dockerfile = "./docker/Dockerfile",
+    context = "./devnet",
+    dockerfile = "./devnet/Dockerfile",
+)
+
+docker_build(
+    ref = "terra-contracts",
+    context = ".",
+    dockerfile = "./Dockerfile",
 )
 
 k8s_yaml("../devnet/terra-devnet.yaml")

+ 0 - 0
terra/docker/Dockerfile → terra/devnet/Dockerfile


+ 0 - 0
terra/docker/config/addrbook.json → terra/devnet/config/addrbook.json


+ 0 - 0
terra/docker/config/app.toml → terra/devnet/config/app.toml


+ 0 - 0
terra/docker/config/config.toml → terra/devnet/config/config.toml


+ 0 - 0
terra/docker/config/genesis.json → terra/devnet/config/genesis.json


+ 0 - 0
terra/docker/config/node_key.json → terra/devnet/config/node_key.json


+ 0 - 0
terra/docker/config/priv_validator_key.json → terra/devnet/config/priv_validator_key.json


+ 0 - 0
terra/docker/config/terrad.toml → terra/devnet/config/terrad.toml


+ 0 - 0
terra/docker/config/wasm.toml → terra/devnet/config/wasm.toml


+ 0 - 29
terra/docs/testing.md

@@ -1,29 +0,0 @@
-# Wormhole + Terra local test environment
-
-For the list of dependencies please follow [DEVELOP.md](../../DEVELOP.md).
-
-Additional dependencies:
-- [Node.js](https://nodejs.org/) >= 14.x, [ts-node](https://www.npmjs.com/package/ts-node) >= 8.x
-
-Start Tilt from the project root:
-
-    tilt up --update-mode=exec -- --num=1
-
-Afterwards use test scripts in `terra/tools` folder:
-
-    npm install
-    npm run prepare-token
-    npm run prepare-wormhole
-
-These commands will give you two important addresses: test token address and Wormhole contract address on Terra. 
-Now you need to change guardian configuration to monitor the right contract. Copy Wormhole contract address and
-replace existing `TERRA_FEE_PAYER` address in `devnet/bridge.yaml`.
-
-Save the changes and monitor Tilt dashboard until guardian services restart.
-
-Now use both token address and Wormhole contract address to issue tocken lock transaction:
-
-    npm run lock-tocken -- TOKEN_CONTRACT WORMHOLE_CONTRACT 1000
-
-Where 1000 is a sample amount to transfer. After this command is issued monitor Guardian service in Tilt dashboard
-to see its effects propagated to the destination blockchain (in this case it is Ethereum).

+ 5 - 0
terra/tools/deploy.sh

@@ -0,0 +1,5 @@
+npm run prepare-token http://terra-lcd:1317
+npm run prepare-wormhole http://terra-lcd:1317
+npm run lock-token terra18vd8fpwxzck93qlwghaj6arh4p7c5n896xzem5 terra174kgn5rtw4kf6f938wm7kwh70h2v4vcfd26jlc 1000 http://terra-lcd:1317
+echo "Going to sleep, interrupt if running manually"
+sleep infinity

+ 2 - 1
terra/tools/lock-token.ts

@@ -1,4 +1,4 @@
-import { execute_contract, query_contract } from './utils';
+import { init_lcd, execute_contract, query_contract } from './utils';
 
 async function script() {
     if (process.argv.length < 5) {
@@ -22,4 +22,5 @@ async function script() {
     console.log('Tokens locked');
 }
 
+init_lcd(process.argv[5]);
 script();

+ 56 - 0
terra/tools/package-lock.json

@@ -27,6 +27,11 @@
       "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.6.tgz",
       "integrity": "sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw=="
     },
+    "arg": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+      "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA=="
+    },
     "axios": {
       "version": "0.20.0",
       "resolved": "https://registry.npmjs.org/axios/-/axios-0.20.0.tgz",
@@ -123,6 +128,11 @@
         "safe-buffer": "^5.1.2"
       }
     },
+    "buffer-from": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
+    },
     "bufferutil": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.2.tgz",
@@ -180,6 +190,11 @@
       "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz",
       "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw=="
     },
+    "diff": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A=="
+    },
     "elliptic": {
       "version": "6.5.3",
       "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
@@ -243,6 +258,11 @@
       "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
       "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
     },
+    "make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
+    },
     "md5.js": {
       "version": "1.3.5",
       "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
@@ -383,6 +403,20 @@
         "safe-buffer": "^5.0.1"
       }
     },
+    "source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+    },
+    "source-map-support": {
+      "version": "0.5.19",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
+      "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
     "string_decoder": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -403,11 +437,28 @@
         "nan": "^2.13.2"
       }
     },
+    "ts-node": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.0.0.tgz",
+      "integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==",
+      "requires": {
+        "arg": "^4.1.0",
+        "diff": "^4.0.1",
+        "make-error": "^1.1.1",
+        "source-map-support": "^0.5.17",
+        "yn": "3.1.1"
+      }
+    },
     "typeforce": {
       "version": "1.18.0",
       "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz",
       "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
     },
+    "typescript": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz",
+      "integrity": "sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ=="
+    },
     "utf-8-validate": {
       "version": "5.0.3",
       "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.3.tgz",
@@ -433,6 +484,11 @@
       "version": "7.3.1",
       "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
       "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA=="
+    },
+    "yn": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+      "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q=="
     }
   }
 }

+ 5 - 3
terra/tools/package.json

@@ -1,7 +1,8 @@
 {
   "name": "terra-contract-tools",
   "version": "1.0.0",
-  "description": "",
+  "description": "Tools to build and deploy Terra contracts",
+  "repository": "https://github.com/certusone/wormhole",
   "main": "index.js",
   "scripts": {
     "build-contracts": "( cd .. && docker run --rm -v \"$(pwd)\":/code --mount type=volume,source=\"$(basename \"$(pwd)\")_cache\",target=/code/target --mount type=volume,source=registry_cache,target=/usr/local/cargo/registry cosmwasm/workspace-optimizer:0.10.4 )",
@@ -12,9 +13,10 @@
   },
   "author": "",
   "license": "ISC",
-  "type": "module",
   "dependencies": {
     "@terra-money/terra.js": "^0.5.12",
-    "@types/node": "^14.14.6"
+    "@types/node": "^14.14.6",
+    "ts-node": "^9.0.0",
+    "typescript": "^4.1.2"
   }
 }

+ 2 - 1
terra/tools/prepare-token.ts

@@ -1,4 +1,4 @@
-import { deploy_contract, instantiate_contract, query_contract } from './utils';
+import { init_lcd, deploy_contract, instantiate_contract, query_contract } from './utils';
 
 async function script() {
     const TEST_ADDRESS: string = 'terra1x46rqay4d3cssq8gxxvqz8xt6nwlz4td20k38v';
@@ -24,4 +24,5 @@ async function script() {
     console.log(`${TEST_ADDRESS} balance is ${result.balance}`);
 }
 
+init_lcd(process.argv[2]);
 script();

+ 2 - 1
terra/tools/prepare-wormhole.ts

@@ -1,4 +1,4 @@
-import { deploy_contract, instantiate_contract, query_contract } from './utils';
+import { init_lcd, deploy_contract, instantiate_contract, query_contract } from './utils';
 
 async function script() {
     // Deploy cw20-wrapped
@@ -23,4 +23,5 @@ async function script() {
     console.log(`Wormhole instance created at ${contract_address}`);
 }
 
+init_lcd(process.argv[2]);
 script();

+ 2 - 1
terra/tools/submit-vaa.ts

@@ -1,4 +1,4 @@
-import { execute_contract } from './utils';
+import { init_lcd, execute_contract } from './utils';
 
 async function script() {
     if (process.argv.length < 3) {
@@ -14,4 +14,5 @@ async function script() {
     console.log('Vaa submitted');
 }
 
+init_lcd(process.argv[3]);
 script();

+ 46 - 30
terra/tools/utils.ts

@@ -6,12 +6,21 @@ const mk = new MnemonicKey({
     mnemonic: 'notice oak worry limit wrap speak medal online prefer cluster roof addict wrist behave treat actual wasp year salad speed social layer crew genius'
 })
 
-// connect to localterra
-const terra = new LCDClient({
-    URL: 'http://localhost:1317',
-    chainID: 'localterra'
-});
-const wallet = terra.wallet(mk);
+let terra: LCDClient;
+let wallet;
+
+export function init_lcd(host_name='http://localhost:1317') {
+    // connect to localterra
+    terra = new LCDClient({
+        URL: host_name,
+        chainID: 'localterra'
+    });
+    wallet = terra.wallet(mk);
+}
+
+function delay(ms: number) {
+    return new Promise( resolve => setTimeout(resolve, ms) );
+}
 
 export async function deploy_contract(wasm_file) : Promise<number> {
   
@@ -19,31 +28,38 @@ export async function deploy_contract(wasm_file) : Promise<number> {
         wallet.key.accAddress,
         fs.readFileSync(wasm_file).toString('base64')
     );
-    try {
-        const storeCodeTx = await wallet.createAndSignTx({
-            msgs: [storeCode],
-        });
-        const storeCodeTxResult = await terra.tx.broadcast(storeCodeTx);
-
-        //console.log(storeCodeTxResult);
-
-        if (isTxError(storeCodeTxResult)) {
-            throw new Error(
-            `store code failed. code: ${storeCodeTxResult.code}, codespace: ${storeCodeTxResult.codespace}, raw_log: ${storeCodeTxResult.raw_log}`
-            );
-        }
-
-        const {
-            store_code: { code_id },
-        } = storeCodeTxResult.logs[0].eventsByType;
-
-        return parseInt(code_id[0], 10);
-    } catch (err) {
-        console.log(`Error ${err}`);
-        if (err.response) {
-            console.log(err.response.data);
+    let first_attempt = true;
+    for (;;) {
+        try {
+            const storeCodeTx = await wallet.createAndSignTx({
+                msgs: [storeCode],
+            });
+            const storeCodeTxResult = await terra.tx.broadcast(storeCodeTx);
+
+            //console.log(storeCodeTxResult);
+
+            if (isTxError(storeCodeTxResult)) {
+                throw new Error(
+                `store code failed. code: ${storeCodeTxResult.code}, codespace: ${storeCodeTxResult.codespace}, raw_log: ${storeCodeTxResult.raw_log}`
+                );
+            }
+
+            const {
+                store_code: { code_id },
+            } = storeCodeTxResult.logs[0].eventsByType;
+
+            return parseInt(code_id[0], 10);
+        } catch (err) {
+            // Only show error from the second time it shows to avoid spamming errors while initialization not yet finished
+            if (!first_attempt) {
+                console.log(`Error ${err}`);
+                if (err.response) {
+                    console.log(err.response.data);
+                }
+            }
+            first_attempt = false;
+            await delay(5000);
         }
-        return -1;
     }
 }