Skip to content

Commit

Permalink
added high res timer for triggers, testing all features
Browse files Browse the repository at this point in the history
  • Loading branch information
TrevorJTClarke committed Feb 3, 2022
1 parent 43ddbfa commit b78633f
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 30 deletions.
1 change: 1 addition & 0 deletions src/configuration.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const NEAR_ENV = process.env.NEAR_ENV || 'testnet'
export const LOG_LEVEL = process.env.LOG_LEVEL || 'info'
export const BETA_FEATURES = process.env.BETA_FEATURES === 'true' ? true : false
export const WAIT_INTERVAL_MS = process.env.WAIT_INTERVAL_MS ? parseInt(`${process.env.WAIT_INTERVAL_MS}`) : 30000
export const TRIGGER_INTERVAL_MS = process.env.TRIGGER_INTERVAL_MS ? parseInt(`${process.env.TRIGGER_INTERVAL_MS}`) : 10000
export const AGENT_ACCOUNT_ID = process.env.AGENT_ACCOUNT_ID || 'croncat-agent'
export const AGENT_MIN_TASK_BALANCE = utils.format.parseNearAmount(`${process.env.AGENT_MIN_TASK_BALANCE || '1'}`) // Default: 1_000_000_000_000_000_000_000_000 (1 NEAR)
export const AGENT_AUTO_REFILL = process.env.AGENT_AUTO_REFILL === 'true' ? true : false
Expand Down
5 changes: 2 additions & 3 deletions src/tasks.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as config from './configuration'
import * as agent from './agent'
import * as util from './util'
import { utils } from 'near-api-js'
import chalk from 'chalk'
Expand Down Expand Up @@ -108,8 +107,8 @@ export const proxyCall = async () => {
try {
const res = await manager.proxy_call({
args: {},
gas: BASE_GAS_FEE,
amount: BASE_ATTACHED_PAYMENT,
gas: config.BASE_GAS_FEE,
amount: config.BASE_ATTACHED_PAYMENT,
})
if (config.LOG_LEVEL === 'debug') console.log(res)
if (config.LOG_LEVEL === 'debug') console.log(`${chalk.yellowBright('TX:' + res.transaction_outcome.id)}`)
Expand Down
70 changes: 44 additions & 26 deletions src/triggers.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import * as config from './configuration'
import * as util from './util'
import chalk from 'chalk'

let cache = []
let lastCacheCheckTs = +new Date()
// Update cache every slot duration (60 blocks)
const CACHE_DELAY = 60 * 1000
const TIME_GRANULARITY = 100 * 10000
let lastCacheCheckTs = +new Date() - CACHE_DELAY
let triggersProcessed = 0

// Get trigger list
export const getTriggers = async (from_index = 0, limit = 100) => {
Expand All @@ -14,7 +17,6 @@ export const getTriggers = async (from_index = 0, limit = 100) => {
try {
// Only get task hashes my agent can execute
triggers = await manager.get_triggers({ from_index: `${from_index}`, limit: `${limit}` })
console.log('triggers', triggers)
} catch (e) {
if (config.LOG_LEVEL === 'debug') console.log('getTriggers', e)
}
Expand All @@ -24,6 +26,7 @@ export const getTriggers = async (from_index = 0, limit = 100) => {

// Get trigger cache
// cache for current triggers list & configs
// TODO: Add logging & stats logging if desired
export const getAllTriggers = async () => {
if (lastCacheCheckTs + CACHE_DELAY > +new Date()) return cache
cache = []
Expand All @@ -40,29 +43,37 @@ export const getAllTriggers = async () => {
}
await loopRetrieve()
lastCacheCheckTs = +new Date()

// stats logging
const manager = await util.getCronManager()
console.log(`${chalk.gray(new Date().toISOString())} ${chalk.gray('[' + manager.account.connection.networkId.toUpperCase() + ']')} Available Triggers: ${chalk.blueBright(cache.length)}, Processed: ${chalk.yellow(triggersProcessed)}`)
// reset after log
triggersProcessed = 0

return cache
}

// Call any contract with a "view" RPC call
export const viewTrigger = async trigger_hash => {
const trigger = cache[triggerHash]
let trigger
let outcome = false
cache.forEach(t => {
if (t.hash === trigger_hash) trigger = {...t}
})
if (!trigger) return outcome

try {
// Check if the trigger evaluates to true or false
const res = await util.queryRpc(`${trigger.contract_id}`, `${trigger.function_id}`, null, null, trigger.arguments)
if (!res) this.validFunctionId = false
if (res) {
// looking for specific error message to confirm function exists
if (res.search('MethodNotFound') > -1) {
this.validFunctionId = false
} else this.validFunctionId = true
}
console.log('callTrigger res', res)
// check outcome === true
if (config.LOG_LEVEL === 'debug') console.log('callTrigger res', res)
if (!res) outcome = false
// res should return a standard payload: (bool, Base64VecU8)
if (typeof res === 'boolean') outcome = res
if (typeof res === 'object' && typeof res[0] === 'boolean') outcome = res[0]
} catch (e) {
if (config.LOG_LEVEL === 'debug') console.log('callTrigger', e)
}
triggersProcessed += 1

return outcome
}
Expand All @@ -71,12 +82,15 @@ export const viewTrigger = async trigger_hash => {
// NOTE: Must be careful here, as fast & high amounts of triggers could drain balance quickly!
export const callTrigger = async trigger_hash => {
const manager = await util.getCronManager()
const trigger = cache[triggerHash]

try {
// Only get task hashes my agent can execute
const res = await manager.proxy_conditional_call({ trigger_hash })
console.log('callTrigger res', res)
const res = await manager.proxy_conditional_call({
args: { trigger_hash },
gas: config.BASE_GAS_FEE,
amount: config.BASE_ATTACHED_PAYMENT,
})
if (config.LOG_LEVEL === 'debug') console.log('callTrigger res', res)
} catch (e) {
if (config.LOG_LEVEL === 'debug') console.log('callTrigger', e)
}
Expand All @@ -87,25 +101,29 @@ export const callTrigger = async trigger_hash => {
// NOTE: This is built without batching, could be implemented in the future
export async function run() {
const allTriggers = await getAllTriggers()
console.log('allTriggers', allTriggers);

// If there aren't any triggers, wait a while before checking for more
if (!allTriggers || allTriggers.length <= 0) {
setTimeout(run, CACHE_DELAY)
return
}
if (!allTriggers || allTriggers.length <= 0) return setTimeout(run, CACHE_DELAY)

// speed range
// protect the runtime of triggers with high resolution timer
// NOTE: Probably overkill, but allows for easy acceleration if needed to accommodate faster block times
const sr_start = process.hrtime()

// Logic:
// - Call every trigger to check if any triggers are evaluating to TRUE
// - If TRUE, do 'proxy_conditional_call' call
await allTriggers.reduce(async (trigger, i) => {
await allTriggers.reduce(async (ctx, trigger, i) => {
const shouldCall = await viewTrigger(trigger.hash)
if (shouldCall) await callTrigger(trigger.hash)
return [...trigger, i + 1]
return [...ctx, i + 1]
}, [])

// TODO: Check if RPC processing time too longer than interval, if so do next immediately
// TODO: Add logging & stats logging if desired
// Wait, then loop again.
setTimeout(run, config.TRIGGER_INTERVAL_MS)
// end speed range
const sr_end = process.hrtime(sr_start)

// Check if RPC processing time too longer than interval, if so do next immediately
const exec_duration = sr_end[1] / TIME_GRANULARITY
if (exec_duration > config.TRIGGER_INTERVAL_MS) run()
else setTimeout(run, Math.abs(config.TRIGGER_INTERVAL_MS - exec_duration))
}
2 changes: 1 addition & 1 deletion src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const queryRpc = async (account_id, method_name, args, options = {}, args

try {
// TODO: Test this, setup using connection pool
res = await Near.connection.provider.query({
res = await Near.client.connection.provider.query({
request_type: 'call_function',
finality: 'final',
account_id,
Expand Down

0 comments on commit b78633f

Please sign in to comment.