Skip to content
axone-protocolPublic

About

🧠 The Axone Prolog VM

Topics

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

1 watching

Forks

Latest commit

 

History

1,009 Commits

Folders and files

Repository files navigation

axone github banner

Discord   LinkedIn   Twitter   Medium   YouTube

Axone Prolog Virtual Machine

build codecov GoDoc

Built with Nix conventional commits Contributor Covenant license

Important

This repository is a hard fork of ichiban/prolog, customized to meet the specific requirements of the Axone protocol. It is maintained independently for our use case, and upstream updates may not be regularly integrated.

For the original, general-purpose Prolog implementation or to contribute to the broader community, please visit the ichiban/prolog repository.

What is this?

axone-protocol/prolog is a Prolog virtual machine written in Go, designed to be embedded in blockchain environments. It serves as the core of the Axone protocol for decentralized, logic-based smart contracts.

This project is a fork of the ichiban/prolog repository, striving to maintain ISO standard compliance where feasible while adapting to the unique constraints of blockchain execution.

Deviations from the ISO Standard

The following customizations have been made to adapt the original ichiban/prolog implementation to the blockchain environment:

  • Capped variable allocation per VM to limit the number of variables.
  • Replaced maps with ordered maps to ensure deterministic execution.
  • Implemented secure integer arithmetic for functors.
  • Integrated cockroachdb/apd for floating-point arithmetic.
  • Removed support for trigonometric functions (sin, cos, tan, asin, acos, atan).
  • Introduced VM hooks for enhanced Prolog execution control.
  • Added support for the Dict term.
  • Added support for read_write mode for bidirectional file I/O, enabling half-duplex transactional devices in the host's VFS.
  • halt/0 and halt/1 stop Prolog execution by signaling a VM halt (the host decides how to handle exit codes).
  • Added VM metering capability to track and limit resource consumption across multiple dimensions (instructions, unifications, list processing, term copying, arithmetic evaluation, structural comparisons, and logical term-cell reservations).

VM metering

VM.InstallMeter lets the host account for and limit VM resources. The VM reports instructions, unification steps, list traversal, copied nodes, arithmetic nodes, structural comparisons, and logical term-cell reservations. Install a meter before parsing or compiling untrusted input, including Interpreter.Query and Interpreter.Exec.

Logical term-cell quotas

engine.MeterTermCell charges term slots before VM-controlled construction and growth: parsing and placeholders, compilation, execution registers, term copies, collectors, DCG expansion, and dictionary operations. Known-size buffers charge their reserved slots; incremental collectors charge new logical entries before appending. Slice views and filling already reserved slots do not charge again. Go's implicit slice overcapacity is not part of the cost.

Install a host-owned quota:

var vm engine.VM
const limit uint64 = 1_000_000
var used uint64

vm.InstallMeter(func(kind engine.MeterKind, units uint64) engine.Term {
	if kind != engine.MeterTermCell {
		return nil
	}
	if units > limit-used {
		return engine.NewAtom("resource_error").Apply(engine.NewAtom("memory"))
	}
	used += units
	return nil
})

Use a separate counter for each VM's budget lifecycle. Accepted charges are cumulative: backtracking, rejected syntax, and garbage collection do not refund them. MeterCopyNode measures copying work and MeterListCell measures traversal; neither replaces the term-cell quota. The existing metering schedule for other resource kinds is unchanged.

Allocation sizes and derived lengths are checked before conversion or allocation. A quota refusal returns error(resource_error(memory), Context) through execution or the synchronous parsing/compilation API; constructing this exception does not consume the exhausted quota.

This is not a physical memory limit or an allocator. No finite term-cell quota is enforced unless the installed callback handles MeterTermCell. Maps, closures, bytecode, strings, runtime overhead, and host-side construction through APIs such as Atom.Apply, List, and NewDict remain outside this quota. Intrinsically fixed small buffers, such as stream properties, remain unmetered.

VM ownership

Allocate variables, environments, and streams through their owning VM: vm.NewVariable(), vm.NewEnv(), and the vm.New*Stream() constructors. Variables contain an opaque VM scope and a local ordinal; equality uses both, while Prolog rendering and variable ordering use only the ordinal within one VM. Unrelated VM activity never changes these observable values.

Do not mix variables, environments, or streams from different VMs. Execution entry points reject foreign variables and environments with engine.ErrVariableScope, and foreign streams with engine.ErrStreamScope. Low-level environment and comparison operations panic on scope conflicts. Allocate variables through vm.NewVariable() rather than constructing a zero-value Variable.

Stream ownership is fixed at creation. User input/output setters reject foreign or unowned streams before changing state; stream I/O predicates reject them before accessing resources. Streams are ordered only within their owning VM by local ID. Do not copy streams.

Create a fresh VM for each execution lifecycle; variable identities and allocation accounting are never reset within an existing VM. Loaded predicates remain usable for that VM's lifetime. Independent VMs can execute concurrently; shared host I/O and filesystem resources must be safe for concurrent use. Do not copy a VM after use or execute concurrently on the same VM.

License

Distributed under the MIT license. See LICENSE for more information.

Bug reports & feature requests

If you notice anything not behaving how you expected, if you would like to make a suggestion or would like to request a new feature, please open a new issue. We appreciate any help you're willing to give!

Don't hesitate to ask if you are having trouble setting up your project repository, creating your first branch or configuring your development environment. Mentors and maintainers are here to help!

You want to get involved? 😍

So you want to contribute? Great! ❤️ We appreciate any help you're willing to give. Don't hesitate to open issues and/or submit pull requests.

We believe that collaboration is key to the success of the Axone project. Join our Community discussions on the Community space to:

  • Engage in conversations with peers and experts.
  • Share your insights and experiences with Axone.
  • Learn from others and expand your knowledge of the protocol.

The Community space serves as a hub for discussions, questions, and knowledge-sharing related to Axone. We encourage you to actively participate and contribute to the growth of our community.

Please check out Axone health files:

Acknowledgements

We would like to thank the following projects for their inspiration and for providing the foundation for this project:

  • ichiban for the original Prolog implementation.

About

🧠 The Axone Prolog VM

Topics

Resources

Code of conduct

Contributing

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages