Creating an immutable audit trail on the blockchain with Xero & Tierion

Riley James
Xero Developer
Published in
12 min readApr 19, 2018

--

There is far more to blockchain technology than the price of bitcoin. This post & PoC project will explore a real use case of blockchain technology. While this is just a proof of concept to show what you can do with Xero’s API, it’s possible to implement this feature yourself.

For context: Xero is cloud-based (SaaS) small business accounting software. Business owners use it to manage their business while accountants and bookkeepers use it to provide business advisory & compliance services to their small business clients.

If you’re not aware of Xero, this will give you some context for this blog post

Audit in Accounting:

An audit is a common process within the accounting world. The Australian Taxation Office (ATO) regularly audits businesses to ensure they’ve declared the correct amount of tax. Publicly listed companies (like Xero) are required to conduct regular audits to ensure their financial statements are accurate. Any accusation of fraud or dishonest activity within business will likely lead to an audit. And in many cases, audits are simply performed at random to ensure legal, accounting & regulatory compliance.

Xero’s History and Notes Feature:

Xero has a ‘History and Notes’ feature which records changes made to an accounting document. Each entry contains details on who made the change, the time and date the change was made, and some details regarding what was changed.

An example of the history and notes feature on an invoice

This feature works well for business owners and accountants to easily see when a record was last updated and by whom.

What it doesn’t display is a copy of the transaction at the time of the change — think Github which tracks all the changes to your code base over time. That level of detail might be useful to a 3rd party system conducting an audit.

And it doesn’t provide immutable proof that the document (or it’s history) hasn’t otherwise changed. Ultimately, these history and notes entries are simply entries in a database, they’re not immutable, and they’re not independently verifiable.

An Immutable Audit Trail:

A person can do some research and come to a conclusion regarding their level of trust for an organisation. And determine if they should trust the data they’ve received.

Audits, regulation, public companies, stock markets, rule of law, freedom of the press, and I’m sure you can think of others. These are all mechanisms which assist people to determine who and what to trust, and to what level.

But, all these mechanisms are built, maintained & enforced by people. Software struggles to parse these systems, and the incentives they create for people to follow, or not follow them.

Therefore, it is difficult for software to verify the integrity of data it receives when this datas’ integrity is enforced through such mechanisms.

immutable: unchanging over time or unable to be changed.

Blockchains* create a new set of incentives, which can be verified easily by a piece of software. It’s these incentives that enable an immutable database of entries, which in turn enables the production of an immutable audit trail.

If you’re interested in more details on why it’s so difficult to change entries within a blockchain, this article provides some great examples.

Can data be changed, technically, yes, but such an event would be easily recognised by humans & computers alike. On top of that, participants in the chain are incentivised against changing existing entries.

*Note: I am referring to public blockchains such as Bitcoin & Ethereum. There are many other types of blockchains, which may have different incentives, for different purposes.

Enter Tierion:

Tierion developed the Chainpoint protocol to enable applications to link data to a blockchain. This is commonly called “anchoring”. Each Chainpoint proof lets you verify the integrity and timestamp of information without relying on a trusted third-party.

How does the Chainpoint protocol work?

In order to attach data to a blockchain, first create a SHA-256 hash of the data. The hash of the data can then submitted to a Chainpoint node that is running the Chainpoint protocol.

The Chainpoint protocol bundles up many of these SHA-256 hashes into a Merkle tree. The use of a Merkle tree allows a large number of hashes (representing an event larger amount of data) to be attached a blockchain through a single entry, also known as a “merkle root”.

The Merkle root produced is then anchored to a public blockchain (Currently BTC & Tierion’s internal Calendar — CAL).

Chainpoint returns a proof that contains the SHA-256 hash of the data, and cryptographic proof that the SHA-256 hash is contained in the Merkle root. It also contains the blockchain (BTC & CAL) transactions that anchor the Merkle root to a blockchain, proving it’s existence at the exact point in time.

Chainpoint protocol in action. Note: Chainpoint does not currently support the ethereum blockchain. Image source: Chainpoint.org

With this process is it now possible to prove that the data existed at a specific date/time and has not been modified since. This can all be done without ever making the original data publicly available, thanks to the SHA-256 hashing & encryption.

The Crypto Audit

If ever audited by the ATO in the future, it is now far easier. Each piece of data has it’s own SHA-256 hash and Chainpoint proof that provides all the information needed.

Technically, the original SHA-256 hash would not even need to be provided, as the auditor could generate this themselves from the original data source (and the auditor should, trust, but verify).

The provided Chainpoint proof could then be evaluated against each blockchain it was anchored to, in order to verify that the transaction exists, in turn proving the given hash exists, untampered with.

This entire data collection & evaluation process could be completed by an application, and later verified by a human manually (if necessary). There are only two possible outcomes:

The data provided generates a SHA-256 hash that matches the Chainpoint proof and can be evaluated against a public blockchain.

Or it does not.

There are no 3rd parties to trust and there are no factors that can not be evaluated by an algorithm.

Why use Tierion’s Chainpoint Technology?

You certainly don’t need to, you could simply hash your document/data and put it directly onto a blockchain. The Chainpoint protocol makes the entire process cheaper & easier to implement.

Chainpoint’s advantages are:

  • Economies of scale: The Merkle tree implementation allows a large number of hashes to be aggregated and anchored within a single transaction. Chainpoint’s aggregation reduces the cost of anchoring data while increasing the amount of data that can be anchored at one time.
  • Anchors against multiple blockchains. Currently only Bitcoin & Tierion’s internal Calendar (CAL), but I’d expect others to be adopted as the blockchain ecosystem develops.
  • Creates ‘Chainpoint proofs’. These proofs allow anyone to verify their data independently, without relying on Tierion.
  • Doesn’t require owning currency/tokens to use.
  • Abstracts away from blockchain specific features / implementations. ie: transaction speed, transaction costs, api changes
  • Ease of implementation: SDK written in JS, inevitably more languages will be supported in the future.
  • Does not require infrastructure, management of network nodes or storage of a complete blockchain.

Building a ‘Proof of Concept’ immutable audit history for Xero invoices

So hopefully you now understand why I’m using a blockchain, and what I’m attempt to achieve with it. Now lets look at how we can put that into practice.

The goal was to build an application that utilised Xero’s API & Tierion’s blockchain technology to create an immutable audit trail. As it’s only a proof of concept, I chose deliberately limited the scope to a single accounting document, Invoices.

I chose to build the sample application in Node, primarily because there is a Node SDK for the Chainpoint protocol, but also because Xero has a relatively new Node SDK (and since beginning this project, we have an even newer one under development :) and I needed an excuse to have a play.

False Start:

I initially built out a prototype based on the documentation on the Tierion website. It was an incredibly basic version, built without any SDK’s, as a single Lambda function (in python).

This first version was modelled on my previous PoC, sending invoices via Fax with Phaxio. The lambda function processed invoice webhooks, retrieved the invoice, hashed it and submitted it to Tierion’s API.

I tweeted the resulting valid receipt, and the Tierion team reached out. Unfortunately they informed me that I had built against v2 of the Chainpoint protocol, and that a new v3 of the Chainpoint protocol was already available.

It was time to go back to the drawing board, and build it again, oh no ;)

Going Node

For the second version I decided I wanted to move away from Lambda functions and build a full app. And having built my last two sample projects in Python, I was keen to try something new, so Node it was.

Check out the Github repo: https://github.com/rjaus/XeroTierion

I also wanted to keep it super light, and not use any databases. This ended up being a bit of pain, but a great learning experience. Instead of using a database, I planned to to use Xero Files / Attachment feature to store the audit data along side Xero’s invoices. By the end of the project I was storing a lot more data than I initially through I’d need to, so this became a little convoluted. But from a users perspective, I think it makes most sense to keep the data in Xero along side the invoices, where a user can easily find it, and would expect it to be.

How does it work?

The Audit History application uses Xero API webhooks to listen for creation & change events on invoices within Xero.

When a creation or change events is delivered to the application via a webhook event, it initiates the process of creating an immutable audit trail.

  1. The full invoice data is retrieved from the Xero API
  2. The invoice data is hashed with SHA-256
  3. The hash is submitted to 2 Chainpoint nodes using the Chainpoint v3 protocol
  4. The CAL proof is retrieved from the 2 Chainpoint nodes and stored as an attachment against the invoice in Xero
  5. The BTC proof is retrieved from the 2 Chainpoint nodes and stored as an attachment against the invoice in Xero (BTC proof can only be generated after the transaction has been created in the Bitcoin blockchain — this takes approximately 90–120 minutes after submitting the hash)
  6. The user can now retrieve the proofs (BTC & CAL) from the invoice in Xero (proofs are stored as attachments) and verify them. In our app, the proofs are then displayed along side the Xero invoice data (the audit history), along with the verified proof.
Invoice Audit History Sample App

So how does this prove our Immutable Audit History?

So now that we’ve hashed our data and submitted it to Chainpoint, how does that prove to the user that the invoice data existed, and has not been modified?

The verified proof, generated with Chainpoint, proves that the hash has been included in the Merkle tree and includes the timestamp of when it was submitted to Tierion. The Merkle root and the Bitcoin block ID are provided to the user.

Verified Proof with timestamp, Merkle root & Bitcoin block ID highlighted

Any user can then take the Bitcoin block ID and put it into any 3rd party blockchain explorer (or use a local copy of the blockchain).

The Merkle root value from the Chainpoint proof should match that displayed from the Bitcoin block explorer.

Block Cypher Bitcoin Blockchain Explorer #514177

We now have proof of existence.

This invoice data:

