Distributed Trustless Workers with Stellar

This article describes something you can do with cryptocurrency besides speculating on the price: pay a distributed network of untrusted workers to create something for you.

Read on for an in-depth look at how Stellar’s advanced features can be used to create a “smart contract” between a customer and an anonymous and untrusted worker.

Finding something to create

Bitcoin and Stellar are both built around the concept of an “address” that is used to send payments. An example Stellar address is: GABFWOKKMDRIDRTUBI6M5SNMABX6XGRPYBYMJ24IIFCDYYZRCKTSKCXZ

Since that series of random letters and numbers isn’t very user friendly, it’s nicer to have a recognizable address that starts or ends with an english word. For example, if the last four letters were ZULU then it would be much easier to recognize this address and verify a payment was going to the right place.

Custom addresses like this are known as “vanity addresses” and need to be generated by randomly creating addresses until one is found. Generating a series of four characters would go quickly, but generating ZULUCRYPTO would take much longer. This is a perfect problem for a distributed group of workers!

Process Overview

There are two actors involved in this transaction:

  • The Customer who wants a vanity address generated. I’ll abbreviate their Stellar account as GCUSTOMER (Stellar addresses always start with G). They start with 500 XLM and want to pay 100 XLM for a vanity address.
  • The Worker who generates the vanity address: GWORKER. The Worker is willing to accept 100 XLM to generate a vanity address.

I’ll refer to the vanity address that gets generated as GVANITY.

Here’s how things look at the beginning:

Account: GCUSTOMER
Balance: 500 XLM
Account: GWORKER
Balance: 1600 XLM

Customer Advertises their Request

In order to get work started, the Customer has to solve a few problems:

  1. How to advertise to the network that there is work to be done?
  2. How to prove to a Worker that the worker will get paid?

Advertising the request

First, the Customer has to figure out a way to advertise what vanity keypair they want. This is done by setting a Data Entry on an account. Each data entry is a key/value pair, so as long as the Customer and Worker can agree on a standard, this is a way to broadcast something to the entire network.

In this case, we’ll set the key request:generateVanityAddress to value G*ZULU . Now, the Worker can scan the blockchain for any accounts with the request:generateVanityAddress data and then examine the value to see what vanity address is requested. In this case, it’s anything that starts with “G” and ends in “ZULU”.

Proving that a Worker will get paid

This can be solved through the use of an Escrow account (that the Customer creates) which we’ll refer to as GESCROW. In order for an escrow account to be effective, the Worker needs to know that the Customer has the funds available to pay them and that the Worker will be able to access those funds when the vanity address has been generated.

The Customer also needs some way to reclaim their funds if a Worker never completes their task.

We’ll go in reverse and come up with a way for the Customer to retrieve their funds by creating a pre-authorized transaction that’s not valid until 30 days have passed:

Transaction Name: txReclaimAccount
Submitted By: GESCROW
Timebounds: Valid starting 30 days from now
Operations:
1. Merge GESCROW into GCUSTOMER

Timebounds are a Stellar feature that allows you to create a transaction that’s only valid during a specific time range. For more details on transactions, see: https://www.stellar.org/developers/guides/concepts/transactions.html

The Merge operation destroys an account and sends all funds to a destination account. The operation above will destroy GESCROW freeing up its resources and sending the balance back to GCUSTOMER.

The customer now saves this transaction somewhere and can submit it to the network after 30 days have passed.

Now it’s time to prove to the Worker that the Customer no longer has access to the escrow account for these 30 days. To solve this problem, we use Stellar’s multisignature features.

As the Customer, we immediately submit this transaction to the network:

Transaction Name: txShareAccount
Submitted By: GESCROW
Operations:
1. Add GWORKER as a signer with weight 1
2. Add GCUSTOMER as a signer with weight 1
3. Require a weight of 2 to perform any actions on the account
4. Set the weight of the master key (GESCROW) to 0

After this transaction is submitted, a weight of 2 is required to do anything with this account. Since the GESCROW master key now has a weight of 0, the only way for anything to happen is if GCUSTOMER and GWORKER agree on a transaction and both sign it.

The one exception to this is the pre-authorized txReclaimAccount transaction, but since it’s not valid for 30 days, the Worker is guaranteed 30 days to work on generating the vanity address.

At this point, we have the following accounts:

Account: GCUSTOMER
Balance: 400 XLM (100 transferred to GESCROW)
Account: GWORKER
Balance: 1600 XLM
Account: GESCROW
Balance: 100 XLM (100 from GCUSTOMER)
Signers:
1. GCUSTOMER (weight 1)
2. GWORKER (weight 1)
3. Master key can no longer sign
4. Pre-authorized transaction (valid starting 30 days from now)

To keep things organized, GESCROW is also the account that the request:generateVanityAddress data entry mentioned above is attached to.

Worker begins work

We’ll switch over to the Worker’s perspective now. By scanning the blockchain, we’ve discovered that someone has requested an address that ends in “ZULU”.

