initial implementation of backend
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 36s Details

This commit is contained in:
Ladd Hoffman 2024-02-23 13:48:43 -06:00
parent ff5f92b1ba
commit d8d8b1a9c6
31 changed files with 4332 additions and 54 deletions

View File

@ -1,43 +0,0 @@
#![no_std]
#![no_main]
extern crate alloc;
pub mod constants;
pub mod entry_points;
mod error;
use alloc::{
collections::BTreeMap,
format,
string::{String, ToString},
vec,
vec::Vec,
};
//use casper_contract::contract_api::{self};
use casper_contract::{
contract_api::{
runtime::{self, get_caller, get_key, get_named_arg, put_key, revert},
storage::{self, dictionary_put},
},
unwrap_or_revert::UnwrapOrRevert,
};
use casper_types::{
bytesrepr::ToBytes, contracts::NamedKeys, runtime_args, CLValue, ContractHash,
ContractPackageHash, Key, RuntimeArgs, U256,
};
#[no_mangle]
pub extern "C" fn name() {
runtime::ret(CLValue::from_t("hi").unwrap_or_revert());
}
#[no_mangle]
pub extern "C" fn stake_availability() {}
#[no_mangle]
pub extern "C" fn assign_work() {}
#[no_mangle]
pub extern "C" fn get_assigned_work() {}

21
backend/.eslintrc.cjs Normal file
View File

@ -0,0 +1,21 @@
module.exports = {
root: true,
env: { es2020: true },
extends: [
'eslint:recommended',
'airbnb',
],
ignorePatterns: ['.eslintrc.cjs'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
rules: {
'no-console': 'off',
"import/no-extraneous-dependencies": [
"error",
{
"devDependencies": false,
"optionalDependencies": false,
"peerDependencies": false,
}
]
}
}

2
backend/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
node_modules/
.env

0
backend/Dockerfile Normal file
View File

View File

40
backend/index.js Normal file
View File

@ -0,0 +1,40 @@
const express = require('express');
require('dotenv').config();
const app = express();
const port = process.env.PORT || 3000;
const {
CasperClient, DeployUtil, Contracts: { Contract },
} = require('casper-js-sdk');
const RPC_API = 'http://65.109.56.30:7777/rpc';
const casperClient = new CasperClient(RPC_API);
const contract = new Contract(casperClient);
contract.setContractHash('hash-9d6641378c5859e4a0367b37f358d9861496318ba814bdd92903210a3f633198');
app.use(express.json());
app.post('/sendDeploy', async (req, res) => {
const { body: deployJson } = req;
const deploy = DeployUtil.deployFromJson(deployJson).unwrap();
const deployHash = await casperClient.putDeploy(deploy);
res.status(200).send(`Deploy hash: ${deployHash}`);
});
app.get('/queryMessage', async (req, res) => {
const result = await contract.queryContractData(['message']);
console.log('query result:', result);
res.send(result);
});
app.get('*', (req, res) => {
console.log(`req.path: ${req.path}`);
res.send('Hello World!');
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});

4003
backend/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

25
backend/package.json Normal file
View File

@ -0,0 +1,25 @@
{
"name": "backend",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"axios": "^1.6.7",
"casper-js-sdk": "^2.15.4",
"dotenv": "^16.4.5",
"express": "^4.18.2"
},
"devDependencies": {
"eslint": "^8.56.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0"
}
}

View File

