README
¶
Computantis
The Computantis is a set of services that keeps track of transactions between wallets. Transactions are not transferring any tokens between wallets but it might be the case if someone wants to use it this way. Just this set of services isn’t designed to track token exchange. Instead, transactions are entities holding data that the transaction issuer and transaction receiver agreed upon. Each wallet has its own independent history of transactions. There is a set of strict rules allowing for transactions to happen:
The central server is private to the corporation, government or agency. It is trusted by the above entity and participants. This solution isn’t proposing the distributed system of transactions as this is not the case. It is ensuring that the transaction is issued and signed and received and signed to confirm its validity. Blockchain keeps transactions history immutable so the validators can be sure that no one will corrupt the transactions. Transaction to be valid needs to:
- Have a valid issuer signature.
- Have a valid receiver signature.
- Have a valid data digest.
- Have a valid issuer public address.
- Have a valid receiver public address.
- Be part of a blockchain.
The full cycle of the transaction and block forging happens as follows:
- The Issuer creates the transaction and signs it with the issuer's private key, attaching the issuer's public key to the transaction.
- The Issuer sends the transaction to the central server.
- The central server validates The Issuer address, signature, data digest and expiration date. If the transaction is valid then it is kept in awaiting transactions repository for the receiver to sign.
- Receiver asks for awaiting transactions for the receiver's signature in the process of proving his public address and signing data received from the server by the receiver's private key.
- If the signature is valid then all awaiting transactions are transferred to the receiver.
- The receiver can sign transactions that the receiver agrees on, and sends them back to the central server.
- The central server validates the address, signature, data digest and expiration date then appends the transaction to be added to the next forged block. The transaction is moved from the awaiting transactions repository to the temporary repository (just in case of any unexpected crashes or attacks on the central server).
- The central servers follow sets of rules from the configuration
yaml
file, which describes how often the block is forged, how many transactions it can hold and what is the difficulty for hashing the block. - When the block is forged and added to the blockchain then transactions that are part of the block are moved from the temporary transactions repository to the permanent transactions repository.
- Information about the new blocks is sent to all validators. Validators cannot reject blocks or rewrite the blockchain. The validator serves the purpose of tracking the central node blockchain to ensure data are not corrupted, the central node isn’t hacked, stores the blocks in its own repository, and serves as an information node for the external clients. If the blockchain is corrupted then the validator raises an alert when noticing corrupted data. It is good practice to have many validator nodes held by independent entities.
Execute the server
- Run database
docker compose up
. - Build the server
go build -o path/to/bin/central cmd/central/main.go
. - Create
server_settings.yaml
according toserver_settings_example.yaml
file inpath/to/bin/
folder. - Run
./path/to/bin/central
.
Run for development
- Run database with
docker compose up -d
. - Create
server_settings.yaml
according toserver_settings_example.yaml
in the repo root folder. - Run
make run
orgo run cmd/central/main.go
.
Stress test
Directory stress/
contains central node REST API performance tests.
Bottleneck is on I/O calls, mostly database writes.
Single PostgreSQL database instance run in docker 1CPU and 2GB RAM allows for
full cycle processing of 750 transactions per second. This is rough estimate and
I would soon provide more precise benchmarks.
Package provides webassembly package that expose client API to the front-end applications.
To use client API allowing for creating a wallet and communication with Central Server REST API
copy wasm/bin/wallet.wasm
and wasm/js/wasm_exec.js
to you fronted project and execute as in example below.
<html>
<head>
<meta charset="utf-8"/>
<script src="wasm_exec.js"></script>
<script>
const go = new Go();
WebAssembly.instantiateStreaming(fetch("wallet.wasm"), go.importObject).then((result) => {
go.run(result.instance);
});
</script>
</head>
<body></body>
</html>
Computantis architecture
The schema below shows how pieces of the computation service are connected together. This is one of the simple examples with high availability where central nodes, db shards and validators may be scaled and orchestrated with k8s or another tool. Because the central node service, validator service as well as wallet API are compiled to a single lightweight binary running on a variety of architectures we can make the whole system lightweight. Container size can be kept very minimal without the need for interpreters or virtual engines which is securing containers, minimizing the cold start and the container size to a few megabytes. Low RAM and CPU consumption of a single node allows to run service on IoT devices.
The task of the whole system is simple, validate transactions, act as a message hub and seal the history of transactions within the immutable blockchain, but be performant with that task.
Use case scenario
The example below describes how Computantis can seal the transactions happening in distributed IoT services. The data are only encrypted when flowing between services. When in the system it might be the case that data are corrupted or when service is compromised then transactions may be faked. The Computantis is on its way to discovering probable scenarios of sealing the data with cryptographic signatures and immutable history. It is one of the scenarios when such an approach may be taken into consideration.
Go Documentation
address
import "github.com/bartossh/Computantis/address"
Index
type Address
Address holds information about unique PublicKey.
type Address struct {
ID any `json:"-" bson:"_id,omitempty" db:"id"`
PublicKey string `json:"public_key" bson:"public_key" db:"public_key"`
}
aeswrapper
import "github.com/bartossh/Computantis/aeswrapper"
Index
Variables
var (
ErrInvalidKeyLength = errors.New("invalid key length, must be longer then 32 bytes")
ErrCipherFailure = errors.New("cipher creation failure")
ErrGCMFailure = errors.New("gcm creation failure")
ErrRandomNonceFailure = errors.New("random nonce creation failure")
ErrOpenDataFailure = errors.New("open data failure, cannot decrypt data")
)
type Helper
Helper wraps eas encryption and decryption. Uses Galois Counter Mode (GCM) for encryption and decryption.
type Helper struct{}
func New
func New() Helper
Creates a new Helper.
func (Helper) Decrypt
func (h Helper) Decrypt(key, data []byte) ([]byte, error)
Decrypt decrypts data with key. Key must be at least 32 bytes long.
func (Helper) Encrypt
func (h Helper) Encrypt(key, data []byte) ([]byte, error)
Encrypt encrypts data with key. Key must be at least 32 bytes long.
block
import "github.com/bartossh/Computantis/block"
Index
type Block
Block holds block information. Block is a part of a blockchain assuring immutability of the data. Block mining difficulty may change if needed and is a part of a hash digest. Block ensures that transactions hashes are valid and match the transactions stored in the repository.
type Block struct {
ID any `json:"-" bson:"_id" db:"id"`
Index uint64 `json:"index" bson:"index" db:"index"`
Timestamp uint64 `json:"timestamp" bson:"timestamp" db:"timestamp"`
Nonce uint64 `json:"nonce" bson:"nonce" db:"nonce"`
Difficulty uint64 `json:"difficulty" bson:"difficulty" db:"difficulty"`
Hash [32]byte `json:"hash" bson:"hash" db:"hash"`
PrevHash [32]byte `json:"prev_hash" bson:"prev_hash" db:"prev_hash"`
TrxHashes [][32]byte `json:"trx_hashes" bson:"trx_hashes" db:"trx_hashes"`
}
func New
func New(difficulty, next uint64, prevHash [32]byte, trxHashes [][32]byte) Block
New creates a new Block hashing it with given difficulty. Higher difficulty requires more computations to happen to find possible target hash. Difficulty is stored inside the Block and is a part of a hashed data. Transactions hashes are prehashed before calculating the Block hash with merkle tree.
func (*Block) Validate
func (b *Block) Validate(trxHashes [][32]byte) bool
Validate validates the Block. Validations goes in the same order like Block hashing algorithm, just the proof of work part is not required as Nonce is already known.
blockchain
import "github.com/bartossh/Computantis/blockchain"
Index
- Variables
- func GenesisBlock(ctx context.Context, rw BlockReadWriter) error
- type BlockReadWriter
- type BlockReader
- type BlockWriter
- type Blockchain
- func New(ctx context.Context, rw BlockReadWriter) (*Blockchain, error)
- func (c *Blockchain) LastBlockHashIndex(ctx context.Context) ([32]byte, uint64, error)
- func (c *Blockchain) ReadBlocksFromIndex(ctx context.Context, idx uint64) ([]block.Block, error)
- func (c *Blockchain) ReadLastNBlocks(ctx context.Context, n int) ([]block.Block, error)
- func (c *Blockchain) WriteBlock(ctx context.Context, block block.Block) error
Variables
var (
ErrBlockNotFound = errors.New("block not found")
ErrInvalidBlockPrevHash = errors.New("block prev hash is invalid")
ErrInvalidBlockHash = errors.New("block hash is invalid")
ErrInvalidBlockIndex = errors.New("block index is invalid")
)
func GenesisBlock
func GenesisBlock(ctx context.Context, rw BlockReadWriter) error
GenesisBlock creates a genesis block. It is a first block in the blockchain. The genesis block is created only if there is no other block in the repository. Otherwise returning an error.
type BlockReadWriter
BlockReadWriter provides read and write access to the blockchain repository.
type BlockReadWriter interface {
BlockReader
BlockWriter
}
type BlockReader
BlockReader provides read access to the blockchain repository.
type BlockReader interface {
LastBlock(ctx context.Context) (block.Block, error)
ReadBlockByHash(ctx context.Context, hash [32]byte) (block.Block, error)
}
type BlockWriter
BlockWriter provides write access to the blockchain repository.
type BlockWriter interface {
WriteBlock(ctx context.Context, block block.Block) error
}
type Blockchain
Blockchain keeps track of the blocks creating immutable chain of data. Blockchain is stored in repository as separate blocks that relates to each other based on the hash of the previous block.
type Blockchain struct {
// contains filtered or unexported fields
}
func New
func New(ctx context.Context, rw BlockReadWriter) (*Blockchain, error)
New creates a new Blockchain that has access to the blockchain stored in the repository. The access to the repository is injected via BlockReadWriter interface. You can use any implementation of repository that implements BlockReadWriter interface and ensures unique indexing for Block Hash, PrevHash and Index.
func (*Blockchain) LastBlockHashIndex
func (c *Blockchain) LastBlockHashIndex(ctx context.Context) ([32]byte, uint64, error)
LastBlockHashIndex returns last block hash and index.
func (*Blockchain) ReadBlocksFromIndex
func (c *Blockchain) ReadBlocksFromIndex(ctx context.Context, idx uint64) ([]block.Block, error)
ReadBlocksFromIndex reads all blocks from given index till the current block in consecutive order.
func (*Blockchain) ReadLastNBlocks
func (c *Blockchain) ReadLastNBlocks(ctx context.Context, n int) ([]block.Block, error)
ReadLastNBlocks reads the last n blocks in reverse consecutive order.
func (*Blockchain) WriteBlock
func (c *Blockchain) WriteBlock(ctx context.Context, block block.Block) error
WriteBlock writes block in to the blockchain repository.
bookkeeping
import "github.com/bartossh/Computantis/bookkeeping"
Index
- Variables
- type AddressChecker
- type BlockFindWriter
- type BlockReadWriter
- type BlockReader
- type BlockSubscription
- type BlockWriter
- type Config
- type DataBaseProvider
- type Ledger
- func New(config Config, bc BlockReadWriter, db DataBaseProvider, ac AddressChecker, vr SignatureVerifier, tf BlockFindWriter, log logger.Logger, blcSub BlockSubscription, sub Subscriber) (*Ledger, error)
- func (l *Ledger) Run(ctx context.Context)
- func (l *Ledger) VerifySignature(message, signature []byte, hash [32]byte, address string) error
- func (l *Ledger) WriteCandidateTransaction(ctx context.Context, trx *transaction.Transaction) error
- func (l *Ledger) WriteIssuerSignedTransactionForReceiver(ctx context.Context, trx *transaction.Transaction) error
- type NodeRegister
- type SignatureVerifier
- type Subscriber
- type Synchronizer
- type TrxWriteReadMover
Variables
var (
ErrTrxExistsInTheLadger = errors.New("transaction is already in the ledger")
ErrTrxExistsInTheBlockchain = errors.New("transaction is already in the blockchain")
ErrAddressNotExists = errors.New("address does not exist in the addresses repository")
ErrBlockTxsCorrupted = errors.New("all transaction failed, block corrupted")
ErrDifficultyNotInRange = errors.New("invalid difficulty, difficulty can by in range [1 : 255]")
ErrBlockWriteTimestampNoInRange = errors.New("block write timestamp is not in range of [one second : four hours]")
ErrBlockTransactionsSizeNotInRange = errors.New("block transactions size is not in range of [1 : 60000]")
)
var (
ErrSynchronizerWatchFailure = errors.New("synchronizer failure")
ErrSynchronizerReleaseFailure = errors.New("synchronizer release failure")
ErrSynchronizerStopped = errors.New("synchronizer stopped")
)
type AddressChecker
AddressChecker provides address existence check method. If you use other repository than addresses repository, you can implement this interface but address should be uniquely indexed in your repository implementation.
type AddressChecker interface {
CheckAddressExists(ctx context.Context, address string) (bool, error)
}
type BlockFindWriter
BlockFindWriter provides block find and write method.
type BlockFindWriter interface {
FindTransactionInBlockHash(ctx context.Context, trxHash [32]byte) ([32]byte, error)
}
type BlockReadWriter
BlockReadWriter provides block read and write methods.
type BlockReadWriter interface {
BlockReader
BlockWriter
}
type BlockReader
BlockReader provides block read methods.
type BlockReader interface {
LastBlockHashIndex(ctx context.Context) ([32]byte, uint64, error)
}
type BlockSubscription
BlockSubscription provides block publishing method. It uses reactive package. It you are using your own implementation of reactive package take care of Publish method to be non-blocking.
type BlockSubscription interface {
Publish(block.Block)
}
type BlockWriter
BlockWriter provides block write methods.
type BlockWriter interface {
WriteBlock(ctx context.Context, block block.Block) error
}
type Config
Config is a configuration of the Ledger.
type Config struct {
Difficulty uint64 `json:"difficulty" bson:"difficulty" yaml:"difficulty"`
BlockWriteTimestamp uint64 `json:"block_write_timestamp" bson:"block_write_timestamp" yaml:"block_write_timestamp"`
BlockTransactionsSize int `json:"block_transactions_size" bson:"block_transactions_size" yaml:"block_transactions_size"`
}
func (Config) Validate
func (c Config) Validate() error
Validate validates the Ledger configuration.
type DataBaseProvider
DataBaseProvider abstracts all the methods that are expected from repository.
type DataBaseProvider interface {
Synchronizer
TrxWriteReadMover
NodeRegister
}
type Ledger
Ledger is a collection of ledger functionality to perform bookkeeping. It performs all the actions on the transactions and blockchain. Ladger seals all the transaction actions in the blockchain.
type Ledger struct {
// contains filtered or unexported fields
}
func New
func New(config Config, bc BlockReadWriter, db DataBaseProvider, ac AddressChecker, vr SignatureVerifier, tf BlockFindWriter, log logger.Logger, blcSub BlockSubscription, sub Subscriber) (*Ledger, error)
New creates new Ledger if config is valid or returns error otherwise.
func (*Ledger) Run
func (l *Ledger) Run(ctx context.Context)
Run runs the Ladger engine that writes blocks to the blockchain repository. Run starts a goroutine and can be stopped by cancelling the context. It is non-blocking and concurrent safe.
func (*Ledger) VerifySignature
func (l *Ledger) VerifySignature(message, signature []byte, hash [32]byte, address string) error
VerifySignature verifies signature of the message.
func (*Ledger) WriteCandidateTransaction
func (l *Ledger) WriteCandidateTransaction(ctx context.Context, trx *transaction.Transaction) error
WriteCandidateTransaction validates and writes a transaction to the repository. Transaction is not yet a part of the blockchain at this point. Ladger will perform all the necessary checks and validations before writing it to the repository. The candidate needs to be signed by the receiver later in the process to be placed as a candidate in the blockchain.
func (*Ledger) WriteIssuerSignedTransactionForReceiver
func (l *Ledger) WriteIssuerSignedTransactionForReceiver(ctx context.Context, trx *transaction.Transaction) error
WriteIssuerSignedTransactionForReceiver validates issuer signature and writes a transaction to the repository for receiver.
type NodeRegister
NodeRegister abstracts node registration operations.
type NodeRegister interface {
CountRegistered(ctx context.Context) (int, error)
}
type SignatureVerifier
SignatureVerifier provides signature verification method.
type SignatureVerifier interface {
Verify(message, signature []byte, hash [32]byte, address string) error
}
type Subscriber
type Subscriber interface {
SubscribeToLockBlockchainNotification(ctx context.Context, c chan<- bool, node string)
}
type Synchronizer
Synchronizer abstracts blockchain synchronization operations.
type Synchronizer interface {
AddToBlockchainLockQueue(ctx context.Context, nodeID string) error
RemoveFromBlockchainLocks(ctx context.Context, nodeID string) error
CheckIsOnTopOfBlockchainsLocks(ctx context.Context, nodeID string) (bool, error)
}
type TrxWriteReadMover
TrxWriteReadMover provides transactions write, read and move methods. It allows to access temporary, permanent and awaiting transactions.
type TrxWriteReadMover interface {
WriteIssuerSignedTransactionForReceiver(ctx context.Context, trx *transaction.Transaction) error
MoveTransactionsFromTemporaryToPermanent(ctx context.Context, blockHash [32]byte, hashes [][32]byte) error
MoveTransactionsFromAwaitingToTemporary(ctx context.Context, trxHash [32]byte) error
ReadAwaitingTransactionsByReceiver(ctx context.Context, address string) ([]transaction.Transaction, error)
ReadAwaitingTransactionsByIssuer(ctx context.Context, address string) ([]transaction.Transaction, error)
ReadTemporaryTransactions(ctx context.Context) ([]transaction.Transaction, error)
}
client
import "github.com/bartossh/Computantis/client"
Index
- Variables
- type Client
- func NewClient(apiRoot string, timeout time.Duration, fw transaction.Verifier, wrs WalletReadSaver, walletCreator NewSignValidatorCreator) *Client
- func (c *Client) Address() (string, error)
- func (c *Client) ConfirmTransaction(trx *transaction.Transaction) error
- func (c *Client) DataToSign(address string) (server.DataToSignResponse, error)
- func (c *Client) FlushWalletFromMemory()
- func (c *Client) GenerateToken(t time.Time) (token.Token, error)
- func (c *Client) NewWallet(token string) error
- func (c *Client) PostWebhookBlock(url string, token string, block *block.Block) error
- func (c *Client) ProposeTransaction(receiverAddr string, subject string, data []byte) error
- func (c *Client) ReadIssuedTransactions() ([]transaction.Transaction, error)
- func (c *Client) ReadWaitingTransactions() ([]transaction.Transaction, error)
- func (c *Client) ReadWalletFromFile() error
- func (c *Client) SaveWalletToFile() error
- func (c *Client) Sign(d []byte) (digest [32]byte, signature []byte, err error)
- func (c *Client) ValidateApiVersion() error
- type NewSignValidatorCreator
- type WalletReadSaver
Variables
var (
ErrApiVersionMismatch = fmt.Errorf("api version mismatch")
ErrApiHeaderMismatch = fmt.Errorf("api header mismatch")
ErrStatusCodeMismatch = fmt.Errorf("status code mismatch")
ErrContentTypeMismatch = fmt.Errorf("content type mismatch")
ErrWalletChecksumMismatch = fmt.Errorf("wallet checksum mismatch")
ErrWalletVersionMismatch = fmt.Errorf("wallet version mismatch")
ErrServerReturnsInconsistentData = fmt.Errorf("server returns inconsistent data")
ErrRejectedByServer = fmt.Errorf("rejected by server")
ErrWalletNotReady = fmt.Errorf("wallet not ready, read wallet first")
ErrSigningFailed = fmt.Errorf("signing failed")
)
type Client
Client is a rest client for the API. It provides methods to communicate with the API server and is designed to serve as a easy way of building client applications that uses the REST API of the central node.
type Client struct {
// contains filtered or unexported fields
}
func NewClient
func NewClient(apiRoot string, timeout time.Duration, fw transaction.Verifier, wrs WalletReadSaver, walletCreator NewSignValidatorCreator) *Client
NewClient creates a new rest client.
func (*Client) Address
func (c *Client) Address() (string, error)
Address reads the wallet address. Address is a string representation of wallet public key.
func (*Client) ConfirmTransaction
func (c *Client) ConfirmTransaction(trx *transaction.Transaction) error
ConfirmTransaction confirms transaction by signing it with the wallet and then sending it to the API server.
func (*Client) DataToSign
func (c *Client) DataToSign(address string) (server.DataToSignResponse, error)
DataToSign returns data to sign for the given address. Data to sign are randomly generated bytes by the server and stored in pair with the address. Signing this data is a proof that the signing public address is the owner of the wallet a making request.
func (*Client) FlushWalletFromMemory
func (c *Client) FlushWalletFromMemory()
FlushWalletFromMemory flushes the wallet from the memory. Do it after you have saved the wallet to the file. It is recommended to use this just before logging out from the UI or closing the front end app that.
func (*Client) GenerateToken
func (c *Client) GenerateToken(t time.Time) (token.Token, error)
GenerateToken generates a token for the given time in the central node repository. It is only permitted to generate a token if wallet has admin permissions in the central node.
func (*Client) NewWallet
func (c *Client) NewWallet(token string) error
NewWallet creates a new wallet and sends a request to the API server to validate the wallet.
func (*Client) PostWebhookBlock
func (c *Client) PostWebhookBlock(url string, token string, block *block.Block) error
PostWebhookBlock posts validator.WebHookNewBlockMessage to given url.
func (*Client) ProposeTransaction
func (c *Client) ProposeTransaction(receiverAddr string, subject string, data []byte) error
ProposeTransaction sends a Transaction proposal to the API server for provided receiver address. Subject describes how to read the data from the transaction. For example, if the subject is "json", then the data can by decoded to map[sting]any, when subject "pdf" than it should be decoded by proper pdf decoder, when "csv" then it should be decoded by proper csv decoder. Client is not responsible for decoding the data, it is only responsible for sending the data to the API server.
func (*Client) ReadIssuedTransactions
func (c *Client) ReadIssuedTransactions() ([]transaction.Transaction, error)
ReadIssuedTransactions reads all issued transactions belonging to current wallet from the API server.
func (*Client) ReadWaitingTransactions
func (c *Client) ReadWaitingTransactions() ([]transaction.Transaction, error)
ReadWaitingTransactions reads all waiting transactions belonging to current wallet from the API server.
func (*Client) ReadWalletFromFile
func (c *Client) ReadWalletFromFile() error
ReadWalletFromFile reads the wallet from the file in the path.
func (*Client) SaveWalletToFile
func (c *Client) SaveWalletToFile() error
SaveWalletToFile saves the wallet to the file in the path.
func (*Client) Sign
func (c *Client) Sign(d []byte) (digest [32]byte, signature []byte, err error)
Sign signs the given data with the wallet and returns digest and signature or error otherwise. This process creates a proof for the API server that requesting client is the owner of the wallet.
func (*Client) ValidateApiVersion
func (c *Client) ValidateApiVersion() error
ValidateApiVersion makes a call to the API server and validates client and server API versions and header correctness. If API version not much it is returning an error as accessing the API server with different API version may lead to unexpected results.
type NewSignValidatorCreator
NewWalletCreator is a function that creates a new SignValidator.
type NewSignValidatorCreator func() (wallet.Wallet, error)
type WalletReadSaver
WalletReadSaver allows to read and save the wallet.
type WalletReadSaver interface {
ReadWallet() (wallet.Wallet, error)
SaveWallet(w wallet.Wallet) error
}
configuration
import "github.com/bartossh/Computantis/configuration"
Index
type Configuration
Configuration is the main configuration of the application that corresponds to the *.yaml file that holds the configuration.
type Configuration struct {
Bookkeeper bookkeeping.Config `yaml:"bookkeeper"`
Server server.Config `yaml:"server"`
Database repository.DBConfig `yaml:"database"`
DataProvider dataprovider.Config `yaml:"data_provider"`
Validator validator.Config `yaml:"validator"`
FileOperator fileoperations.Config `yaml:"file_operator"`
SignerService signerservice.Config `yaml:"signer_service"`
}
func Read
func Read(path string) (Configuration, error)
Read reads the configuration from the file and returns the Configuration with set fields according to the yaml setup.
dataprovider
import "github.com/bartossh/Computantis/dataprovider"
Index
type Cache
Cache is a simple in-memory cache for storing generated data.
type Cache struct {
// contains filtered or unexported fields
}
func New
func New(ctx context.Context, cfg Config) *Cache
New creates new Cache and runs the cleaner.
func (*Cache) ProvideData
func (c *Cache) ProvideData(address string) []byte
ProvideData generates data and stores it referring to given address.
func (*Cache) ValidateData
func (c *Cache) ValidateData(address string, data []byte) bool
ValidateData checks if data is stored for given address and is not expired.
type Config
Config holds configuration for Cache.
type Config struct {
Longevity uint64 `yaml:"longevity"` // Data longevity in seconds.
}
fileoperations
import "github.com/bartossh/Computantis/fileoperations"
Index
type Config
Config holds configuration of the file operator Helper.
type Config struct {
WalletPath string `yaml:"wallet_path"` // wallet path to the wallet file
WalletPasswd string `yaml:"wallet_passwd"` // wallet password to the wallet file in hex format
}
type Helper
Helper holds all file operation methods.
type Helper struct {
// contains filtered or unexported fields
}
func New
func New(cfg Config, s Sealer) Helper
New creates new Helper.
func (Helper) ReadWallet
func (h Helper) ReadWallet() (wallet.Wallet, error)
RereadWallet reads wallet from the file.
func (Helper) SaveWallet
func (h Helper) SaveWallet(w wallet.Wallet) error
SaveWallet saves wallet to the file.
type Sealer
type Sealer interface {
Encrypt(key, data []byte) ([]byte, error)
Decrypt(key, data []byte) ([]byte, error)
}
logger
import "github.com/bartossh/Computantis/logger"
Index
type Log
Log is log marshaled and written in to the io.Writer of the helper implementing Logger abstraction.
type Log struct {
ID any `json:"_id" bson:"_id" db:"id"`
Level string `jon:"level" bson:"level" db:"level"`
Msg string `json:"msg" bson:"msg" db:"msg"`
CreatedAt time.Time `json:"created_at" bson:"created_at" db:"created_at"`
}
type Logger
Logger provides logging methods for debug, info, warning, error and fatal.
type Logger interface {
Debug(msg string)
Info(msg string)
Warn(msg string)
Error(msg string)
Fatal(msg string)
}
logging
import "github.com/bartossh/Computantis/logging"
Index
type Helper
Helper helps with writing logs to io.Writers. Helper implements logger.Logger interface. Writing is done concurrently with out blocking the current thread.
type Helper struct {
// contains filtered or unexported fields
}
func New
func New(callOnWriteLogErr, callOnFatal func(error), writers ...io.Writer) Helper
New creates new Helper.
func (Helper) Debug
func (h Helper) Debug(msg string)
Debug writes debug log.
func (Helper) Error
func (h Helper) Error(msg string)
Error writes error log.
func (Helper) Fatal
func (h Helper) Fatal(msg string)
Fatal writes fatal log.
func (Helper) Info
func (h Helper) Info(msg string)
Info writes info log.
func (Helper) Warn
func (h Helper) Warn(msg string)
Warn writes warning log.
reactive
import "github.com/bartossh/Computantis/reactive"
Index
type Observable
Observable creates a container for subscribers. This works in single producer multiple consumer pattern.
type Observable[T any] struct {
// contains filtered or unexported fields
}
func New
func New[T any](size int) *Observable[T]
New creates Observable container that holds channels for all subscribers. size is the buffer size of each channel.
func (*Observable[T]) Publish
func (o *Observable[T]) Publish(v T)
Publish publishes value to all subscribers.
func (*Observable[T]) Subscribe
func (o *Observable[T]) Subscribe() *subscriber[T]
Subscribe subscribes to the container.
repository
import "github.com/bartossh/Computantis/repository"
Index
- Variables
- type DBConfig
- type DataBase
- func Connect(ctx context.Context, cfg DBConfig) (*DataBase, error)
- func (db DataBase) AddToBlockchainLockQueue(ctx context.Context, nodeID string) error
- func (db DataBase) CheckAddressExists(ctx context.Context, addr string) (bool, error)
- func (db DataBase) CheckIsOnTopOfBlockchainsLocks(ctx context.Context, nodeID string) (bool, error)
- func (db DataBase) CheckToken(ctx context.Context, tkn string) (bool, error)
- func (db DataBase) CountRegistered(ctx context.Context) (int, error)
- func (db DataBase) Disconnect(ctx context.Context) error
- func (db DataBase) FindAddress(ctx context.Context, search string, limit int) ([]string, error)
- func (db DataBase) FindTransactionInBlockHash(ctx context.Context, trxHash [32]byte) ([32]byte, error)
- func (db DataBase) InvalidateToken(ctx context.Context, token string) error
- func (db DataBase) IsAddressAdmin(ctx context.Context, addr string) (bool, error)
- func (db DataBase) IsAddressStandard(ctx context.Context, addr string) (bool, error)
- func (db DataBase) IsAddressSuspended(ctx context.Context, addr string) (bool, error)
- func (db DataBase) IsAddressTrusted(ctx context.Context, addr string) (bool, error)
- func (db DataBase) LastBlock(ctx context.Context) (block.Block, error)
- func (db DataBase) MoveTransactionsFromAwaitingToTemporary(ctx context.Context, trxHash [32]byte) error
- func (db DataBase) MoveTransactionsFromTemporaryToPermanent(ctx context.Context, blockHash [32]byte, hashes [][32]byte) error
- func (db DataBase) Ping(ctx context.Context) error
- func (db DataBase) ReadAwaitingTransactionsByIssuer(ctx context.Context, address string) ([]transaction.Transaction, error)
- func (db DataBase) ReadAwaitingTransactionsByReceiver(ctx context.Context, address string) ([]transaction.Transaction, error)
- func (db DataBase) ReadBlockByHash(ctx context.Context, hash [32]byte) (block.Block, error)
- func (db DataBase) ReadLastNValidatorStatuses(ctx context.Context, last int64) ([]validator.Status, error)
- func (db DataBase) ReadRegisteredNodesAddresses(ctx context.Context) ([]string, error)
- func (db DataBase) ReadTemporaryTransactions(ctx context.Context) ([]transaction.Transaction, error)
- func (db DataBase) RegisterNode(ctx context.Context, n, ws string) error
- func (db DataBase) RemoveFromBlockchainLocks(ctx context.Context, nodeID string) error
- func (DataBase) RunMigration(_ context.Context) error
- func (db DataBase) UnregisterNode(ctx context.Context, n string) error
- func (db DataBase) Write(p []byte) (n int, err error)
- func (db DataBase) WriteAddress(ctx context.Context, addr string) error
- func (db DataBase) WriteBlock(ctx context.Context, block block.Block) error
- func (db DataBase) WriteIssuerSignedTransactionForReceiver(ctx context.Context, trx *transaction.Transaction) error
- func (db DataBase) WriteToken(ctx context.Context, tkn string, expirationDate int64) error
- func (db DataBase) WriteValidatorStatus(ctx context.Context, vs *validator.Status) error
- type Listener
Variables
var (
ErrInsertFailed = fmt.Errorf("insert failed")
ErrRemoveFailed = fmt.Errorf("remove failed")
ErrSelectFailed = fmt.Errorf("select failed")
ErrMoveFailed = fmt.Errorf("move failed")
ErrScanFailed = fmt.Errorf("scan failed")
ErrUnmarshalFailed = fmt.Errorf("unmarshal failed")
ErrCommitFailed = fmt.Errorf("transaction commit failed")
ErrTrxBeginFailed = fmt.Errorf("transaction begin failed")
ErrAddingToLockQueueBlockChainFailed = fmt.Errorf("adding to lock blockchain failed")
ErrRemovingFromLockQueueBlockChainFailed = fmt.Errorf("removing from lock blockchain failed")
ErrListenFailed = fmt.Errorf("listen failed")
ErrCheckingIsOnTopOfBlockchainsLocksFailed = fmt.Errorf("checking is on top of blockchains locks failed")
ErrNodeRegisterFailed = fmt.Errorf("node register failed")
ErrNodeUnregisterFailed = fmt.Errorf("node unregister failed")
ErrNodeLookupFailed = fmt.Errorf("node lookup failed")
ErrNodeRegisteredAddressesQueryFailed = fmt.Errorf("node registered addresses query failed")
)
type DBConfig
Config contains configuration for the database.
type DBConfig struct {
ConnStr string `yaml:"conn_str"` // ConnStr is the connection string to the database.
DatabaseName string `yaml:"database_name"` // DatabaseName is the name of the database.
IsSSL bool `yaml:"is_ssl"` // IsSSL is the flag that indicates if the connection should be encrypted.
}
type DataBase
Database provides database access for read, write and delete of repository entities.
type DataBase struct {
// contains filtered or unexported fields
}
func Connect
func Connect(ctx context.Context, cfg DBConfig) (*DataBase, error)
Connect creates new connection to the repository and returns pointer to the DataBase.
func (DataBase) AddToBlockchainLockQueue
func (db DataBase) AddToBlockchainLockQueue(ctx context.Context, nodeID string) error
AddToBlockchainLockQueue adds blockchain lock to queue.
func (DataBase) CheckAddressExists
func (db DataBase) CheckAddressExists(ctx context.Context, addr string) (bool, error)
CheckAddressExists checks if address exists in the database.
func (DataBase) CheckIsOnTopOfBlockchainsLocks
func (db DataBase) CheckIsOnTopOfBlockchainsLocks(ctx context.Context, nodeID string) (bool, error)
CheckIsOnTopOfBlockchainsLocks checks if node is on top of blockchain locks queue.
func (DataBase) CheckToken
func (db DataBase) CheckToken(ctx context.Context, tkn string) (bool, error)
CheckToken checks if token exists in the database is valid and didn't expire.
func (DataBase) CountRegistered
func (db DataBase) CountRegistered(ctx context.Context) (int, error)
CountRegistered counts registered nodes in the database.
func (DataBase) Disconnect
func (db DataBase) Disconnect(ctx context.Context) error
Disconnect disconnects user from database
func (DataBase) FindAddress
func (db DataBase) FindAddress(ctx context.Context, search string, limit int) ([]string, error)
FindAddress finds address in the database.
func (DataBase) FindTransactionInBlockHash
func (db DataBase) FindTransactionInBlockHash(ctx context.Context, trxHash [32]byte) ([32]byte, error)
FindTransactionInBlockHash returns block hash in to which transaction with given hash was added. If transaction is not yet added to any block, empty hash is returned.
func (DataBase) InvalidateToken
func (db DataBase) InvalidateToken(ctx context.Context, token string) error
InvalidateToken invalidates token.
func (DataBase) IsAddressAdmin
func (db DataBase) IsAddressAdmin(ctx context.Context, addr string) (bool, error)
IsAddressAdmin checks if address has access level admin.
func (DataBase) IsAddressStandard
func (db DataBase) IsAddressStandard(ctx context.Context, addr string) (bool, error)
IsAddressStandard checks if address has access level standard.
func (DataBase) IsAddressSuspended
func (db DataBase) IsAddressSuspended(ctx context.Context, addr string) (bool, error)
IsAddressAdmin checks if address has access level suspended.
func (DataBase) IsAddressTrusted
func (db DataBase) IsAddressTrusted(ctx context.Context, addr string) (bool, error)
IsAddressTrusted checks if address has access level trusted.
func (DataBase) LastBlock
func (db DataBase) LastBlock(ctx context.Context) (block.Block, error)
LastBlock returns last block from the database.
func (DataBase) MoveTransactionsFromAwaitingToTemporary
func (db DataBase) MoveTransactionsFromAwaitingToTemporary(ctx context.Context, trxHash [32]byte) error
MoveTransactionsFromAwaitingToTemporary moves awaiting transaction marking it as temporary.
func (DataBase) MoveTransactionsFromTemporaryToPermanent
func (db DataBase) MoveTransactionsFromTemporaryToPermanent(ctx context.Context, blockHash [32]byte, hashes [][32]byte) error
MoveTransactionsFromTemporaryToPermanent moves transactions by marking transactions with matching hash to be permanent and sets block hash field to referenced block hash.
func (DataBase) Ping
func (db DataBase) Ping(ctx context.Context) error
Ping checks if the connection to the database is still alive.
func (DataBase) ReadAwaitingTransactionsByIssuer
func (db DataBase) ReadAwaitingTransactionsByIssuer(ctx context.Context, address string) ([]transaction.Transaction, error)
ReadAwaitingTransactionsByIssuer reads all transactions paired with given issuer address.
func (DataBase) ReadAwaitingTransactionsByReceiver
func (db DataBase) ReadAwaitingTransactionsByReceiver(ctx context.Context, address string) ([]transaction.Transaction, error)
ReadAwaitingTransactionsByReceiver reads all transactions paired with given receiver address.
func (DataBase) ReadBlockByHash
func (db DataBase) ReadBlockByHash(ctx context.Context, hash [32]byte) (block.Block, error)
ReadBlockByHash returns block with given hash.
func (DataBase) ReadLastNValidatorStatuses
func (db DataBase) ReadLastNValidatorStatuses(ctx context.Context, last int64) ([]validator.Status, error)
ReadLastNValidatorStatuses reads last validator statuses from the database.
func (DataBase) ReadRegisteredNodesAddresses
func (db DataBase) ReadRegisteredNodesAddresses(ctx context.Context) ([]string, error)
ReadAddresses reads registered nodes addresses from the database.
func (DataBase) ReadTemporaryTransactions
func (db DataBase) ReadTemporaryTransactions(ctx context.Context) ([]transaction.Transaction, error)
ReadTemporaryTransactions reads all transactions that are marked as temporary.
func (DataBase) RegisterNode
func (db DataBase) RegisterNode(ctx context.Context, n, ws string) error
RegisterNode registers node in the database.
func (DataBase) RemoveFromBlockchainLocks
func (db DataBase) RemoveFromBlockchainLocks(ctx context.Context, nodeID string) error
RemoveFromBlockchainLocks removes blockchain lock from queue.
func (DataBase) RunMigration
func (DataBase) RunMigration(_ context.Context) error
RunMigration satisfies the RepositoryProvider interface as PostgreSQL migrations are run on when database is created in docker-compose-postgresql.yml.
func (DataBase) UnregisterNode
func (db DataBase) UnregisterNode(ctx context.Context, n string) error
UnregisterNode unregister node from the database.
func (DataBase) Write
func (db DataBase) Write(p []byte) (n int, err error)
Write writes log to the database. p is a marshaled logger.Log.
func (DataBase) WriteAddress
func (db DataBase) WriteAddress(ctx context.Context, addr string) error
WriteAddress writes address to the database.
func (DataBase) WriteBlock
func (db DataBase) WriteBlock(ctx context.Context, block block.Block) error
WriteBlock writes block to the database.
func (DataBase) WriteIssuerSignedTransactionForReceiver
func (db DataBase) WriteIssuerSignedTransactionForReceiver(ctx context.Context, trx *transaction.Transaction) error
WriteIssuerSignedTransactionForReceiver writes transaction to the storage marking it as awaiting.
func (DataBase) WriteToken
func (db DataBase) WriteToken(ctx context.Context, tkn string, expirationDate int64) error
WriteToken writes unique token to the database.
func (DataBase) WriteValidatorStatus
func (db DataBase) WriteValidatorStatus(ctx context.Context, vs *validator.Status) error
WriteValidatorStatus writes validator status to the database.
type Listener
Listener wraps listener for notifications from database. Provides methods for listening and closing.
type Listener struct {
// contains filtered or unexported fields
}
func Listen
func Listen(conn string, report func(ev pq.ListenerEventType, err error)) (Listener, error)
Listen creates Listener for notifications from database.
func Subscribe
func Subscribe(ctx context.Context, cfg DBConfig) (Listener, error)
Subscribe subscribes to the database events.
func (Listener) Close
func (l Listener) Close()
Close closes listener.
func (Listener) SubscribeToLockBlockchainNotification
func (l Listener) SubscribeToLockBlockchainNotification(ctx context.Context, c chan<- bool, node string)
SubscribeToLockBlockchainNotification listens for blockchain lock. To stop subscription, close channel.
serializer
import "github.com/bartossh/Computantis/serializer"
Index
func Base58Decode
func Base58Decode(input []byte) ([]byte, error)
Base58Decode decodes base58 string to byte array.
func Base58Encode
func Base58Encode(input []byte) []byte
Base58Encode encodes byte array to base58 string.
server
import "github.com/bartossh/Computantis/server"
Index
- Constants
- Variables
- func Run(ctx context.Context, c Config, repo Repository, bookkeeping Bookkeeper, pv RandomDataProvideValidator, log logger.Logger, rx ReactiveSubscriberProvider) error
- type AddressReaderWriterModifier
- type AliveResponse
- type AwaitedIssuedTransactionRequest
- type AwaitedTransactionResponse
- type Bookkeeper
- type Config
- type CreateAddressRequest
- type CreateAddressResponse
- type DataToSignRequest
- type DataToSignResponse
- type GenerateTokenRequest
- type GenerateTokenResponse
- type IssuedTransactionResponse
- type Message
- type RandomDataProvideValidator
- type ReactiveSubscriberProvider
- type Register
- type Repository
- type SearchAddressRequest
- type SearchAddressResponse
- type SearchBlockRequest
- type SearchBlockResponse
- type TokenWriteInvalidateChecker
- type TransactionConfirmProposeResponse
- type TransactionProposeRequest
- type Verifier
Constants
const (
ApiVersion = "1.0.0"
Header = "Computantis-Central"
)
const (
AliveURL = "/alive" // URL to check if server is alive and version.
SearchAddressURL = searchGroupURL + addressURL // URL to search for address.
SearchBlockURL = searchGroupURL + blockURL // URL to search for block that contains transaction hash.
ProposeTransactionURL = transactionGroupURL + proposeURL // URL to propose transaction signed by the issuer.
ConfirmTransactionURL = transactionGroupURL + confirmURL // URL to confirm transaction signed by the receiver.
AwaitedTransactionURL = transactionGroupURL + awaitedURL // URL to get awaited transactions for the receiver.
IssuedTransactionURL = transactionGroupURL + issuedURL // URL to get issued transactions for the issuer.
DataToValidateURL = validatorGroupURL + dataURL // URL to get data to validate address by signing rew message.
CreateAddressURL = addressGroupURL + createURL // URL to create new address.
GenerateTokenURL = tokenGroupURL + generateURL // URL to generate new token.
WsURL = "/ws" // URL to connect to websocket.
)
const (
CommandEcho = "echo"
CommandSocketList = "socketlist"
CommandNewBlock = "command_new_block"
CommandNewTransaction = "command_new_transaction"
)
Variables
var (
ErrWrongPortSpecified = errors.New("port must be between 1 and 65535")
ErrWrongMessageSize = errors.New("message size must be between 1024 and 15000000")
)
func Run
func Run(ctx context.Context, c Config, repo Repository, bookkeeping Bookkeeper, pv RandomDataProvideValidator, log logger.Logger, rx ReactiveSubscriberProvider) error
Run initializes routing and runs the server. To stop the server cancel the context. It blocks until the context is canceled.
type AddressReaderWriterModifier
AddressReaderWriterModifier abstracts address operations.
type AddressReaderWriterModifier interface {
FindAddress(ctx context.Context, search string, limit int) ([]string, error)
CheckAddressExists(ctx context.Context, address string) (bool, error)
WriteAddress(ctx context.Context, address string) error
IsAddressSuspended(ctx context.Context, addr string) (bool, error)
IsAddressStandard(ctx context.Context, addr string) (bool, error)
IsAddressTrusted(ctx context.Context, addr string) (bool, error)
IsAddressAdmin(ctx context.Context, addr string) (bool, error)
}
type AliveResponse
AliveResponse is a response for alive and version check.
type AliveResponse struct {
Alive bool `json:"alive"`
APIVersion string `json:"api_version"`
APIHeader string `json:"api_header"`
}
type AwaitedIssuedTransactionRequest
AwaitedIssuedTransactionRequest is a request to get awaited or issued transactions for given address. Request contains of Address for which Transactions are requested, Data in binary format, Hash of Data and Signature of the Data to prove that entity doing the request is an Address owner.
type AwaitedIssuedTransactionRequest struct {
Address string `json:"address"`
Data []byte `json:"data"`
Hash [32]byte `json:"hash"`
Signature []byte `json:"signature"`
}
type AwaitedTransactionResponse
AwaitedTransactionResponse is a response for awaited transactions request.
type AwaitedTransactionResponse struct {
Success bool `json:"success"`
AwaitedTransactions []transaction.Transaction `json:"awaited_transactions"`
}
type Bookkeeper
Bookkeeper abstracts methods of the bookkeeping of a blockchain.
type Bookkeeper interface {
Verifier
Run(ctx context.Context)
WriteCandidateTransaction(ctx context.Context, tx *transaction.Transaction) error
WriteIssuerSignedTransactionForReceiver(ctx context.Context, trx *transaction.Transaction) error
}
type Config
Config contains configuration of the server.
type Config struct {
Port int `yaml:"port"` // Port to listen on.
DataSizeBytes int `yaml:"data_size_bytes"` // Size of the data to be stored in the transaction.
WebsocketAddress string `yaml:"websocket_address"` // Address of the websocket server.
}
type CreateAddressRequest
CreateAddressRequest is a request to create an address.
type CreateAddressRequest struct {
Address string `json:"address"`
Token string `json:"token"`
Data []byte `json:"data"`
Hash [32]byte `json:"hash"`
Signature []byte `json:"signature"`
}
type CreateAddressResponse
Response for address creation request. If Success is true, Address contains created address in base58 format.
type CreateAddressResponse struct {
Success bool `json:"success"`
Address string `json:"address"`
}
type DataToSignRequest
DataToSignRequest is a request to get data to sign for proving identity.
type DataToSignRequest struct {
Address string `json:"address"`
}
type DataToSignResponse
DataToSignRequest is a response containing data to sign for proving identity.
type DataToSignResponse struct {
Data []byte `json:"message"`
}
type GenerateTokenRequest
GenerateTokenRequest is a request for token generation.
type GenerateTokenRequest struct {
Address string `json:"address"`
Expiration int64 `json:"expiration"`
Data []byte `json:"data"`
Hash [32]byte `json:"hash"`
Signature []byte `json:"signature"`
}
type GenerateTokenResponse
GenerateTokenResponse is a response containing generated token.
type GenerateTokenResponse = token.Token
type IssuedTransactionResponse
AwaitedTransactionResponse is a response for issued transactions request.
type IssuedTransactionResponse struct {
Success bool `json:"success"`
IssuedTransactions []transaction.Transaction `json:"issued_transactions"`
}
type Message
Message is the message that is used to exchange information between the server and the client.
type Message struct {
Command string `json:"command"` // Command is the command that refers to the action handler in websocket protocol.
Error string `json:"error,omitempty"` // Error is the error message that is sent to the client.
Block block.Block `json:"block,omitempty"` // Block is the block that is sent to the client.
Transaction transaction.Transaction `json:"transaction,omitempty"` // Transaction is the transaction validated by the central server and will be added to the next block.
Sockets []string `json:"sockets,omitempty"` // sockets is the list of central nodes web-sockets addresses.
}
type RandomDataProvideValidator
RandomDataProvideValidator provides random binary data for signing to prove identity and the validator of data being valid and not expired.
type RandomDataProvideValidator interface {
ProvideData(address string) []byte
ValidateData(address string, data []byte) bool
}
type ReactiveSubscriberProvider
ReactiveSubscriberProvider provides reactive subscription to the blockchain. It allows to listen for the new blocks created by the Ladger.
type ReactiveSubscriberProvider interface {
Cancel()
Channel() <-chan block.Block
}
type Register
Register abstracts node registration operations.
type Register interface {
RegisterNode(ctx context.Context, n, ws string) error
UnregisterNode(ctx context.Context, n string) error
ReadRegisteredNodesAddresses(ctx context.Context) ([]string, error)
CountRegistered(ctx context.Context) (int, error)
}
type Repository
Repository is the interface that wraps the basic CRUD and Search methods. Repository should be properly indexed to allow for transaction and block hash. as well as address public keys to be and unique and the hash lookup should be fast. Repository holds the blocks and transaction that are part of the blockchain.
type Repository interface {
Register
AddressReaderWriterModifier
TokenWriteInvalidateChecker
FindTransactionInBlockHash(ctx context.Context, trxHash [32]byte) ([32]byte, error)
ReadAwaitingTransactionsByIssuer(ctx context.Context, address string) ([]transaction.Transaction, error)
ReadAwaitingTransactionsByReceiver(ctx context.Context, address string) ([]transaction.Transaction, error)
}
type SearchAddressRequest
SearchAddressRequest is a request to search for address.
type SearchAddressRequest struct {
Address string `json:"address"`
}
type SearchAddressResponse
SearchAddressResponse is a response for address search.
type SearchAddressResponse struct {
Addresses []string `json:"addresses"`
}
type SearchBlockRequest
SearchBlockRequest is a request to search for block.
type SearchBlockRequest struct {
Address string `json:"address"`
RawTrxHash [32]byte `json:"raw_trx_hash"`
}
type SearchBlockResponse
SearchBlockResponse is a response for block search.
type SearchBlockResponse struct {
RawBlockHash [32]byte `json:"raw_block_hash"`
}
type TokenWriteInvalidateChecker
TokenWriteInvalidateChecker abstracts token operations.
type TokenWriteInvalidateChecker interface {
WriteToken(ctx context.Context, tkn string, expirationDate int64) error
CheckToken(ctx context.Context, token string) (bool, error)
InvalidateToken(ctx context.Context, token string) error
}
type TransactionConfirmProposeResponse
TransactionConfirmProposeResponse is a response for transaction propose.
type TransactionConfirmProposeResponse struct {
Success bool `json:"success"`
TrxHash [32]byte `json:"trx_hash"`
}
type TransactionProposeRequest
TransactionProposeRequest is a request to propose a transaction.
type TransactionProposeRequest struct {
ReceiverAddr string `json:"receiver_addr"`
Transaction transaction.Transaction `json:"transaction"`
}
type Verifier
Verifier provides methods to verify the signature of the message.
type Verifier interface {
VerifySignature(message, signature []byte, hash [32]byte, address string) error
}
signerservice
import "github.com/bartossh/Computantis/signerservice"
Index
- Constants
- func Run(ctx context.Context, cfg Config, log logger.Logger, timeout time.Duration, fw transaction.Verifier, wrs client.WalletReadSaver, walletCreator client.NewSignValidatorCreator) error
- type Config
- type ConfirmTransactionRequest
- type ConfirmTransactionResponse
- type CreateWalletRequest
- type CreateWalletResponse
- type IssueTransactionRequest
- type IssueTransactionResponse
- type IssuedTransactionResponse
- type ReadWalletPublicAddressResponse
- type ReceivedTransactionResponse
Constants
const (
Alive = "/alive" // alive URL allows to check if server is alive and if sign service is of the same version.
IssueTransaction = "/transactions/issue" // issue URL allows to issue transaction signed by the issuer.
ConfirmTransaction = "/transaction/sign" // sign URL allows to sign transaction received by the receiver.
GetIssuedTransactions = "/transactions/issued" // issued URL allows to get issued transactions for the issuer.
GetReceivedTransactions = "/transactions/received" // received URL allows to get received transactions for the receiver.
CreateWallet = "/wallet/create" // create URL allows to create new wallet.
ReadWalletPublicAddress = "/wallet/address" // address URL allows to read public address of the wallet.
GetOneDayToken = "token/day" // token/day URL allows to get one day token.
GetOneWeekToken = "token/week" // token/week URL allows to get one week token.
)
func Run
func Run(ctx context.Context, cfg Config, log logger.Logger, timeout time.Duration, fw transaction.Verifier, wrs client.WalletReadSaver, walletCreator client.NewSignValidatorCreator) error
Run runs the service application that exposes the API for creating, validating and signing transactions. This blocks until the context is canceled.
type Config
Config is the configuration for the server
type Config struct {
Port string `yaml:"port"`
CentralNodeAddress string `yaml:"central_node_address"`
}
type ConfirmTransactionRequest
ValidateTransactionRequest is a request to validate transaction.
type ConfirmTransactionRequest struct {
Transaction transaction.Transaction `json:"transaction"`
}
type ConfirmTransactionResponse
ConfirmTransactionResponse is response to validate transaction.
type ConfirmTransactionResponse struct {
Ok bool `json:"ok"`
Err string `json:"err"`
}
type CreateWalletRequest
CreateWalletRequest is a request to create wallet.
type CreateWalletRequest struct {
Token string `json:"token"`
}
type CreateWalletResponse
CreateWalletResponse is response to create wallet.
type CreateWalletResponse struct {
Ok bool `json:"ok"`
Err string `json:"err"`
}
type IssueTransactionRequest
IssueTransactionRequest is a request message that contains data and subject of the transaction to be issued.
type IssueTransactionRequest struct {
ReceiverAddress string `json:"receiver_address"`
Subject string `json:"subject"`
Data []byte `json:"data"`
}
type IssueTransactionResponse
IssueTransactionResponse is response to issued transaction.
type IssueTransactionResponse struct {
Ok bool `json:"ok"`
Err string `json:"err"`
}
type IssuedTransactionResponse
IssuedTransactionResponse is a response of issued transactions.
type IssuedTransactionResponse struct {
Ok bool `json:"ok"`
Err string `json:"err"`
Transactions []transaction.Transaction `json:"transactions"`
}
type ReadWalletPublicAddressResponse
ReadWalletPublicAddressResponse is a response to read wallet public address.
type ReadWalletPublicAddressResponse struct {
Ok bool `json:"ok"`
Err string `json:"err"`
Address string `json:"address"`
}
type ReceivedTransactionResponse
ReceivedTransactionResponse is a response of issued transactions.
type ReceivedTransactionResponse struct {
Ok bool `json:"ok"`
Err string `json:"err"`
Transactions []transaction.Transaction `json:"transactions"`
}
stdoutwriter
import "github.com/bartossh/Computantis/stdoutwriter"
Index
type Logger
type Logger struct{}
func (Logger) Write
func (l Logger) Write(p []byte) (n int, err error)
stress
import "github.com/bartossh/Computantis/stress"
Stress is a package that provides a simple way to stress test your code on the full cycle of transaction processing.
Index
token
import "github.com/bartossh/Computantis/token"
Index
type Token
Token holds information about unique token. Token is a way of proving to the REST API of the central server that the request is valid and comes from the client that is allowed to use the API.
type Token struct {
ID any `json:"-" bson:"_id,omitempty" db:"id"`
Token string `json:"token" bson:"token" db:"token"`
Valid bool `json:"valid" bson:"valid" db:"valid"`
ExpirationDate int64 `json:"expiration_date" bson:"expiration_date" db:"expiration_date"`
}
func New
func New(expiration int64) (Token, error)
New creates new token.
transaction
import "github.com/bartossh/Computantis/transaction"
Index
- Constants
- Variables
- type Signer
- type Transaction
- type TransactionAwaitingReceiverSignature
- type TransactionInBlock
- type Verifier
Constants
const ExpirationTimeInDays = 7 // transaction validity expiration time in days. TODO: move to config
Variables
var (
ErrTransactionHasAFutureTime = errors.New("transaction has a future time")
ErrExpiredTransaction = errors.New("transaction has expired")
ErrTransactionHashIsInvalid = errors.New("transaction hash is invalid")
ErrSignatureNotValidOrDataCorrupted = errors.New("signature not valid or data are corrupted")
ErrSubjectIsEmpty = errors.New("subject cannot be empty")
ErrAddressIsInvalid = errors.New("address is invalid")
)
type Signer
Signer provides signing and address methods.
type Signer interface {
Sign(message []byte) (digest [32]byte, signature []byte)
Address() string
}
type Transaction
Transaction contains transaction information, subject type, subject data, signatures and public keys. Transaction is valid for a week from being issued. Subject represents an information how to read the Data and / or how to decode them. Data is not validated by the computantis server, Ladger ior block. What is stored in Data is not important for the whole Computantis system. It is only important that the data are signed by the issuer and the receiver and both parties agreed on them.
type Transaction struct {
ID any `json:"-" bson:"_id" db:"id"`
CreatedAt time.Time `json:"created_at" bson:"created_at" db:"created_at"`
Hash [32]byte `json:"hash" bson:"hash" db:"hash"`
IssuerAddress string `json:"issuer_address" bson:"issuer_address" db:"issuer_address"`
ReceiverAddress string `json:"receiver_address" bson:"receiver_address" db:"receiver_address"`
Subject string `json:"subject" bson:"subject" db:"subject"`
Data []byte `json:"data" bson:"data" db:"data"`
IssuerSignature []byte `json:"issuer_signature" bson:"issuer_signature" db:"issuer_signature"`
ReceiverSignature []byte `json:"receiver_signature" bson:"receiver_signature" db:"receiver_signature"`
}
func New
func New(subject string, data []byte, receiverAddress string, issuer Signer) (Transaction, error)
New creates new transaction signed by the issuer.
func (*Transaction) GeMessage
func (t *Transaction) GeMessage() []byte
GeMessage returns message used for signature validation.
func (*Transaction) Sign
func (t *Transaction) Sign(receiver Signer, v Verifier) ([32]byte, error)
Sign verifies issuer signature and signs Transaction by the receiver.
type TransactionAwaitingReceiverSignature
TransactionAwaitingReceiverSignature represents transaction awaiting receiver signature. It is as well the entity of all issued transactions that has not been signed by receiver yet.
type TransactionAwaitingReceiverSignature struct {
ID any `json:"-" bson:"_id,omitempty" db:"id"`
ReceiverAddress string `json:"receiver_address" bson:"receiver_address" db:"receiver_address"`
IssuerAddress string `json:"issuer_address" bson:"issuer_address" db:"issuer_address"`
Transaction Transaction `json:"transaction" bson:"transaction" db:"-"`
TransactionHash [32]byte `json:"transaction_hash" bson:"transaction_hash" db:"hash"`
}
type TransactionInBlock
TransactionInBlock stores relation between Transaction and Block to which Transaction was added. It is stored for fast lookup only to allow to find Block hash in which Transaction was added.
type TransactionInBlock struct {
ID any `json:"-" bson:"_id,omitempty" db:"id"`
BlockHash [32]byte `json:"-" bson:"block_hash" db:"block_hash"`
TransactionHash [32]byte `json:"-" bson:"transaction_hash" db:"transaction_hash"`
}
type Verifier
Verifier provides signature verification method.
type Verifier interface {
Verify(message, signature []byte, hash [32]byte, issuer string) error
}
validator
import "github.com/bartossh/Computantis/validator"
Index
- Constants
- Variables
- func Run(ctx context.Context, cfg Config, srw StatusReadWriter, log logger.Logger, ver Verifier, wh WebhookCreateRemovePoster, wallet *wallet.Wallet) error
- type Config
- type CreateRemoveUpdateHookRequest
- type Status
- type StatusReadWriter
- type Verifier
- type WebHookNewBlockMessage
- type WebhookCreateRemovePoster
Constants
const (
Header = "Computantis-Validator"
)
Variables
var (
ErrProofBlockIsInvalid = fmt.Errorf("block proof is invalid")
ErrBlockIndexIsInvalid = fmt.Errorf("block index is invalid")
ErrBlockPrevHashIsInvalid = fmt.Errorf("block previous hash is invalid")
)
func Run
func Run(ctx context.Context, cfg Config, srw StatusReadWriter, log logger.Logger, ver Verifier, wh WebhookCreateRemovePoster, wallet *wallet.Wallet) error
Run initializes routing and runs the validator. To stop the validator cancel the context. Validator connects to the central server via websocket and listens for new blocks. It will block until the context is canceled.
type Config
Config contains configuration of the validator.
type Config struct {
Token string `yaml:"token"` // token is used to authenticate validator in the central server
Websocket string `yaml:"websocket"` // websocket address of the central server
Port int `yaml:"port"` // port on which validator will listen for http requests
}
type CreateRemoveUpdateHookRequest
CreateRemoveUpdateHookRequest is the request sent to create, remove or update the webhook.
type CreateRemoveUpdateHookRequest struct {
URL string `json:"address"` // URL is a url of the webhook.
Hook string `json:"hook"` // Hook is a type of the webhook. It describes on what event the webhook is triggered.
Address string `json:"wallet_address"` // Address is the address of the wallet that is used to sign the webhook.
Token string `json:"token"` // Token is the token added to the webhook to verify that the message comes from the valid source.
Data []byte `json:"data"` // Data is the data is a subject of the signature. It is signed by the wallet address.
Digest []byte `json:"digest"` // Digest is the digest of the data. It is used to verify that the data is not changed.
Signature []byte `json:"signature"` // Signature is the signature of the data. It is used to verify that the data is not changed.
}
type Status
Status is a status of each received block by the validator. It keeps track of invalid blocks in case of blockchain corruption.
type Status struct {
ID any `json:"-" bson:"_id,omitempty" db:"id"`
Index int64 `json:"index" bson:"index" db:"index"`
Block block.Block `json:"block" bson:"block" db:"-"`
Valid bool `json:"valid" bson:"valid" db:"valid"`
CreatedAt time.Time `json:"created_at" bson:"created_at" db:"created_at"`
}
type StatusReadWriter
StatusReadWriter provides methods to bulk read and single write validator status.
type StatusReadWriter interface {
WriteValidatorStatus(ctx context.Context, vs *Status) error
ReadLastNValidatorStatuses(ctx context.Context, last int64) ([]Status, error)
}
type Verifier
Verifier provides methods to verify the signature of the message.
type Verifier interface {
Verify(message, signature []byte, hash [32]byte, address string) error
}
type WebHookNewBlockMessage
WebHookNewBlockMessage is the message sent to the webhook url that was created.
type WebHookNewBlockMessage struct {
Token string `json:"token"` // Token given to the webhook by the webhooks creator to validate the message source.
Block block.Block `json:"block"` // Block is the block that was mined.
Valid bool `json:"valid"` // Valid is the flag that indicates if the block is valid.
}
type WebhookCreateRemovePoster
WebhookCreateRemovePoster provides methods to create, remove webhooks and post messages to webhooks.
type WebhookCreateRemovePoster interface {
CreateWebhook(trigger string, h webhooks.Hook) error
RemoveWebhook(trigger string, h webhooks.Hook) error
PostWebhookBlock(blc *block.Block)
}
wallet
import "github.com/bartossh/Computantis/wallet"
Index
- type Helper
- type Wallet
- func DecodeGOBWallet(data []byte) (Wallet, error)
- func New() (Wallet, error)
- func (w *Wallet) Address() string
- func (w *Wallet) ChecksumLength() int
- func (w *Wallet) EncodeGOB() ([]byte, error)
- func (w *Wallet) Sign(message []byte) (digest [32]byte, signature []byte)
- func (w *Wallet) Verify(message, signature []byte, hash [32]byte) bool
- func (w *Wallet) Version() byte
type Helper
Helper provides wallet helper functionalities without knowing about wallet private and public keys.
type Helper struct{}
func NewVerifier
func NewVerifier() Helper
NewVerifier creates new wallet Helper verifier.
func (Helper) AddressToPubKey
func (h Helper) AddressToPubKey(address string) (ed25519.PublicKey, error)
AddressToPubKey creates ED25519 public key from address, or returns error otherwise.
func (Helper) Verify
func (h Helper) Verify(message, signature []byte, hash [32]byte, address string) error
Verify verifies if message is signed by given key and hash is equal.
type Wallet
Wallet holds public and private key of the wallet owner.
type Wallet struct {
Private ed25519.PrivateKey `json:"private" bson:"private"`
Public ed25519.PublicKey `json:"public" bson:"public"`
}
func DecodeGOBWallet
func DecodeGOBWallet(data []byte) (Wallet, error)
DecodeGOBWallet tries to decode Wallet from gob representation or returns error otherwise.
func New
func New() (Wallet, error)
New tries to creates a new Wallet or returns error otherwise.
func (*Wallet) Address
func (w *Wallet) Address() string
Address creates address from the public key that contains wallet version and checksum.
func (*Wallet) ChecksumLength
func (w *Wallet) ChecksumLength() int
ChecksumLength returns checksum length.
func (*Wallet) EncodeGOB
func (w *Wallet) EncodeGOB() ([]byte, error)
EncodeGOB tries to encodes Wallet in to the gob representation or returns error otherwise.
func (*Wallet) Sign
func (w *Wallet) Sign(message []byte) (digest [32]byte, signature []byte)
Sign signs the message with Ed25519 signature. Returns digest hash sha256 and signature.
func (*Wallet) Verify
func (w *Wallet) Verify(message, signature []byte, hash [32]byte) bool
Verify verifies message ED25519 signature and hash. Uses hashing sha256.
func (*Wallet) Version
func (w *Wallet) Version() byte
Version returns wallet version.
webhooks
import "github.com/bartossh/Computantis/webhooks"
Index
Constants
const (
TriggerNewBlock = "trigger_new_block" // TriggerNewBlock is the trigger for new block. It is triggered when a new block is forged.
)
Variables
var (
ErrorHookNotImplemented = errors.New("hook not implemented")
)
type Hook
Hook is the hook that is used to trigger the webhook.
type Hook struct {
URL string `json:"address"` // URL is a url of the webhook.
Token string `json:"token"` // Token is the token added to the webhook to verify that the message comes from the valid source.
}
type HookRequestHTTPPoster
HookRequestHTTPPoster provides PostWebhookBlock method that allows to post new forged block to the webhook url over HTTP protocol.
type HookRequestHTTPPoster interface {
PostWebhookBlock(url string, token string, block *block.Block) error
}
type Service
Service provide webhook service that is used to create, remove and update webhooks.
type Service struct {
// contains filtered or unexported fields
}
func New
func New(client HookRequestHTTPPoster, l logger.Logger) *Service
New creates new instance of the webhook service.
func (*Service) CreateWebhook
func (s *Service) CreateWebhook(trigger string, h Hook) error
CreateWebhook creates new webhook or or updates existing one for given trigger.
func (*Service) PostWebhookBlock
func (s *Service) PostWebhookBlock(blc *block.Block)
PostWebhookBlock posts block to all webhooks that are subscribed to the new block trigger.
func (*Service) RemoveWebhook
func (s *Service) RemoveWebhook(trigger string, h Hook) error
RemoveWebhook removes webhook for given trigger and Hook URL.
central
import "github.com/bartossh/Computantis/cmd/central"
Index
validator
import "github.com/bartossh/Computantis/cmd/validator"
Index
wallet
import "github.com/bartossh/Computantis/cmd/wallet"
Index
Generated by gomarkdoc
Directories
¶
Path | Synopsis |
---|---|
cmd
|
|
src
module
|
|
Stress is a package that provides a simple way to stress test your code on the full cycle of transaction processing.
|
Stress is a package that provides a simple way to stress test your code on the full cycle of transaction processing. |
your front-end html should look like this: ```html <html> <head>
|
your front-end html should look like this: ```html <html> <head> |