-
Notifications
You must be signed in to change notification settings - Fork 211
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This PR aims to make Solang support a simple counter.sol example on Soroban, where a storage variable is instatiated, modified and retrieved. The counter contract is only limited to `uint64` data types, and only supports `instance` soroban storage. This can be considered a "skeleton" for supporting more data and storage types, as well as more host function invokations. - [x] Support Soroban storage function calls `put_contract_data`, `get_contract_data` and `has_contract_data` - [x] Implement a wrapper `init` for `storage_initializer` - [x] Implement wrappers for public functions - [x] Insert decoding/encoding instructions into the wrapper functions - [x] Soroban doesn't have function return codes. This needs to be handled all over emit - [x] Add integration tests and MockVm tests --------- Signed-off-by: salaheldinsoliman <[email protected]>
- Loading branch information
1 parent
08dbe49
commit 399c199
Showing
25 changed files
with
794 additions
and
126 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -306,6 +306,48 @@ jobs: | |
with: | ||
name: anchor-tests | ||
path: ./target/*.profraw | ||
|
||
soroban: | ||
name: Soroban Integration test | ||
runs-on: solang-ubuntu-latest | ||
container: ghcr.io/hyperledger/solang-llvm:ci-7 | ||
needs: linux-x86-64 | ||
steps: | ||
- name: Checkout sources | ||
uses: actions/checkout@v3 | ||
- uses: actions/setup-node@v3 | ||
with: | ||
node-version: '16' | ||
- uses: dtolnay/[email protected] | ||
- uses: actions/download-artifact@v3 | ||
with: | ||
name: solang-linux-x86-64 | ||
path: bin | ||
- name: Solang Compiler | ||
run: | | ||
chmod 755 ./bin/solang | ||
echo "$(pwd)/bin" >> $GITHUB_PATH | ||
- name: Install Soroban | ||
run: cargo install --locked soroban-cli --version 21.0.0-rc.1 | ||
- name: Add cargo install location to PATH | ||
run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH | ||
- run: npm install | ||
working-directory: ./integration/soroban | ||
- name: Build Solang contracts | ||
run: npm run build | ||
working-directory: ./integration/soroban | ||
- name: Setup Soroban enivronment | ||
run: npm run setup | ||
working-directory: ./integration/soroban | ||
- name: Deploy and test contracts | ||
run: npm run test | ||
working-directory: ./integration/soroban | ||
- name: Upload test coverage files | ||
uses: actions/[email protected] | ||
with: | ||
name: soroban-tests | ||
path: ./target/*.profraw | ||
|
||
solana: | ||
name: Solana Integration test | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
*.js | ||
*.so | ||
*.key | ||
*.json | ||
!tsconfig.json | ||
!package.json | ||
node_modules | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
contract counter { | ||
uint64 public count = 10; | ||
|
||
function increment() public returns (uint64) { | ||
count += 1; | ||
return count; | ||
} | ||
|
||
function decrement() public returns (uint64) { | ||
count -= 1; | ||
return count; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import * as StellarSdk from '@stellar/stellar-sdk'; | ||
import { readFileSync } from 'fs'; | ||
import { expect } from 'chai'; | ||
import path from 'path'; | ||
import { fileURLToPath } from 'url'; | ||
import { call_contract_function } from './test_helpers.js'; | ||
|
||
const __filename = fileURLToPath(import.meta.url); | ||
const dirname = path.dirname(__filename); | ||
|
||
describe('Counter', () => { | ||
let keypair; | ||
const server = new StellarSdk.SorobanRpc.Server( | ||
"https://soroban-testnet.stellar.org:443", | ||
); | ||
|
||
let contractAddr; | ||
let contract; | ||
before(async () => { | ||
|
||
console.log('Setting up counter contract tests...'); | ||
|
||
// read secret from file | ||
const secret = readFileSync('alice.txt', 'utf8').trim(); | ||
keypair = StellarSdk.Keypair.fromSecret(secret); | ||
|
||
let contractIdFile = path.join(dirname, '.soroban', 'contract-ids', 'counter.txt'); | ||
// read contract address from file | ||
contractAddr = readFileSync(contractIdFile, 'utf8').trim().toString(); | ||
|
||
// load contract | ||
contract = new StellarSdk.Contract(contractAddr); | ||
|
||
// initialize the contract | ||
await call_contract_function("init", server, keypair, contract); | ||
|
||
}); | ||
|
||
it('get correct initial counter', async () => { | ||
// get the count | ||
let count = await call_contract_function("count", server, keypair, contract); | ||
expect(count.toString()).eq("10"); | ||
}); | ||
|
||
it('increment counter', async () => { | ||
// increment the counter | ||
await call_contract_function("increment", server, keypair, contract); | ||
|
||
// get the count | ||
let count = await call_contract_function("count", server, keypair, contract); | ||
expect(count.toString()).eq("11"); | ||
}); | ||
}); | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"type": "module", | ||
"dependencies": { | ||
"@stellar/stellar-sdk": "^12.0.1", | ||
"chai": "^5.1.1", | ||
"dotenv": "^16.4.5", | ||
"mocha": "^10.4.0" | ||
}, | ||
"scripts": { | ||
"build": "solang compile *.sol --target soroban", | ||
"setup": "node setup.js", | ||
"test": "mocha *.spec.js --timeout 20000" | ||
}, | ||
"devDependencies": { | ||
"@eslint/js": "^9.4.0", | ||
"@types/mocha": "^10.0.6", | ||
"eslint": "^9.4.0", | ||
"expect": "^29.7.0", | ||
"globals": "^15.4.0", | ||
"typescript": "^5.4.5" | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
|
||
import 'dotenv/config'; | ||
import { mkdirSync, readdirSync} from 'fs'; | ||
import { execSync } from 'child_process'; | ||
import path from 'path'; | ||
import { fileURLToPath } from 'url'; | ||
|
||
console.log("###################### Initializing ########################"); | ||
|
||
// Get dirname (equivalent to the Bash version) | ||
const __filename = fileURLToPath(import.meta.url); | ||
const dirname = path.dirname(__filename); | ||
|
||
// variable for later setting pinned version of soroban in "$(dirname/target/bin/soroban)" | ||
const soroban = "soroban" | ||
|
||
// Function to execute and log shell commands | ||
function exe(command) { | ||
console.log(command); | ||
execSync(command, { stdio: 'inherit' }); | ||
} | ||
|
||
function generate_alice() { | ||
exe(`${soroban} keys generate alice --network testnet`); | ||
|
||
// get the secret key of alice and put it in alice.txt | ||
exe(`${soroban} keys show alice > alice.txt`); | ||
} | ||
|
||
|
||
function filenameNoExtension(filename) { | ||
return path.basename(filename, path.extname(filename)); | ||
} | ||
|
||
function deploy(wasm) { | ||
|
||
let contractId = path.join(dirname, '.soroban', 'contract-ids', filenameNoExtension(wasm) + '.txt'); | ||
|
||
exe(`(${soroban} contract deploy --wasm ${wasm} --ignore-checks --source-account alice --network testnet) > ${contractId}`); | ||
} | ||
|
||
function deploy_all() { | ||
const contractsDir = path.join(dirname, '.soroban', 'contract-ids'); | ||
mkdirSync(contractsDir, { recursive: true }); | ||
|
||
const wasmFiles = readdirSync(`${dirname}`).filter(file => file.endsWith('.wasm')); | ||
|
||
wasmFiles.forEach(wasmFile => { | ||
deploy(path.join(dirname, wasmFile)); | ||
}); | ||
} | ||
|
||
function add_testnet() { | ||
|
||
exe(`${soroban} network add \ | ||
--global testnet \ | ||
--rpc-url https://soroban-testnet.stellar.org:443 \ | ||
--network-passphrase "Test SDF Network ; September 2015"`); | ||
} | ||
|
||
add_testnet(); | ||
generate_alice(); | ||
deploy_all(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import * as StellarSdk from '@stellar/stellar-sdk'; | ||
|
||
|
||
|
||
export async function call_contract_function(method, server, keypair, contract) { | ||
|
||
let res; | ||
let builtTransaction = new StellarSdk.TransactionBuilder(await server.getAccount(keypair.publicKey()), { | ||
fee: StellarSdk.BASE_FEE, | ||
networkPassphrase: StellarSdk.Networks.TESTNET, | ||
}).addOperation(contract.call(method)).setTimeout(30).build(); | ||
|
||
let preparedTransaction = await server.prepareTransaction(builtTransaction); | ||
|
||
// Sign the transaction with the source account's keypair. | ||
preparedTransaction.sign(keypair); | ||
|
||
try { | ||
let sendResponse = await server.sendTransaction(preparedTransaction); | ||
if (sendResponse.status === "PENDING") { | ||
let getResponse = await server.getTransaction(sendResponse.hash); | ||
// Poll `getTransaction` until the status is not "NOT_FOUND" | ||
while (getResponse.status === "NOT_FOUND") { | ||
console.log("Waiting for transaction confirmation..."); | ||
// See if the transaction is complete | ||
getResponse = await server.getTransaction(sendResponse.hash); | ||
// Wait one second | ||
await new Promise((resolve) => setTimeout(resolve, 1000)); | ||
} | ||
|
||
if (getResponse.status === "SUCCESS") { | ||
// Make sure the transaction's resultMetaXDR is not empty | ||
if (!getResponse.resultMetaXdr) { | ||
throw "Empty resultMetaXDR in getTransaction response"; | ||
} | ||
// Find the return value from the contract and return it | ||
let transactionMeta = getResponse.resultMetaXdr; | ||
let returnValue = transactionMeta.v3().sorobanMeta().returnValue(); | ||
console.log(`Transaction result: ${returnValue.value()}`); | ||
res = returnValue.value(); | ||
} else { | ||
throw `Transaction failed: ${getResponse.resultXdr}`; | ||
} | ||
} else { | ||
throw sendResponse.errorResultXdr; | ||
} | ||
} catch (err) { | ||
// Catch and report any errors we've thrown | ||
console.log("Sending transaction failed"); | ||
console.log(err); | ||
} | ||
return res; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.