@ -8,7 +8,7 @@ module.exports = {
'plugin:react/jsx-runtime',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
ignorePatterns: ['dist', '.eslintrc.cjs', 'vite.config.js'],
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
settings: { react: { version: '18.2' } },
plugins: ['react-refresh'],

View File

@ -1,5 +1,7 @@
import { useState } from 'react';
import Connect from './Connect';
import UpdateMessage from './UpdateMessage';
import Query from './Query';
import './App.css';
function App() {
@ -14,6 +16,8 @@ function App() {
{' '}
{publicKey}
<br />
<UpdateMessage publicKey={publicKey} />
<Query publicKey={publicKey} />
</>
)}
</div>

20
client/src/Query.jsx Normal file
View File

@ -0,0 +1,20 @@
import axios from 'axios';
import { CLPublicKey } from 'casper-js-sdk';
const query = (props) => {
const accountHash = CLPublicKey.fromHex(props.publicKey).toAccountHashStr().substring(13);
axios
.get(`/api/queryMessage?accountHash=${accountHash}`)
.then((response) => {
alert(response.data);
})
.catch((error) => {
console.error(error.message);
});
};
function Query(props) {
return <button type="button" onClick={() => query(props)}>Query</button>;
}
export default Query;

View File

@ -0,0 +1,78 @@
import { useState } from 'react';
import {
Contracts, RuntimeArgs, CLValueBuilder, CLPublicKey, DeployUtil,
} from 'casper-js-sdk';
import axios from 'axios';
import getProvider from './casper-wallet';
const provider = getProvider();
const NETWORK_NAME = 'casper-test'; // "casper" for mainnet
const CONTRACT_HASH = 'hash-9d6641378c5859e4a0367b37f358d9861496318ba814bdd92903210a3f633198';
const updateMessage = (props, message) => {
const contract = new Contracts.Contract();
contract.setContractHash(CONTRACT_HASH);
const runtimeArguments = RuntimeArgs.fromMap({
message: CLValueBuilder.string(message),
});
const deploy = contract.callEntrypoint(
'hello',
runtimeArguments,
CLPublicKey.fromHex(props.publicKey),
NETWORK_NAME,
'1000000000', // 1 CSPR (10^9 Motes)
);
const deployJSON = DeployUtil.deployToJson(deploy);
// Initiates sign request
provider
.sign(JSON.stringify(deployJSON), props.publicKey)
.then((res) => {
if (res.cancelled) {
alert('Signing cancelled');
} else {
const signedDeploy = DeployUtil.setSignature(
deploy,
res.signature,
CLPublicKey.fromHex(props.publicKey),
);
console.log('signedDeploy:', signedDeploy);
console.log('signedDeploy json:', DeployUtil.deployToJson(signedDeploy));
axios
.post('/api/sendDeploy', DeployUtil.deployToJson(signedDeploy), {
headers: {
'Content-Type': 'application/json',
},
})
.then((response) => {
alert(response.data);
})
.catch((error) => {
console.error(error.message);
});
}
})
.catch((error) => {
console.error(error.message);
});
};
function UpdateMessage(props) {
const [message, setMessage] = useState('');
return (
<>
<input
id="message"
type="text"
value={message}
onChange={(e) => {
setMessage(e.target.value);
}}
/>
<button type="button" onClick={() => updateMessage(props, message)}>Update Message</button>
</>
);
}
export default UpdateMessage;

View File

@ -1,7 +1,11 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
})
server: {
host: '0.0.0.0',
port: 3002
}
});

View File

View File

@ -4,6 +4,7 @@ members = [
"availability",
"work-1",
]
resolver = "2"
[profile.release]
codegen-units = 1

View File

@ -1,12 +1,12 @@
[package]
name = "availability"
version = "0.1.0"
edition = "2018"
edition = "2021"
description = "Contract that receives reputation stakes from a worker and makes them available to one or more work contracts"
[dependencies]
casper-contract = "2.0.0"
casper-types = "2.0.0"
casper-contract = "4.0.0"
casper-types = "4.0.1"
[[bin]]
name = "availability"

View File

