Return codes for vfs application
const ( CodeTypeOK uint32 = 0 CodeTypeEmptyDataError uint32 = 1 CodeTypeInvalidFormatError uint32 = 2 CodeTypeInvalidSignatureError uint32 = 3 )
const ( AppVersion uint64 = 1 QueryType_Default string = "hash" QueryType_Height string = "height" QueryType_PubKey string = "pubkey" )
func ComputeHash(p *SignedTransaction) []byte
ComputeHash computes the SHA256 hash of a signed transaction The transaction hash consists of a SHA256 of the signer public key, followed by the data and the attached timestamp bytes.
func Decrypt(secret []byte, ciphertext []byte) ([]byte, error)
Decrypt decrypts a ciphertext using the secret with the AES block cipher algo.
func Encrypt(secret []byte, data []byte) ([]byte, error)
Encrypt encrypts a plaintext using the secret with the AES block cipher algo.
func GenerateSecret(pw, salt []byte) ([]byte, []byte, error)
GenerateSecret generates a 32-bytes secret by creating a SHA-256 hash of a salted password using a random salt of 8-bytes. If a non-empty salt is provided, it is expected to be of 8-bytes length. It returns the 32-bytes secret and an 8-bytes salt.
func MustGenerateIdentity(idFile string, pw []byte) (string, string)
MustGenerateIdentity generates a new ed25519 private key and saves it to the provided idFile file. A password pw is used to encrypt the private key. 8 bytes are added in front of the ciphertext which consist of a random salt. The created identity file contains a base64-encoded AES ciphertext prefixed with a random salt of 8 bytes. This function will panic if any errors occur.
func MustGenerateSecret(pw, salt []byte) ([]byte, []byte)
MustGenerateSecret generates a 32-bytes secret with salt or panics. This function will panic if any errors occur.
func NewIdentity(file string, pw []byte) *identityFile
NewIdentity creates a new identityFile instance
func PubKeyToProto(pubKey crypto.PubKey) cmtp2p.PublicKey
func SignData(priv ed25519.PrivKey, tx Signable) []byte
SignData signs a transaction using a private key.
IdentitySecretProvider describes a provider that returns an AES-256 secret which is used to encrypt the database.
type IdentitySecretProvider interface { // Secret returns the 32-bytes secret used for encryption of data. // This is the secret used to encrypt the contents of the database. Secret() ([]byte, error) // PrivKey returns a ed25519 private key instance. PrivKey() (ed25519.PrivKey, error) // PubKey returns a ed25519 public key from the private key. PubKey() (crypto.PubKey, error) }
SecretProvider describes a provider that returns an AES-256 secret which is used to encrypt an ed25519 identity (private key).
type SecretProvider interface { // Bytes returns the raw bytes of a secret provider which include the random // salt (8 bytes) used for encryption and the private key (64 bytes) // Note: This function does not decrypt the AES encrypted private key. Bytes() ([]byte, error) // Open returns the bytes of the private key (64-bytes) // This method shall decrypt the AES encrypted private key. Open() ([]byte, error) // Secret returns the 32-bytes secret used for encryption of the private key. // This is the secret used to encrypt the contents of an identity file. Secret() ([]byte, error) // Identity returns a ed25519 identity which is used to encrypt the database. Identity() IdentitySecretProvider }
Signable describes data that can be signed using a private key.
type Signable interface { Sign(ed25519.PrivKey) ([]byte, error) Bytes() []byte }
SignedTransaction describes a signed data object that includes an owner public key, a SHA-256 hash, a size, a signature and a timestamp.
type SignedTransaction struct { Signer ed25519.PubKey Hash []byte Signature []byte Size int Time time.Time Data TransactionBody }
func FromBytes(bz []byte) (*SignedTransaction, error)
FromBytes takes a bytes slice and returns the SignedTransaction
func FromProto(pb *vfsp2p.Transaction) (*SignedTransaction, error)
FromProto takes a transaction proto message and returns the SignedTransaction.
func NewSignedTransactionFromBytes(tx []byte) (*SignedTransaction, error)
NewSignedTransaction expects a signed data payload which contains an owner public key (32 bytes), a signature (64 bytes), a timestamp and at least 1 byte of arbitrary data. TODO: TBI verification of timestamp (too far in future, etc.) TODO: TBI when to verify signatures (careful with CheckTx)
func (p SignedTransaction) Bytes() []byte
Bytes returns a byte slice built from the size-prefixed data and the signature.
func (p SignedTransaction) PublicKey() string
PublicKey returns the uppercase hexadecimal representation of the signer public key.
func (p SignedTransaction) ToProto() *vfsp2p.Transaction
ToProto returns a protobuf transaction object.
func (p SignedTransaction) Verify() bool
Verify returns a boolean that determines the validity of a signature.
State describes the vstore application state which consists of a latest blockchain height, a total number of transactions and cryptographic commitments about transaction data (merkle roots).
type State struct { // NumTransactions is essentially the total number of transactions processed. // This is used for the appHash in combination with the merkle roots NumTransactions int64 `json:"num_transactions"` Height int64 `json:"height"` // MerkleRoots contains the cryptographic commitments for transactions that // have previously been processed. // This is used for the appHash. MerkleRoots map[string][]byte `json:"merkle_roots"` // contains filtered or unexported fields }
func (s State) Hash() []byte
Hash returns the hash of the application state. This is computed as the merkle root of all the committed transaction hashes using a deterministic merkle root slices as produced with MerkleRoots(). The produced hash can be used to verify the integrity of the State. This function is used as the "AppHash"
func (s State) SortedMerkleRoots() [][]byte
MerkleRoots returns a slice of merkle roots that is *deterministic* due to keys always being sorted lexicographically.
TransactionBody represents *unsigned* data.
type TransactionBody []byte
func (p TransactionBody) Bytes() []byte
Bytes returns a byte representation of unsigned data. Bytes implements Signable
func (p TransactionBody) Sign(priv ed25519.PrivKey) ([]byte, error)
Sign creates a digital signature of the bytes using the private key implementation for ed25519. Only ed25519 compatibility is added for now because of being able to batch verify ed25519 signatures. Sign implements Signable
VStoreApplication describes the vStore ABCI application.
type VStoreApplication struct { abci.BaseApplication // contains filtered or unexported fields }
func NewInMemoryVStoreApplication( id_file string, password []byte, ) *VStoreApplication
NewInMemoryApplication creates a new application from an in memory database. NOTE: the data will not be persisted.
func NewVStoreApplication( db cmtdb.DB, id_file string, password []byte, ) *VStoreApplication
NewVStoreApplication creates a vfs application using a DB to load the State and an ed25519 identity to encrypt/decrypt database entities.
func (app *VStoreApplication) CheckTx( _ context.Context, check *abci.RequestCheckTx, ) (*abci.ResponseCheckTx, error)
CheckTx handles inbound transactions or in the case of re-CheckTx assesses old transaction validity after a state transition happened. It is preferable to keep the checks as stateless and as quick as possible. For the vfs application, we check that each transaction has a valid tx format: - Must not be empty - Must contain at least the owner pubkey (32 bytes) and a signature (64 bytes) - Must contain at least 1 byte of arbitrary data CheckTx implements abci.Application
func (app *VStoreApplication) Commit( _ context.Context, commit *abci.RequestCommit, ) (*abci.ResponseCommit, error)
Commit is called after FinalizeBlock and after the CometBFT state updates. The vfs application persists the staged data (from FinalizeBlock) in database in a modified key-value store where the key is the tx hash, and where values describe marshalled protobuf instances of vfsp2p.Transaction. Commit implements abci.Application
func (app *VStoreApplication) FinalizeBlock( ctx context.Context, req *abci.RequestFinalizeBlock, ) (*abci.ResponseFinalizeBlock, error)
FinalizeBlock executes the block against the application state. Transactions are processed one-by-one and are cached in memory. They will be persisted when Commit is called. ConsensusParams are never changed. FinalizeBlock implements abci.Application
func (app *VStoreApplication) Info( _ context.Context, info *abci.RequestInfo, ) (*abci.ResponseInfo, error)
Info returns information about the State of the application. This is used everytime a CometBFT instance begins and forwards its version to the application. Based on this information, CometBFT will ensure synchronicity with the application by potentially replaying some blocks. If the application returns a 0 LastBlockHeight, CometBFT will call InitChain. Info implements abci.Application
func (app *VStoreApplication) InitChain( _ context.Context, chain *abci.RequestInitChain, ) (*abci.ResponseInitChain, error)
InitChain returns the application hash in case the application starts with values pre-populated. This method is called whenever a new instance of the application is started, i.e. when LastBlockHeight is 0. InitChain implements abci.Application
func (app *VStoreApplication) PrepareProposal( ctx context.Context, proposal *abci.RequestPrepareProposal, ) (*abci.ResponsePrepareProposal, error)
PrepareProposal is called only when the node is a proposer. CometBFT stages a set of transactions for the application. NOTE: we assume that CometBFT won't provide too many transactions for 1 block. PrepareProposal implements abci.Application
func (app *VStoreApplication) ProcessProposal( ctx context.Context, proposal *abci.RequestProcessProposal, ) (*abci.ResponseProcessProposal, error)
ProcessProposal is called whenever a node receives a complete proposal and allows the application to validate the proposal. Only validators from the validator set will have this method called. ProcessProposal implements abci.Application
func (app *VStoreApplication) Query( _ context.Context, req *abci.RequestQuery, ) (*abci.ResponseQuery, error)
Query returns an associated value or nil if missing. Expects a transaction hash in the request's Data field. Query implements abci.Application