{ "Type": "ACCREC", "Contact": { "ContactID": "152fd4d9-08e7-48fd-b8f7-0d04674f2fd0", "ContactStatus": "ACTIVE", "Name": "Blockchain Auditor", "EmailAddress": "", "BankAccountDetails": "", "Addresses": [ { "City": "", "Region": "", "PostalCode": "", "Country": "", "AddressType": "STREET" }, { "City": "", "Region": "", "PostalCode": "", "Country": "", "AddressType": "POBOX" } ], "Phones": [ { "PhoneNumber": "", "PhoneAreaCode": "", "PhoneCountryCode": "", "PhoneType": "DEFAULT" }, { "PhoneNumber": "", "PhoneAreaCode": "", "PhoneCountryCode": "", "PhoneType": "DDI" }, { "PhoneNumber": "", "PhoneAreaCode": "", "PhoneCountryCode": "", "PhoneType": "FAX" }, { "PhoneNumber": "", "PhoneAreaCode": "", "PhoneCountryCode": "", "PhoneType": "MOBILE" } ], "IsSupplier": false, "IsCustomer": true, "DefaultCurrency": "AUD" }, "LineItems": [ { "Description": "A hash of this invoice will end up in the blockchain.", "Quantity": 1, "UnitAmount": 1000, "AccountCode": "200", "TaxType": "OUTPUT", "TaxAmount": 100, "LineAmount": 1000 } ], "Date": "2018-02-23T00:00:00.000Z", "DueDate": "2018-02-24T00:00:00.000Z", "LineAmountTypes": "Exclusive", "InvoiceNumber": "XRO-TNT-1", "Reference": "tierion-chainpoint-2", "BrandingThemeID": "dfe23d27-a3a6-4ef3-a5ca-b9e02b142dde", "CurrencyCode": "AUD", "CurrencyRate": 1, "Status": "DRAFT", "SentToContact": false, "SubTotal": 1000, "TotalTax": 100, "Total": 1100, "InvoiceID": "9f950cfe-1cb6-4422-8a8f-49725bd9e914", "HasAttachments": false, "AmountDue": 1100, "AmountPaid": 0 }

Represented by it’s SHA-256 hashed value of:

9ec53ce79305e4c4c77aab08d0ba95a75be68923e76bcbc7e7c16274c98772c8

Was submitted to a Chainpoint node at:

2018-03-19T01:48:46Z

Was included in the Merkle tree with a root of:

7252a3f8c1cc4726341687cdaf85a2b4dc0bd85d86e2de70255229d453c86f56

Which was attached to Bitcoin block:

514177

This becomes the first entry in our immutable audit history for this invoice.

Immutable Audit History:

Any further changes to an invoice which will be picked up by the audit history app (through webhooks) and taken through the same process, adding a new entry to the audit history.

Some of the reasons it’s immutable:

  • Attempting to change the data of an invoice that has already been included in the audit history will result in a different hash being generated.
  • Attempting to modify the timestamp, Merkle root or Bitcoin block ID will result in a mismatch between the verified proof provided, and that which would be generated with the Chainpoint protocol.
  • Re-hashing the data and submitting it to Tierion will result in a new timestamp, and a new (more recent) entry in the audit history
  • Attempting to modify the Merkle root, as recorded in the Bitcoin block would require forking of the Bitcoin blockchain

PoC to Product:

Taking this from a proof of concept to a product would require a lot of polishing. There plenty of features to be added to make it usable for a technical user.

Xero Files as a Database — XFAAD:

Xero Files do not provide previews of text files. Downloading the file is required to view the contents.

Xero Files is not a database. The primary reason I did this was to keep everything in Xero, but that provides little value when text files are not browsable in the UI. Only images & pdf files can be previewed within the UI, text files must be downloaded before they can be viewed.

Multi-tenancy:

Currently the application uses the Private App method. This is only suitable for 1:1 connections between and Xero Org and the Xero API. This makes it perfect for PoC / Dev environment, but to make it user friendly it would require the Partner App, and to become a multi-tenanted application (so users don’t need to manage infrastructure).

Deltas / What’s changed:

Knowing that an invoice has changed is a great feature, but the real value coming in knowing what part that invoice has changed. A critical feature of this application would be to determine what has changed, and potentially raise these changes to the user if they particularly noteworthy.

One Click Audit:

The application currently doesn’t provide any way to export the audit trail. That’s going to be a necessary feature for any kind of useful audit history. Even better, find some way to export it in one click to the ATO / auditing body. The capability to meet audit requirements in a single click would be a massive timesaver for a small business.

Audit all the things:

An audit trail of invoices is nice, but to be useful it would need to expand to other accounting document types. CreditNotes, BankTransfers, BankTransactions, Payroll, Payments, JournalEntries, the list goes on…

Do not ship, hire a designer

Hire a designer:

I’m very clearly a developer, not a designer. To make this a product you would need to hide all those long strings and show the user when things match/conflict (at least I colour coded them :) A lot of design work would be required to make this functional for non-developers.

And that’s it:

If you’ve got questions, reach out on twitter: @RileyJamesAU

Check out the Github repo: https://github.com/rjaus/XeroTierion

If you want to build something with the Xero API, get in contact: api@xero.com or visit https://developer.xero.com/

-

Over a million small businesses, and their advisors are looking for the best cloud apps that integrate with Xero. Partner with us, and we’ll make sure they find yours.

--

--