@ -1,6 +1,6 @@
//! Entry points
use alloc::{string::String, vec};
use alloc::{string::String, vec, vec::Vec};
use casper_types::{
CLType, CLTyped, EntryPoint, EntryPointAccess, EntryPointType, EntryPoints, Key, Parameter,
@ -12,6 +12,26 @@ use crate::constants::{
STAKE_AVAILABILITY_ENTRY_POINT_NAME, WORKER, WORK_CONTRACT,
};
pub fn hello() -> EntryPoint {
EntryPoint::new(
String::from("hello"),
vec![Parameter::new("message", String::cl_type())],
String::cl_type(),
EntryPointAccess::Public,
EntryPointType::Contract,
)
}
pub fn query() -> EntryPoint {
EntryPoint::new(
String::from("query"),
Vec::new(),
CLType::Unit,
EntryPointAccess::Public,
EntryPointType::Contract,
)
}
// Entry point: Stake availability toward one or more work contracts
pub fn stake_availability() -> EntryPoint {
EntryPoint::new(
@ -47,8 +67,10 @@ pub fn get_assigned_work() -> EntryPoint {
pub fn generate_entry_points() -> EntryPoints {
let mut entry_points = EntryPoints::new();
entry_points.add_entry_point(stake_availability());
entry_points.add_entry_point(assign_work());
entry_points.add_entry_point(get_assigned_work());
entry_points.add_entry_point(hello());
entry_points.add_entry_point(query());
// entry_points.add_entry_point(stake_availability());
// entry_points.add_entry_point(assign_work());
// entry_points.add_entry_point(get_assigned_work());
entry_points
}

View File

@ -0,0 +1,101 @@
#![no_std]
#![no_main]
extern crate alloc;
pub mod constants;
pub mod entry_points;
mod error;
use alloc::{
collections::BTreeMap,
format,
string::{String, ToString},
vec,
vec::Vec,
};
//use casper_contract::contract_api::{self};
use casper_contract::{
contract_api::{
runtime::{self, get_caller, get_key, get_named_arg, put_key, revert},
storage::{self, dictionary_put},
},
unwrap_or_revert::UnwrapOrRevert,
};
use casper_types::{
api_error::ApiError, bytesrepr::ToBytes, contracts::NamedKeys, runtime_args, CLValue,
ContractHash, ContractPackageHash, Key, RuntimeArgs, URef, U256,
};
use entry_points::generate_entry_points;
const CONTRACT_PACKAGE_NAME: &str = "package_name";
const CONTRACT_ACCESS_UREF: &str = "access_uref";
const CONTRACT_VERSION_KEY: &str = "version";
const CONTRACT_KEY: &str = "availability";
const MESSAGE_KEY: &str = "message";
#[no_mangle]
pub extern "C" fn hello() {
let message: String = runtime::get_named_arg("message");
let uref: URef = runtime::get_key(MESSAGE_KEY)
.unwrap_or_revert_with(ApiError::MissingKey)
.into_uref()
.unwrap_or_revert_with(ApiError::UnexpectedKeyVariant);
storage::write(uref, message);
}
#[no_mangle]
pub extern "C" fn query() {
let uref: URef = runtime::get_key(MESSAGE_KEY)
.unwrap_or_revert_with(ApiError::MissingKey)
.into_uref()
.unwrap_or_revert_with(ApiError::UnexpectedKeyVariant);
let result: String = storage::read(uref)
.unwrap_or_revert_with(ApiError::Read)
.unwrap_or_revert_with(ApiError::ValueNotFound);
let typed_result = CLValue::from_t(result).unwrap_or_revert();
runtime::ret(typed_result); // Return the message value.
}
#[no_mangle]
pub extern "C" fn stake_availability() {}
#[no_mangle]
pub extern "C" fn assign_work() {}
#[no_mangle]
pub extern "C" fn get_assigned_work() {}
// Entry point that executes automatically when a caller installs the contract.
#[no_mangle]
pub extern "C" fn call() {
let message = storage::new_uref("initial message");
// In the named keys of the contract, add a key for the message
let mut named_keys = NamedKeys::new();
let key_name = String::from(MESSAGE_KEY);
named_keys.insert(key_name, message.into());
// Create the entry points for this contract.
let entry_points = generate_entry_points();
// Create a new contract package that can be upgraded.
let (stored_contract_hash, contract_version) = storage::new_contract(
entry_points,
Some(named_keys),
Some(CONTRACT_PACKAGE_NAME.to_string()),
Some(CONTRACT_ACCESS_UREF.to_string()),
);
/* To create a locked contract instead, use new_locked_contract and throw away the contract version returned.
let (stored_contract_hash, _) =
storage::new_locked_contract(counter_entry_points, Some(counter_named_keys), None, None); */
// Store the contract version in the context's named keys.
let version_uref = storage::new_uref(contract_version);
runtime::put_key(CONTRACT_VERSION_KEY, version_uref.into());
// Create a named key for the contract hash.
runtime::put_key(CONTRACT_KEY, stored_contract_hash.into());
}

View File