Since this request is attached to the Escrow account, we can see that the price is reasonable (100 XLM) and that the escrow account is locked and cannot be reclaimed by the Customer while we’re working on it.

The actual algorithm for generating a vanity address involves repeatedly generating random keys until we find one that matches the Customer’s desired pattern.

At some point, we’ll find a matching address and then we have to begin the process of communicating it to the Customer.

Worker proves that they found a keypair

After finding a keypair, the Worker’s challenge is to prove to the Customer that they’ve generated it. There also needs to be a way for the Customer to pay the Worker by transferring the escrow account.

This process will again rely on account data entries. In this case, they will be attached to the Worker account.

First: set a data entry with key:value GCUSTOMER_result:GVANITY . This allows the Customer to examine the data entries on GWORKER to check if the Worker is done.

Then, we need a way to prove to the Customer that the Worker controls the private key for GVANITY without revealing what that private key is. This process should sound familiar since that’s how cryptocurrencies work! When you’re submitting a transaction to the network you’re using your secret key to sign a transaction. In this case, we’ll sign a text string and write the signature to our account as the following key:value pair: GCUSTOMER_proof:<ed25519 signature>. The text being signed doesn’t matter as long as GCUSTOMER and GWORKER both know what it is.

The final thing the Worker needs to take care of is generating signatures for the transfer transaction.

The transfer transaction

This transaction is the critical part of the process and allows the Customer and Worker to exchange payment and data in a single operation. Due to the properties of the Stellar Consensus Protocol, all operations in a transaction will either succeed or fail. There’s no way for the transaction to be partially completed.

This transaction will look like the following:

Transaction Name: txTransfer
Submitted By: GCUSTOMER (see the next step)
Source Account: GCUSTOMER
Operations:
1. GVANITY: Add GCUSTOMER as a signer with weight 1
2. GVANITY: Set all thresholds to 1
3. GVANITY: Set master key weight to 0
4. GESCROW: Merge to GWORKER

The first three operations take care of giving control of GVANITY to GCUSTOMER. After the above transaction runs, the secret key to GVANITY (only known by GWORKER) will no longer be able to perform any operations on the account since its weight will be 0 and all operations have a threshold of 1.

The last operation is how GWORKER receives payment: GESCROW is merged to GWORKER which transfers all XLM in the account.

Since this transaction involves three accounts (GCUSTOMER, GVANITY, and GESCROW) it will require three signatures:

  • GWORKER to provide 1 of 2 necessary weights to mergeGESCROW
  • GCUSTOMER since they are the source account (which means they are paying all fees) and are 1 of 2 necessary weights to merge GESCROW
  • GVANITY because we’re altering the thresholds and master key weights of GVANITY

Since the Worker knows the private keys for GWORKER and GVANITY it can provide these signatures and write them as data entries on the GWORKER account.

Note that the Worker is not submitting the above transaction! They only generate the signatures for it. It will be the Customer’s responsibility to provide the final signature and submit to the network.

Customer verifies vanity keypair and submits transfer transaction

The Customer checks the data entries on GWORKER and sees the following:

     Account: GWORKER
Data Entries:
GCUSTOMER_result: GVANITY
GCUSTOMER_proof: <ed25519 signature>
GCUSTOMER_sigW: <worker stellar signature for txTransfer>
GCUSTOMER_sigV: <vanity keypair stellar signature for txTransfer>

The Customer now takes the following steps:

  1. Verify that the data in GCUSTOMER_proof is a valid signature. This is how we know that GVANITY was really generated.
  2. Build txTransfer . The Customer and Worker both independently build this transaction. All that needs to be exchanged are the signatures.
  3. Add a signature from GCUSTOMER to txTransfer
  4. Add the _sigW and _sigV signatures that were read from the GWORKER data entries
  5. Submit txTransfer to the Stellar network now that the Customer has all of the necessary signatures

As soon as txTransfer is submitted and confirmed then the process is complete!

Customer uses vanity address

The Customer is now in control of the vanity address, but you’ll note they never received the secret key.

Instead, Stellar’s multisig features are used to allow GCUSTOMER to sign for GVANITY.

For example, to pay 50 XLM toGMERCHANT, the following transaction would be generated:

Transaction Name: txExamplePayment
Submitted By: GCUSTOMER
Operations:
1. From GVANITY: Pay 50 XLM to GMERCHANT

GCUSTOMER would then sign this transaction with their own secret key. Even though the payment is coming from GVANITY, GCUSTOMER can provide a weight of 1 with their signature which is enough to perform any operation.

Real-world Implementation

A working implementation of this would require that Customers and Workers agreed on some standards. It would also require additional data entries for better communication between the two parties.

Source code implementing a test version of this smart contract is available at: https://github.com/zulucrypto/stellar-smart-contracts/blob/master/distributed-worker/README.md

Like what you read? Give Zulu Crypto a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.