├── .gitignore ├── .travis.yml ├── Dockerfile ├── LICENSE ├── README.md ├── accounts ├── account.go ├── account_io.go ├── account_io_test.go ├── account_test.go └── accounts.proto ├── api ├── api.go ├── rpc_api.go └── ssl.go ├── cli └── terminal.go ├── common ├── common_cli.go ├── common_io.go ├── common_io_test.go ├── common_types.go └── common_types_test.go ├── config ├── config.proto ├── dag_config.go ├── dag_config_io.go ├── dag_config_io_test.go ├── dag_config_test.go └── test_genesis.json ├── crypto ├── address.go ├── address_test.go ├── crypto.proto ├── sha3.go └── sha3_test.go ├── doc └── spec.md ├── go.mod ├── go.sum ├── internal ├── proto │ ├── accounts │ │ ├── accounts.pb.go │ │ └── accounts.twirp.go │ ├── config │ │ ├── config.pb.go │ │ └── config.twirp.go │ ├── crypto │ │ ├── crypto.pb.go │ │ └── crypto.twirp.go │ ├── dag │ │ ├── dag.pb.go │ │ └── dag.twirp.go │ └── transaction │ │ ├── transaction.pb.go │ │ └── transaction.twirp.go └── rpc │ ├── accounts │ └── server.go │ ├── config │ └── server.go │ ├── crypto │ └── server.go │ ├── dag │ └── server.go │ └── transaction │ └── server.go ├── main.go ├── p2p ├── p2p.go ├── p2p_client.go ├── p2p_client_stream_handlers.go ├── p2p_client_stream_handlers_test.go ├── p2p_client_test.go ├── p2p_stream_handlers.go └── p2p_test.go ├── test.sh ├── types ├── dag.go ├── dag.proto ├── dag_io.go ├── dag_io_test.go ├── dag_test.go ├── transaction.go ├── transaction.proto ├── transaction_io.go ├── transaction_io_test.go ├── transaction_signature.go ├── transaction_signature_io.go ├── transaction_signature_test.go └── transaction_test.go ├── validator ├── beacon_dag_validator.go ├── beacon_dag_validator_test.go └── validator.go └── vm ├── protocol.go └── vm.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Deps 15 | vendor/ 16 | 17 | # VS Code 18 | .vscode/ 19 | 20 | # Test data 21 | common/data/ 22 | config/data/ 23 | types/data/ 24 | p2p/data/ 25 | accounts/data/ 26 | 27 | # Data 28 | data/ 29 | 30 | # System Service 31 | start_server.sh 32 | 33 | # RPC Private Keys 34 | *.pem -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.12 5 | - master 6 | 7 | install: true 8 | 9 | sudo: false 10 | 11 | matrix: 12 | allow_failures: 13 | - go: master 14 | fast_finish: true 15 | 16 | notifications: 17 | email: false 18 | 19 | before_install: 20 | - export GO111MODULE=on # Enable go mod 21 | - go mod vendor # Download deps 22 | 23 | before_script: 24 | - GO_FILES=$(find . -iname '*.go' -type f | grep -v -r ./vendor/) # All the .go files, excluding vendor/, .vendor-new/ 25 | # For .vendor-new inclusion, GO_FILES=$(find . -iname '*.go' -type f | grep -v -r ./vendor/ ./.vendor-new/) 26 | - go get github.com/mattn/goveralls 27 | - go get golang.org/x/tools/cmd/cover 28 | - go get -u golang.org/x/lint/golint 29 | - go get github.com/fzipp/gocyclo 30 | 31 | script: 32 | - test -z $(gofmt -s -l $GO_FILES) # Fail if a .go file hasn't been formatted with gofmt 33 | - go vet ./... # Go vet is the official Go static analyzer 34 | - chmod +x ./test.sh && ./test.sh # Run unit tests 35 | - go build # Build 36 | 37 | after_success: 38 | - bash <(curl -s https://codecov.io/bash) 39 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.12 2 | 3 | WORKDIR /go/src/github.com/polaris-project/go-polaris 4 | COPY . . 5 | 6 | RUN go get -d -v ./... 7 | 8 | CMD go run main.go -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Polaris 2 | 3 | A distributed computations protocol for the next generation of the web. 4 | 5 | [![Godoc Reference](https://img.shields.io/badge/godoc-reference-%23516aa0.svg)](https://godoc.org/github.com/polaris-project/go-polaris) 6 | [![Go Report Card](https://goreportcard.com/badge/github.com/polaris-project/go-polaris)](https://goreportcard.com/report/github.com/polaris-project/go-polaris) 7 | [![Build Status](https://travis-ci.com/polaris-project/go-polaris.svg?branch=master)](https://travis-ci.com/polaris-project/go-polaris) 8 | [![Gluten Status](https://img.shields.io/badge/gluten-free-brightgreen.svg)](https://img.shields.io/badge/gluten-free-brightgreen.svg) 9 | 10 | ## Installation 11 | 12 | ### Binary 13 | 14 | ```zsh 15 | go install github.com/polaris-project/go-polaris 16 | ``` 17 | 18 | ### Source Code 19 | 20 | ```zsh 21 | go get -u github.com/polaris-project/go-polaris 22 | ``` 23 | 24 | ## Usage 25 | 26 | ### Joining the Testnet 27 | 28 | ```zsh 29 | go-polaris 30 | ``` 31 | 32 | ### Creating a Private Network 33 | 34 | Note: Before creating a private network, make sure to create a `data/config/config_network_name.json` file. 35 | 36 | ```zsh 37 | go-polaris --network your_network_name --bootstrap-address 38 | ``` 39 | -------------------------------------------------------------------------------- /accounts/account.go: -------------------------------------------------------------------------------- 1 | // Package accounts defines a set of ECDSA private-public keypair management utilities and helper methods. 2 | package accounts 3 | 4 | import ( 5 | "crypto/ecdsa" 6 | "crypto/elliptic" 7 | "crypto/rand" 8 | "math/big" 9 | 10 | "github.com/polaris-project/go-polaris/common" 11 | "github.com/polaris-project/go-polaris/crypto" 12 | ) 13 | 14 | // Account represents an ECDSA private-public keypair. 15 | // Only an account's x and y curve values are stored persistently. 16 | // ecdsa.PrivateKey and ecdsa.PublicKey references can be obtained at runtime via .PrivateKey() and .PublicKey(). 17 | type Account struct { 18 | X *big.Int `json:"x"` // X value 19 | Y *big.Int `json:"y"` // Y value 20 | D *big.Int `json:"d"` // D value 21 | } 22 | 23 | /* BEGIN EXPORTED METHODS */ 24 | 25 | // NewAccount generates a new ECDSA private-public keypair, returns the initialized account. 26 | // Does not write the new account to persistent memory on creation. 27 | func NewAccount() (*Account, error) { 28 | privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) // Generate private key 29 | if err != nil { // Check for errors 30 | return &Account{}, err // Return found error 31 | } 32 | 33 | return &Account{ 34 | privateKey.X, // Set X 35 | privateKey.Y, // Set Y 36 | privateKey.D, // Set D 37 | }, nil // Return initialized account 38 | } 39 | 40 | // AccountFromKey initializes a new account instance from a given ECDSA private key. 41 | func AccountFromKey(privateKey *ecdsa.PrivateKey) *Account { 42 | return &Account{ 43 | X: privateKey.X, // Set X 44 | Y: privateKey.Y, // Set Y 45 | D: privateKey.D, // Set D 46 | } // Return initialized account 47 | } 48 | 49 | // Address attempts to derive an address from the given account. 50 | func (account *Account) Address() *common.Address { 51 | return crypto.AddressFromPublicKey(account.PublicKey()) // Return address value 52 | } 53 | 54 | // PublicKey derives an ECDSA public key from the given account. 55 | func (account *Account) PublicKey() *ecdsa.PublicKey { 56 | return &ecdsa.PublicKey{ 57 | Curve: elliptic.P521(), // Set curve 58 | X: account.X, // Set X 59 | Y: account.Y, // Set Y 60 | } // Return public key 61 | } 62 | 63 | // PrivateKey derives an ECDSA private key from the given account. 64 | func (account *Account) PrivateKey() *ecdsa.PrivateKey { 65 | return &ecdsa.PrivateKey{ 66 | PublicKey: *account.PublicKey(), // Set public key 67 | D: account.D, // Set D 68 | } // Return private key 69 | } 70 | 71 | /* END EXPORTED METHODS */ 72 | -------------------------------------------------------------------------------- /accounts/account_io.go: -------------------------------------------------------------------------------- 1 | // Package accounts defines a set of ECDSA private-public keypair management utilities and helper methods. 2 | package accounts 3 | 4 | import ( 5 | "encoding/hex" 6 | "encoding/json" 7 | "fmt" 8 | "io/ioutil" 9 | "path/filepath" 10 | "strings" 11 | 12 | "github.com/polaris-project/go-polaris/common" 13 | "github.com/polaris-project/go-polaris/crypto" 14 | ) 15 | 16 | /* BEGIN EXPORTED METHODS */ 17 | 18 | // GetAllAccounts gets a list of all the owned accounts. 19 | func GetAllAccounts() []common.Address { 20 | buffer := []common.Address{} // Init buffer 21 | 22 | files, err := ioutil.ReadDir(common.KeystoreDir) // Walk keystore dir 23 | if err != nil { // Check for errors 24 | return []common.Address{} // Return nil 25 | } 26 | 27 | for _, file := range files { // Iterate through files 28 | addressBytes, _ := hex.DecodeString(strings.Split(strings.Split(file.Name(), "account_")[1], ".json")[0]) // Decode hex addr 29 | 30 | buffer = append(buffer, *common.NewAddress(addressBytes)) // Append address 31 | } 32 | 33 | return buffer // No error occurred, return success 34 | } 35 | 36 | // String marshals a given account's contents to a JSON-encoded string. 37 | func (account *Account) String() string { 38 | marshaledVal, _ := json.MarshalIndent(*account, "", " ") // Marshal JSON 39 | 40 | return string(marshaledVal) // Return JSON 41 | } 42 | 43 | // Bytes encodes a given account's contents to a JSON-encoded byte array. 44 | func (account *Account) Bytes() []byte { 45 | marshaledVal, _ := json.MarshalIndent(*account, "", " ") // Marshal JSON 46 | 47 | return marshaledVal // Return JSON 48 | } 49 | 50 | // WriteToMemory writes the given account's contents to persistent memory 51 | func (account *Account) WriteToMemory() error { 52 | err := common.CreateDirIfDoesNotExist(common.KeystoreDir) // Create keystore dir if necessary 53 | if err != nil { // Check for errors 54 | return err // Return found error 55 | } 56 | 57 | err = ioutil.WriteFile(filepath.FromSlash(fmt.Sprintf("%s/account_%s.json", common.KeystoreDir, hex.EncodeToString(crypto.AddressFromPublicKey(account.PublicKey()).Bytes()))), account.Bytes(), 0o644) // Write account to persistent memory 58 | 59 | if err != nil { // Check for errors 60 | return err // Return error 61 | } 62 | 63 | return nil // No error occurred, return nil 64 | } 65 | 66 | // ReadAccountFromMemory reads an account with a given address from persistent memory. 67 | func ReadAccountFromMemory(address *common.Address) (*Account, error) { 68 | data, err := ioutil.ReadFile(filepath.FromSlash(fmt.Sprintf("%s/account_%s.json", common.KeystoreDir, hex.EncodeToString(address.Bytes())))) // Read account 69 | if err != nil { // Check for errors 70 | return &Account{}, err // Return found error 71 | } 72 | 73 | buffer := &Account{} // Initialize buffer 74 | 75 | err = json.Unmarshal(data, buffer) // Deserialize JSON into buffer. 76 | 77 | if err != nil { // Check for errors 78 | return &Account{}, err // Return found error 79 | } 80 | 81 | return buffer, nil // No error occurred, return read account 82 | } 83 | 84 | /* END EXPORTED METHODS */ 85 | -------------------------------------------------------------------------------- /accounts/account_io_test.go: -------------------------------------------------------------------------------- 1 | // Package accounts defines a set of ECDSA private-public keypair management utilities and helper methods. 2 | package accounts 3 | 4 | import "testing" 5 | 6 | /* BEGIN EXPORTED METHODS */ 7 | 8 | // TestWriteToMemory tests the functionality of the WriteToMemory() helper method. 9 | func TestWriteToMemory(t *testing.T) { 10 | account, err := NewAccount() // Initialize new account 11 | if err != nil { // Check for errors 12 | t.Fatal(err) // Panic 13 | } 14 | 15 | err = account.WriteToMemory() // Write account to persistent memory 16 | 17 | if err != nil { // Check for errors 18 | t.Fatal(err) // panic 19 | } 20 | } 21 | 22 | // TestReadAccountFromMemory tests the functionality of the ReadAccountFromMemory() helper method. 23 | func TestReadAccountFromMemory(t *testing.T) { 24 | account, err := NewAccount() // Initialize new account 25 | if err != nil { // Check for errors 26 | t.Fatal(err) // Panic 27 | } 28 | 29 | err = account.WriteToMemory() // Write account to persistent memory 30 | 31 | if err != nil { // Check for errors 32 | t.Fatal(err) // panic 33 | } 34 | 35 | _, err = ReadAccountFromMemory(account.Address()) // Read account from memory 36 | 37 | if err != nil { // Check for errors 38 | t.Fatal(err) // Panic 39 | } 40 | } 41 | 42 | /* END EXPORTED METHODS */ 43 | -------------------------------------------------------------------------------- /accounts/account_test.go: -------------------------------------------------------------------------------- 1 | // Package accounts defines a set of ECDSA private-public keypair management utilities and helper methods. 2 | package accounts 3 | 4 | import ( 5 | "crypto/ecdsa" 6 | "crypto/elliptic" 7 | "crypto/rand" 8 | "testing" 9 | ) 10 | 11 | /* BEGIN EXPORTED METHODS TESTS */ 12 | 13 | // TestNewAccount tests the functionality of the NewAccount() helper method. 14 | func TestNewAccount(t *testing.T) { 15 | _, err := NewAccount() // Initialize new account 16 | if err != nil { // Check for errors 17 | t.Fatal(err) // Panic 18 | } 19 | } 20 | 21 | // TestAccountFromKey tests the functionality of the AccountFromKey() helper method. 22 | func TestAccountFromKey(t *testing.T) { 23 | privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) // Generate private key 24 | if err != nil { // Check for errors 25 | t.Fatal(err) // Panic 26 | } 27 | 28 | account := AccountFromKey(privateKey) // Initialize account from private key 29 | 30 | if account == nil { // Check for nil account 31 | t.Fatal("account should not be nil") // Panic 32 | } 33 | } 34 | 35 | /* END EXPORTED METHODS TESTS */ 36 | -------------------------------------------------------------------------------- /accounts/accounts.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; // Specify compiler version 2 | 3 | package accounts; 4 | 5 | service Accounts { 6 | rpc NewAccount(GeneralRequest) returns (GeneralResponse) {} // Generate a new ECDSA private-public keypair, returns the initialized account 7 | rpc GetAllAccounts(GeneralRequest) returns (GeneralResponse) {} // Log all accounts 8 | rpc AccountFromKey(GeneralRequest) returns (GeneralResponse) {} // Import account with given private key 9 | rpc Address(GeneralRequest) returns (GeneralResponse) {} // Log account address 10 | rpc PublicKey(GeneralRequest) returns (GeneralResponse) {} // Log account public key 11 | rpc PrivateKey(GeneralRequest) returns (GeneralResponse) {} // Log account private key 12 | rpc String(GeneralRequest) returns (GeneralResponse) {} // Log account contents 13 | } 14 | 15 | /* BEGIN REQUESTS */ 16 | 17 | message GeneralRequest { 18 | string privatePublicKey = 1; // Private/public key 19 | } 20 | 21 | /* END REQUESTS */ 22 | 23 | /* BEGIN RESPONSES */ 24 | 25 | message GeneralResponse { 26 | string message = 1; // Response 27 | } 28 | 29 | /* END REPSONSES */ -------------------------------------------------------------------------------- /api/api.go: -------------------------------------------------------------------------------- 1 | // Package api contains all rpc and rest-related api helper methods, structs, etc... 2 | package api 3 | 4 | // API defines a standardized API spec, that of which can be implemented via REST, RPC, etc... 5 | type API interface { 6 | GetAPIProtocol() string // Get API protocol (e.g. REST_HTTP, RPC, etc...) 7 | 8 | GetAPIURI() string // Get API uri (e.g. https://localhost:8080/) 9 | 10 | GetSupportedFormats() []string // Get supported formats 11 | 12 | GetIsServing() bool // Check is serving 13 | 14 | StartServingAPI() error // Start serving API 15 | } 16 | -------------------------------------------------------------------------------- /api/rpc_api.go: -------------------------------------------------------------------------------- 1 | // Package api contains all rpc and rest-related api helper methods, structs, etc... 2 | package api 3 | 4 | import ( 5 | "context" 6 | "fmt" 7 | "net/http" 8 | "path/filepath" 9 | 10 | "github.com/polaris-project/go-polaris/common" 11 | accountsProto "github.com/polaris-project/go-polaris/internal/proto/accounts" 12 | configProto "github.com/polaris-project/go-polaris/internal/proto/config" 13 | cryptoProto "github.com/polaris-project/go-polaris/internal/proto/crypto" 14 | dagProto "github.com/polaris-project/go-polaris/internal/proto/dag" 15 | transactionProto "github.com/polaris-project/go-polaris/internal/proto/transaction" 16 | accountsServer "github.com/polaris-project/go-polaris/internal/rpc/accounts" 17 | configServer "github.com/polaris-project/go-polaris/internal/rpc/config" 18 | cryptoServer "github.com/polaris-project/go-polaris/internal/rpc/crypto" 19 | dagServer "github.com/polaris-project/go-polaris/internal/rpc/dag" 20 | transactionServer "github.com/polaris-project/go-polaris/internal/rpc/transaction" 21 | ) 22 | 23 | // RPCAPI represents an RPC API. 24 | type RPCAPI struct { 25 | Network string `json:"network"` // API network 26 | 27 | SupportedProtocols []string `json:"protocols"` // API protocols 28 | 29 | URI string `json:"uri"` // API URI 30 | 31 | Server *http.Server `json:"server"` // Working server 32 | } 33 | 34 | /* BEGIN EXPORTED METHODS */ 35 | 36 | // NewRPCAPI initializes a new RPCAPI instance. 37 | func NewRPCAPI(network, uri string) (*RPCAPI, error) { 38 | err := generateCert("rpc", []string{"localhost", "127.0.0.1"}) // Generate tls certs 39 | if err != nil { // Check for errors 40 | return nil, err // Return found error 41 | } 42 | 43 | return &RPCAPI{ 44 | Network: network, // Set network 45 | URI: uri, // Set URI 46 | }, nil // Return initialized API 47 | } 48 | 49 | // NewRPCAPINoTLS initializes a new RPCAPI instance without enabling TLS. 50 | func NewRPCAPINoTLS(network, uri string) *RPCAPI { 51 | return &RPCAPI{ 52 | Network: network, // Set network 53 | URI: uri, // Set URI 54 | } // Return initialized API 55 | } 56 | 57 | // GetAPIProtocol gets the working rpc api protocol. 58 | func (rpcAPI *RPCAPI) GetAPIProtocol() string { 59 | return "RPC" // Return protocol 60 | } 61 | 62 | // GetAPIURI gets the current rpc api URI. 63 | func (rpcAPI *RPCAPI) GetAPIURI() string { 64 | return rpcAPI.URI // Return URI 65 | } 66 | 67 | // GetSupportedFormats gets the formats supported by the current rpc api. 68 | func (rpcAPI *RPCAPI) GetSupportedFormats() []string { 69 | return []string{"protobuf"} // Return format 70 | } 71 | 72 | // GetIsServing returns whether or not the api is currently serving. 73 | func (rpcAPI *RPCAPI) GetIsServing() bool { 74 | return rpcAPI.Server != nil // Check is serving 75 | } 76 | 77 | // StartServing starts serving the API. 78 | func (rpcAPI *RPCAPI) StartServing(ctx context.Context) error { 79 | err := generateCert("rpc", []string{"localhost"}) // Generate cert 80 | if err != nil { // Check for errors 81 | return err // Return found error 82 | } 83 | 84 | configHandler := configProto.NewConfigServer(&configServer.Server{}, nil) // Get handler 85 | cryptoHandler := cryptoProto.NewCryptoServer(&cryptoServer.Server{}, nil) // Get handler 86 | transactionHandler := transactionProto.NewTransactionServer(&transactionServer.Server{}, nil) // Get handler 87 | accountsHandler := accountsProto.NewAccountsServer(&accountsServer.Server{}, nil) // Get handler 88 | dagHandler := dagProto.NewDagServer(&dagServer.Server{}, nil) // Get handler 89 | 90 | mux := http.NewServeMux() // Init mux 91 | 92 | mux.Handle(configProto.ConfigPathPrefix, configHandler) // Set route handler 93 | mux.Handle(cryptoProto.CryptoPathPrefix, cryptoHandler) // Set route handler 94 | mux.Handle(transactionProto.TransactionPathPrefix, transactionHandler) // Set route handler 95 | mux.Handle(accountsProto.AccountsPathPrefix, accountsHandler) // Set route handler 96 | mux.Handle(dagProto.DagPathPrefix, dagHandler) // Set route handler 97 | 98 | return http.ListenAndServeTLS(rpcAPI.URI, filepath.FromSlash(fmt.Sprintf("%s/rpcCert.pem", common.CertificatesDir)), filepath.FromSlash(fmt.Sprintf("%s/rpcKey.pem", common.CertificatesDir)), mux) // Start serving 99 | } 100 | 101 | /* END EXPORTED METHODS */ 102 | -------------------------------------------------------------------------------- /api/ssl.go: -------------------------------------------------------------------------------- 1 | // Package api contains all rpc and rest-related api helper methods, structs, etc... 2 | package api 3 | 4 | import ( 5 | "crypto/ecdsa" 6 | "crypto/elliptic" 7 | "crypto/rand" 8 | "crypto/x509" 9 | "crypto/x509/pkix" 10 | "encoding/pem" 11 | "fmt" 12 | "io/ioutil" 13 | "math/big" 14 | "os" 15 | "path/filepath" 16 | "time" 17 | 18 | "github.com/polaris-project/go-polaris/common" 19 | ) 20 | 21 | /* BEGIN INTERNAL METHODS */ 22 | 23 | // generateCert generates an ssl cert. 24 | func generateCert(certName string, hosts []string) error { 25 | os.Remove(fmt.Sprintf("%sKey.pem", certName)) // Remove existent key 26 | os.Remove(fmt.Sprintf("%sCert.pem", certName)) // Remove existent cert 27 | 28 | privateKey, err := generateTLSKey(certName) // Generate key 29 | if err != nil { // Check for errors 30 | return err // Return found error 31 | } 32 | 33 | err = generateTLSCert(privateKey, certName, hosts) // Generate cert 34 | 35 | if err != nil { // Check for errors 36 | return err // Return found error 37 | } 38 | 39 | return nil // No error occurred, return nil 40 | } 41 | 42 | // generateTLSKey generates necessary TLS keys. 43 | func generateTLSKey(keyName string) (*ecdsa.PrivateKey, error) { 44 | err := common.CreateDirIfDoesNotExist(common.CertificatesDir) // Create certs dir if does not exist 45 | if err != nil { // Check for errors 46 | return &ecdsa.PrivateKey{}, err // Return found error 47 | } 48 | 49 | privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) // Generate private key 50 | if err != nil { // Check for errors 51 | return &ecdsa.PrivateKey{}, err // Return found error 52 | } 53 | 54 | marshaledPrivateKey, err := x509.MarshalECPrivateKey(privateKey) // Marshal private key 55 | if err != nil { // Check for errors 56 | return &ecdsa.PrivateKey{}, err // Return found error 57 | } 58 | 59 | pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: marshaledPrivateKey}) // Encode to memory 60 | 61 | err = ioutil.WriteFile(filepath.FromSlash(fmt.Sprintf("%s/%sKey.pem", common.CertificatesDir, keyName)), pemEncoded, 0o644) // Write pem 62 | 63 | if err != nil { // Check for errors 64 | return &ecdsa.PrivateKey{}, err // Return found error 65 | } 66 | 67 | return privateKey, nil // No error occurred, return nil 68 | } 69 | 70 | // generateTLSCert generates necessary TLS certs. 71 | func generateTLSCert(privateKey *ecdsa.PrivateKey, certName string, hosts []string) error { 72 | err := common.CreateDirIfDoesNotExist(common.CertificatesDir) // Create certs dir if does not exist 73 | if err != nil { // Check for errors 74 | return err // Return found error 75 | } 76 | 77 | notBefore := time.Now() // Fetch current time 78 | 79 | notAfter := notBefore.Add(2 * 24 * time.Hour) // Fetch 'deadline' 80 | 81 | serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) // Init limit 82 | serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) // Init serial number 83 | if err != nil { // Check for errors 84 | return err // Return found error 85 | } 86 | 87 | template := x509.Certificate{ // Init template 88 | SerialNumber: serialNumber, // Generate w/serial number 89 | Subject: pkix.Name{ // Generate w/subject 90 | Organization: hosts, // Generate w/org 91 | }, 92 | NotBefore: notBefore, // Generate w/not before 93 | NotAfter: notAfter, // Generate w/not after 94 | 95 | KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, // Generate w/key usage 96 | ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, // Generate w/ext key 97 | BasicConstraintsValid: true, // Generate w/basic constraints 98 | IsCA: true, // Force is CA 99 | } 100 | 101 | cert, err := x509.CreateCertificate(rand.Reader, &template, &template, &privateKey.PublicKey, privateKey) // Generate certificate 102 | if err != nil { // Check for errors 103 | return err // Return found error 104 | } 105 | 106 | pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: cert}) // Encode pem 107 | 108 | err = ioutil.WriteFile(filepath.FromSlash(fmt.Sprintf("%s/%sCert.pem", common.CertificatesDir, certName)), pemEncoded, 0o644) // Write cert file 109 | 110 | if err != nil { // Check for errors 111 | return err // Return found error 112 | } 113 | 114 | return nil // No error occurred, return nil 115 | } 116 | 117 | // keyToFile writes a given key to a pem-encoded file. 118 | func keyToFile(filename string, key *ecdsa.PrivateKey) error { 119 | err := common.CreateDirIfDoesNotExist(common.CertificatesDir) // Create cert dir if doesn't already exist 120 | if err != nil { // Check for errors 121 | return err // Return found error 122 | } 123 | 124 | file, err := os.Create(filepath.FromSlash(fmt.Sprintf("%s/%s", common.CertificatesDir, filename))) // Create key file 125 | if err != nil { // Check for errors 126 | return err // Return found error 127 | } 128 | 129 | b, err := x509.MarshalECPrivateKey(key) // Marshal private key 130 | if err != nil { // Check for errors 131 | file.Close() // Close file 132 | 133 | return err // Return found error 134 | } 135 | 136 | if err := pem.Encode(file, &pem.Block{Type: "EC PRIVATE KEY", Bytes: b}); err != nil { // Encode 137 | file.Close() // Close file 138 | 139 | return err // Return found error 140 | } 141 | 142 | return file.Close() // Close file 143 | } 144 | 145 | // certToFile writes a given certificate to a file. 146 | func certToFile(filename string, derBytes []byte) error { 147 | err := common.CreateDirIfDoesNotExist(common.CertificatesDir) // Create cert dir if doesn't already exist 148 | if err != nil { // Check for errors 149 | return err // Return found error 150 | } 151 | 152 | certOut, err := os.Create(filepath.FromSlash(fmt.Sprintf("%s/%s", common.CertificatesDir, filename))) // Create file 153 | if err != nil { 154 | return err // Return found error 155 | } 156 | 157 | if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil { 158 | certOut.Close() // Close cert file 159 | 160 | return err // Return found error 161 | } 162 | 163 | return certOut.Close() // Close cert file 164 | } 165 | 166 | /* END INTERNAL METHODS */ 167 | -------------------------------------------------------------------------------- /common/common_cli.go: -------------------------------------------------------------------------------- 1 | // Package common defines a set of commonly used helper methods and data types. 2 | package common 3 | 4 | import ( 5 | "errors" 6 | "strings" 7 | ) 8 | 9 | // ErrNilInput is an error definition describing input of 0 char length. 10 | var ErrNilInput = errors.New("nil input") 11 | 12 | /* BEGIN EXPORTED METHODS */ 13 | 14 | // ParseStringMethodCall attempts to parse string as method call, returning receiver, method name and params. 15 | func ParseStringMethodCall(input string) (string, string, []string, error) { 16 | if input == "" { // Check for errors 17 | return "", "", []string{}, ErrNilInput // Return found error 18 | } else if !strings.Contains(input, "(") || !strings.Contains(input, ")") { 19 | input = input + "()" // Fetch receiver methods 20 | } 21 | 22 | if !strings.Contains(input, ".") { // Check for nil receiver 23 | return "", "", []string{}, errors.New("invalid method " + input) // Return found error 24 | } 25 | 26 | method := strings.Split(strings.Split(input, "(")[0], ".")[1] // Fetch method 27 | 28 | receiver := StringFetchCallReceiver(input) // Fetch receiver 29 | 30 | params := []string{} // Init buffer 31 | 32 | if strings.Contains(input, ",") || !strings.Contains(input, "()") { // Check for nil params 33 | params, _ = ParseStringParams(input) // Fetch params 34 | } 35 | 36 | return receiver, method, params, nil // No error occurred, return parsed method+params 37 | } 38 | 39 | // ParseStringParams attempts to fetch string parameters from (..., ..., ...) style call. 40 | func ParseStringParams(input string) ([]string, error) { 41 | if input == "" { // Check for errors 42 | return []string{}, ErrNilInput // Return found error 43 | } 44 | 45 | parenthesesStripped := StringStripReceiverCall(input) // Strip parentheses 46 | 47 | params := strings.Split(parenthesesStripped, ", ") // Split by ', ' 48 | 49 | return params, nil // No error occurred, return split params 50 | } 51 | 52 | // StringStripReceiverCall strips receiver from string method call. 53 | func StringStripReceiverCall(input string) string { 54 | openParenthIndex := strings.Index(input, "(") // Get open parent index 55 | closeParenthIndex := strings.LastIndex(input, ")") // Get close parent index 56 | 57 | return input[openParenthIndex+1 : closeParenthIndex] // Strip receiver 58 | } 59 | 60 | // StringFetchCallReceiver attempts to fetch receiver from string, as if it were an x.y(..., ..., ...) style method call. 61 | func StringFetchCallReceiver(input string) string { 62 | return strings.Split(strings.Split(input, "(")[0], ".")[0] // Return split string 63 | } 64 | 65 | /* END EXPORTED METHODS */ 66 | -------------------------------------------------------------------------------- /common/common_io.go: -------------------------------------------------------------------------------- 1 | // Package common defines a set of commonly used helper methods and data types. 2 | package common 3 | 4 | import ( 5 | "fmt" 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | var ( 11 | // DataDir is the global data directory definition. 12 | DataDir = getDataDir() 13 | 14 | // ConfigDir is the global configuration directory definition. 15 | ConfigDir = filepath.FromSlash(fmt.Sprintf("%s/config", DataDir)) 16 | 17 | // DbDir is the global database directory definition. 18 | DbDir = filepath.FromSlash(fmt.Sprintf("%s/db", DataDir)) 19 | 20 | // PeerIdentityDir is the global p2p identity directory definition. 21 | PeerIdentityDir = filepath.FromSlash(fmt.Sprintf("%s/p2p", DataDir)) 22 | 23 | // LogsDir is the global logs directory definition. 24 | LogsDir = filepath.FromSlash(fmt.Sprintf("%s/logs", DataDir)) 25 | 26 | // CertificatesDir is the global certificate directory definition. 27 | CertificatesDir = filepath.FromSlash(fmt.Sprintf("%s/certs", DataDir)) 28 | 29 | // MempoolDir is the global mempool directory definition. 30 | // The mempool is used to store cached transactions that have not been added to the public dag. 31 | MempoolDir = filepath.FromSlash(fmt.Sprintf("%s/mempool", DataDir)) 32 | 33 | // KeystoreDir is the global keystore directory definition. 34 | KeystoreDir = filepath.FromSlash(fmt.Sprintf("%s/keystore", DataDir)) 35 | ) 36 | 37 | /* BEGIN EXPORTED METHODS */ 38 | 39 | // CreateDirIfDoesNotExist creates a given directory if it does not already exist. 40 | func CreateDirIfDoesNotExist(dir string) error { 41 | safeDir := filepath.FromSlash(dir) // Just to be safe 42 | 43 | if _, err := os.Stat(safeDir); os.IsNotExist(err) { // Check dir exists 44 | err = os.MkdirAll(safeDir, 0o755) // Create directory 45 | 46 | if err != nil { // Check for errors 47 | return err // Return error 48 | } 49 | } 50 | 51 | return nil // No error occurred 52 | } 53 | 54 | /* END EXPORTED METHODS */ 55 | 56 | /* BEGIN INTERNAL METHODS */ 57 | 58 | // getDataDir fetches the data directory 59 | func getDataDir() string { 60 | abs, _ := filepath.Abs("./data") // Get absolute dir 61 | 62 | return filepath.FromSlash(abs) // Match OS slashes 63 | } 64 | 65 | /* END INTERNAL METHODS */ 66 | -------------------------------------------------------------------------------- /common/common_io_test.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import "testing" 4 | 5 | /* BEGIN EXPORTED METHODS TESTS */ 6 | 7 | // TestCreateDirIfDoesNotExist tests the functionality of the CreateDirIfDoesNotExist() helper method. 8 | func TestCreateDirIfDoesNotExist(t *testing.T) { 9 | err := CreateDirIfDoesNotExist(DataDir) // Create data dir (just as an example) 10 | if err != nil { // Check for errors 11 | t.Fatal(err) // Panic 12 | } 13 | } 14 | 15 | /* END EXPORTED METHODS TESTS */ 16 | 17 | /* BEGIN INTERNAL METHODS TESTS */ 18 | 19 | // TestGetDataDir tests the functionality of the getDataDir() helper method. 20 | func TestGetDataDir(t *testing.T) { 21 | t.Log(getDataDir()) // Log data dir 22 | } 23 | 24 | /* END INTERNAL METHODS TESTS */ 25 | -------------------------------------------------------------------------------- /common/common_types.go: -------------------------------------------------------------------------------- 1 | // Package common defines a set of commonly used helper methods and data types. 2 | package common 3 | 4 | const ( 5 | // HashLength is the standardized length of a hash 6 | HashLength = 32 7 | 8 | // AddressLength is the standardized length of an address 9 | AddressLength = 20 10 | ) 11 | 12 | // Hash represents the 32 byte output of sha3(). 13 | type Hash [HashLength]byte 14 | 15 | // Address represents a 20 byte, hex-encoded ECDSA public key. 16 | type Address [AddressLength]byte 17 | 18 | /* BEGIN EXPORTED METHODS */ 19 | 20 | /* 21 | BEGIN HASH METHODS 22 | */ 23 | 24 | // NewHash converts a given hash, b, to a 32-byte mem-prefix-compliant hash. 25 | func NewHash(b []byte) Hash { 26 | var hash Hash // Hash 27 | 28 | bCropped := b // Init cropped buffer 29 | 30 | if len(b) > len(hash) { // Check crop side 31 | bCropped = bCropped[len(bCropped)-HashLength:] // Crop 32 | } 33 | 34 | copy(hash[HashLength-len(bCropped):], bCropped) // Copy source 35 | 36 | return hash // Return hash value 37 | } 38 | 39 | // IsNil checks if a given hash is nil. 40 | func (hash Hash) IsNil() bool { 41 | nilBytes := 0 // Init nil bytes buffer 42 | 43 | for _, byteVal := range hash[:] { // Iterate through hash 44 | if byteVal == 0 { // Check nil byte 45 | nilBytes++ // Increment nil bytes 46 | } 47 | } 48 | 49 | return nilBytes == HashLength 50 | } 51 | 52 | // Bytes converts a given hash to a byte array. 53 | func (hash Hash) Bytes() []byte { 54 | return hash[:] // Return byte array value 55 | } 56 | 57 | /* 58 | END HASH METHODS 59 | */ 60 | 61 | /* 62 | BEGIN ADDRESS METHODS 63 | */ 64 | 65 | // NewAddress formats a given byte array to an address. 66 | func NewAddress(b []byte) *Address { 67 | var address Address // Initialize address buffer 68 | 69 | bCropped := b // Init cropped buffer 70 | 71 | if len(b) > len(address) { // Check crop side 72 | bCropped = bCropped[len(bCropped)-AddressLength:] // Crop 73 | } 74 | 75 | copy(address[AddressLength-len(bCropped):], bCropped) // Copy source 76 | 77 | return &address // Return address 78 | } 79 | 80 | // Bytes converts a given address to a byte array. 81 | func (address *Address) Bytes() []byte { 82 | if address != nil { 83 | return (*address)[:] // Return byte array value 84 | } 85 | 86 | return nil // No address at pointer 87 | } 88 | 89 | /* 90 | END ADDRESS METHODS 91 | */ 92 | 93 | /* END EXPORTED METHODS */ 94 | -------------------------------------------------------------------------------- /common/common_types_test.go: -------------------------------------------------------------------------------- 1 | // Package common defines a set of commonly used helper methods and data types. 2 | package common 3 | 4 | import ( 5 | "testing" 6 | ) 7 | 8 | /* BEGIN EXPORTED METHODS TESTS */ 9 | 10 | // TestNewHash tests the functionality of the NewHash() helper method. 11 | func TestNewHash(t *testing.T) { 12 | b := []byte("36f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80") // Hash test 13 | 14 | t.Log(NewHash(b)) // Log hash value 15 | } 16 | 17 | // TestIsNil tests the functionality of the IsNil() helper method. 18 | func TestIsNil(t *testing.T) { 19 | hash := NewHash([]byte("36f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80")) // Hash test 20 | nilHash := NewHash([]byte("")) // Hash nil 21 | 22 | if hash.IsNil() == true { // Check invalid determination 23 | t.Fatal("invalid determination: hash isn't nil") // Panic 24 | } 25 | 26 | if nilHash.IsNil() == false { // Check invalid determination 27 | t.Fatal("invalid determination: hash should be nil") // Panic 28 | } 29 | } 30 | 31 | // TestNewAddress tests the functionality of the NewAddress() helper method. 32 | func TestNewAddress(t *testing.T) { 33 | address := NewAddress([]byte("99994467913f1743a5b2ca672fcfb4b7dd268d3f5d36f5e61079c8a2706c9112")) // Create new address 34 | 35 | t.Log(address) // Log address 36 | } 37 | 38 | /* END EXPORTED METHODS TESTS */ 39 | -------------------------------------------------------------------------------- /config/config.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; // Specify compiler version 2 | 3 | package config; 4 | 5 | service Config { 6 | rpc NewDagConfig(GeneralRequest) returns (GeneralResponse) {} // Create new config from genesis.json file 7 | rpc GetAllConfigs(GeneralRequest) returns (GeneralResponse) {} // Walk config dir 8 | rpc GetConfig(GeneralRequest) returns (GeneralResponse) {} // Log contents of config with network name 9 | } 10 | 11 | /* BEGIN REQUESTS */ 12 | 13 | message GeneralRequest { 14 | string filePath = 1; // File path 15 | 16 | string network = 2; // Network (e.g. "main_net") 17 | } 18 | 19 | /* END REQUESTS */ 20 | 21 | /* BEGIN RESPONSES */ 22 | 23 | message GeneralResponse { 24 | string message = 1; // Response 25 | } 26 | 27 | /* END REPSONSES */ -------------------------------------------------------------------------------- /config/dag_config.go: -------------------------------------------------------------------------------- 1 | // Package config provides DAG configuration helper methods and structs. 2 | // Most notably, config provides the DagConfig struct, that of which is used to specify 3 | // supply allocations, the dag identifier, and other metadata. 4 | package config 5 | 6 | import ( 7 | "encoding/json" 8 | "io/ioutil" 9 | ) 10 | 11 | // DagConfigRequest represents the global dag config request message byte value. 12 | var DagConfigRequest = []byte("dag_config_req") 13 | 14 | // DagConfig represents a DAG configuration. 15 | type DagConfig struct { 16 | Alloc map[string]float64 `json:"alloc"` // Account balances at genesis 17 | 18 | Identifier string `json:"identifier"` // Dag/network name (e.g. "mainnet_beta", "mainnet_alpha") 19 | 20 | Network uint64 `json:"network"` // Dag version (e.g. 0 => mainnet, 1 => testnet, etc...) 21 | } 22 | 23 | /* BEGIN EXPORTED METHODS */ 24 | 25 | // NewDagConfig initializes a new DagConfig from a given set of parameters. 26 | func NewDagConfig(alloc map[string]float64, identifier string, network uint64) *DagConfig { 27 | return &DagConfig{ 28 | Alloc: alloc, // Set alloc 29 | Identifier: identifier, // Set identifier 30 | Network: network, // Set network 31 | } // Return initialized dag config 32 | } 33 | 34 | // NewDagConfigFromGenesis generates a new DagConfig from the given genesis.json file. 35 | func NewDagConfigFromGenesis(genesisFilePath string) (*DagConfig, error) { 36 | rawJSON, err := ioutil.ReadFile(genesisFilePath) // Read genesis file 37 | if err != nil { // Check for errors 38 | return &DagConfig{}, err // Return found error 39 | } 40 | 41 | var readJSON map[string]interface{} // Init buffer 42 | 43 | err = json.Unmarshal(rawJSON, &readJSON) // Unmarshal to buffer 44 | 45 | if err != nil { // Check for errors 46 | return &DagConfig{}, err // Return found error 47 | } 48 | 49 | alloc := make(map[string]float64) // Init alloc map 50 | 51 | for key, value := range readJSON["alloc"].(map[string]interface{}) { // Iterate through genesis addresses 52 | alloc[key] = value.(float64) // Set alloc for address 53 | } 54 | 55 | return &DagConfig{ 56 | Network: uint64(readJSON["network"].(float64)), // Set network 57 | Identifier: readJSON["identifier"].(string), // Set ID 58 | Alloc: alloc, // Set supply allocation 59 | }, nil 60 | } 61 | 62 | /* END EXPORTED METHODS */ 63 | -------------------------------------------------------------------------------- /config/dag_config_io.go: -------------------------------------------------------------------------------- 1 | // Package config provides DAG configuration helper methods and structs. 2 | // Most notably, config provides the DagConfig struct, that of which is used to specify 3 | // supply allocations, the dag identifier, and other metadata. 4 | package config 5 | 6 | import ( 7 | "encoding/json" 8 | "errors" 9 | "fmt" 10 | "io/ioutil" 11 | "path/filepath" 12 | 13 | "github.com/polaris-project/go-polaris/common" 14 | ) 15 | 16 | // ErrCouldNotDeserializeConfig represents an invalidly serialized dag config--that of which cannot be correctly deserialized. 17 | var ErrCouldNotDeserializeConfig = errors.New("could not deserialize dag config") 18 | 19 | /* BEGIN EXPORTED METHODS */ 20 | 21 | // String serializes a given dag config to a string via json. 22 | func (dagConfig *DagConfig) String() string { 23 | marshaledVal, _ := json.MarshalIndent(*dagConfig, "", " ") // Marshal JSON 24 | 25 | return string(marshaledVal) // Return marshalled JSON as a string 26 | } 27 | 28 | // Bytes serializes a given dag config to a byte array via json. 29 | func (dagConfig *DagConfig) Bytes() []byte { 30 | marshaledVal, _ := json.MarshalIndent(*dagConfig, "", " ") // Marshal JSON 31 | 32 | return marshaledVal // Return marshalled JSON 33 | } 34 | 35 | // DagConfigFromBytes deserializes a dag config from the given byte array b. 36 | func DagConfigFromBytes(b []byte) *DagConfig { 37 | buffer := &DagConfig{} // Init buffer 38 | 39 | err := json.Unmarshal(b, buffer) // Unmarshal into buffer 40 | if err != nil { // Check for errors 41 | return &DagConfig{} // Return nil dag config 42 | } 43 | 44 | return buffer // Return deserialized config 45 | } 46 | 47 | // WriteToMemory writes the given dag config to persistent memory. 48 | func (dagConfig *DagConfig) WriteToMemory() error { 49 | err := common.CreateDirIfDoesNotExist(common.ConfigDir) // Create config dir if necessary 50 | if err != nil { // Check for errors 51 | return err // Return found error 52 | } 53 | 54 | err = ioutil.WriteFile(filepath.FromSlash(fmt.Sprintf("%s/config_%s.json", common.ConfigDir, dagConfig.Identifier)), dagConfig.Bytes(), 0o644) // Write dag config to persistent memory 55 | 56 | if err != nil { // Check for errors 57 | return err // Return error 58 | } 59 | 60 | return nil // No error occurred, return nil 61 | } 62 | 63 | // ReadDagConfigFromMemory reads a dag config with the given identifier from persistent memory. 64 | func ReadDagConfigFromMemory(identifier string) (*DagConfig, error) { 65 | data, err := ioutil.ReadFile(filepath.FromSlash(fmt.Sprintf("%s/config_%s.json", common.ConfigDir, identifier))) // Read file 66 | if err != nil { // Check for errors 67 | return &DagConfig{}, err // Return found error 68 | } 69 | 70 | buffer := &DagConfig{} // Initialize buffer 71 | 72 | err = json.Unmarshal(data, buffer) // Deserialize JSON into buffer. 73 | 74 | if err != nil { // Check for errors 75 | return &DagConfig{}, err // Return found error 76 | } 77 | 78 | return buffer, nil // No error occurred, return read dag config 79 | } 80 | 81 | /* END EXPORTED METHODS */ 82 | -------------------------------------------------------------------------------- /config/dag_config_io_test.go: -------------------------------------------------------------------------------- 1 | // Package config provides DAG configuration helper methods and structs. 2 | // Most notably, config provides the DagConfig struct, that of which is used to specify 3 | // supply allocations, the dag identifier, and other metadata. 4 | package config 5 | 6 | import ( 7 | "bytes" 8 | "testing" 9 | ) 10 | 11 | /* BEGIN EXPORTED METHODS TESTS */ 12 | 13 | // TestString tests the functionality of the dag config string() helper method. 14 | func TestString(t *testing.T) { 15 | dagConfig, err := NewDagConfigFromGenesis("test_genesis.json") // Initialize new dag config with test genesis file. 16 | if err != nil { // Check for errors 17 | t.Fatal(err) // Panic 18 | } 19 | 20 | if dagConfig.String() == "" { // Check nil string 21 | t.Fatal("dag config string value should not be nil") // Panic 22 | } 23 | 24 | t.Log(dagConfig.String()) // Log success 25 | } 26 | 27 | // TestBytes tests the functionality fo the dag config bytes() helper method. 28 | func TestBytes(t *testing.T) { 29 | dagConfig, err := NewDagConfigFromGenesis("test_genesis.json") // Initialize new dag config with test genesis file. 30 | if err != nil { // Check for errors 31 | t.Fatal(err) // Panic 32 | } 33 | 34 | if dagConfig.Bytes() == nil { // Check nil byte val 35 | t.Fatal("dag config bytes value should not be nil") // Panic 36 | } 37 | } 38 | 39 | // TestDagConfigFromBytes tests the functionality of the dag config FromBytes() helper method. 40 | func TestDagConfigFromBytes(t *testing.T) { 41 | dagConfig, err := NewDagConfigFromGenesis("test_genesis.json") // Initialize new dag config with test genesis file. 42 | if err != nil { // Check for errors 43 | t.Fatal(err) // Panic 44 | } 45 | 46 | deserializedDagConfig := DagConfigFromBytes(dagConfig.Bytes()) // Deserialize 47 | 48 | if !bytes.Equal(deserializedDagConfig.Bytes(), dagConfig.Bytes()) { // Check dag configs equivalent 49 | t.Fatal("invalid deserialized dag config") // Panic 50 | } 51 | } 52 | 53 | // TestWriteToMemory tests the functionality of outbound dag config I/O. 54 | func TestWriteToMemory(t *testing.T) { 55 | dagConfig, err := NewDagConfigFromGenesis("test_genesis.json") // Initialize new dag config with test genesis file. 56 | if err != nil { // Check for errors 57 | t.Fatal(err) // Panic 58 | } 59 | 60 | err = dagConfig.WriteToMemory() // Write dag config to persistent memory 61 | 62 | if err != nil { // Check for errors 63 | t.Fatal(err) // Panic 64 | } 65 | } 66 | 67 | // TestReadDagConfigFromMemory tests the functionality of inbound dag config I/O. 68 | func TestReadDagConfigFromMemory(t *testing.T) { 69 | dagConfig, err := NewDagConfigFromGenesis("test_genesis.json") // Initialize new dag config with test genesis file. 70 | if err != nil { // Check for errors 71 | t.Fatal(err) // Panic 72 | } 73 | 74 | err = dagConfig.WriteToMemory() // Write dag config to persistent memory 75 | 76 | if err != nil { // Check for errors 77 | t.Fatal(err) // Panic 78 | } 79 | 80 | readDagConfig, err := ReadDagConfigFromMemory(dagConfig.Identifier) // Read dag config 81 | if err != nil { // Check for errors 82 | t.Fatal(err) // Panic 83 | } 84 | 85 | if !bytes.Equal(dagConfig.Bytes(), readDagConfig.Bytes()) { // Check dag configs not equivalent 86 | t.Fatal("dag configs should be equivalent") // Panic 87 | } 88 | } 89 | 90 | /* END EXPORTED METHODS TESTS */ 91 | -------------------------------------------------------------------------------- /config/dag_config_test.go: -------------------------------------------------------------------------------- 1 | // Package config provides DAG configuration helper methods and structs. 2 | // Most notably, config provides the DagConfig struct, that of which is used to specify 3 | // supply allocations, the dag identifier, and other metadata. 4 | package config 5 | 6 | import "testing" 7 | 8 | /* BEGIN EXPORTED METHODS TESTS */ 9 | 10 | // TestNewDagConfig tests the functionality of the NewDagConfigFromGenesis() helper method. 11 | func TestNewDagConfig(t *testing.T) { 12 | dagConfig := NewDagConfig(nil, "test_dag_config", 1) // Initialize new dag config. 13 | 14 | t.Log(dagConfig) // Log success 15 | } 16 | 17 | // TestNewDagConfig tests the functionality of the NewDagConfigFromGenesis() helper method. 18 | func TestNewDagConfigFromGenesis(t *testing.T) { 19 | dagConfig, err := NewDagConfigFromGenesis("test_genesis.json") // Initialize new dag config with test genesis file. 20 | if err != nil { // Check for errors 21 | t.Fatal(err) // Panic 22 | } 23 | 24 | t.Log(dagConfig) // Log success 25 | } 26 | 27 | /* END EXPORTED METHODS TESTS */ 28 | -------------------------------------------------------------------------------- /config/test_genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "network": 0, 3 | "identifier": "test_genesis_network", 4 | "alloc": { 5 | "0x040028d536d5351e83fbbec320c194629ace": 1000000000000000000 6 | } 7 | } -------------------------------------------------------------------------------- /crypto/address.go: -------------------------------------------------------------------------------- 1 | // Package crypto provides cryptography helper methods. 2 | package crypto 3 | 4 | import ( 5 | "crypto/ecdsa" 6 | "crypto/elliptic" 7 | 8 | "github.com/polaris-project/go-polaris/common" 9 | ) 10 | 11 | /* BEGIN EXPORTED METHODS */ 12 | 13 | // AddressFromPrivateKey serializes and converts an ecdsa private key into an address (uses private key pub). 14 | func AddressFromPrivateKey(privateKey *ecdsa.PrivateKey) *common.Address { 15 | return AddressFromPublicKey(&privateKey.PublicKey) // Return address 16 | } 17 | 18 | // AddressFromPublicKey serializes and converts an ecdsa public key into an address. 19 | func AddressFromPublicKey(publicKey *ecdsa.PublicKey) *common.Address { 20 | publicKeyBytes := elliptic.Marshal(elliptic.P521(), publicKey.X, publicKey.Y) // Marshal public key 21 | 22 | return common.NewAddress(Sha3(publicKeyBytes).Bytes()) // Return address value 23 | } 24 | 25 | /* END EXPORTED METHODS */ 26 | -------------------------------------------------------------------------------- /crypto/address_test.go: -------------------------------------------------------------------------------- 1 | // Package crypto provides cryptography helper methods. 2 | package crypto 3 | 4 | import ( 5 | "crypto/ecdsa" 6 | "crypto/elliptic" 7 | "crypto/rand" 8 | "encoding/hex" 9 | "testing" 10 | ) 11 | 12 | /* BEGIN EXPORTED METHODS TESTS */ 13 | 14 | // TestAddressFromPrivateKey tests the functionality of the AddressFromPrivateKey() helper method. 15 | func TestAddressFromPrivateKey(t *testing.T) { 16 | privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) // Generate ecdsa private key 17 | if err != nil { // Check for errors 18 | t.Fatal(err) // Panic 19 | } 20 | 21 | address := AddressFromPrivateKey(privateKey) // Derive address 22 | 23 | t.Log(hex.EncodeToString(address.Bytes())) // Log success 24 | } 25 | 26 | // TestAddressFromPublicKey tests the functionality of the AddressFromPublicKey() helper method. 27 | func TestAddressFromPublicKey(t *testing.T) { 28 | privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) // Generate ecdsa private key 29 | if err != nil { // Check for errors 30 | t.Fatal(err) // Panic 31 | } 32 | 33 | address := AddressFromPublicKey(&privateKey.PublicKey) // Derive address 34 | 35 | t.Log(address) // Log success 36 | } 37 | 38 | /* END EXPORTED METHODS TESTS */ 39 | -------------------------------------------------------------------------------- /crypto/crypto.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; // Specify compiler version 2 | 3 | package crypto; 4 | 5 | service Crypto { 6 | rpc AddressFromPrivateKey(GeneralRequest) returns (GeneralResponse) {} // Serialize new address from private key 7 | rpc AddressFromPublicKey(GeneralRequest) returns (GeneralResponse) {} // Serialize new address from public key 8 | rpc Sha3(GeneralRequest) returns (GeneralResponse) {} // Hash a given message with sha3 9 | rpc Sha3n(GeneralRequest) returns (GeneralResponse) {} // hash a given message with sha3 n times 10 | rpc Sha3d(GeneralRequest) returns (GeneralResponse) {} // Hash a given message with sha3 twice 11 | } 12 | 13 | /* BEGIN REQUESTS */ 14 | 15 | message GeneralRequest { 16 | string privatePublicKey = 1; // Private/public key 17 | 18 | bytes b = 2; // Hash input 19 | 20 | double n = 3; // N times to hash 21 | } 22 | 23 | /* END REQUESTS */ 24 | 25 | /* BEGIN RESPONSES */ 26 | 27 | message GeneralResponse { 28 | string message = 1; // Response 29 | } 30 | 31 | /* END REPSONSES */ -------------------------------------------------------------------------------- /crypto/sha3.go: -------------------------------------------------------------------------------- 1 | // Package crypto provides cryptography helper methods. 2 | package crypto 3 | 4 | import ( 5 | "encoding/hex" 6 | 7 | "github.com/polaris-project/go-polaris/common" 8 | "golang.org/x/crypto/sha3" 9 | ) 10 | 11 | /* BEGIN EXPORTED METHODS */ 12 | 13 | // Sha3 hashes a given message via sha3. 14 | func Sha3(b []byte) common.Hash { 15 | hash := sha3.New256() // Init hasher 16 | 17 | hash.Write(b) // Write 18 | 19 | return common.NewHash(hash.Sum(nil)) // Return final hash 20 | } 21 | 22 | // Sha3String hashes a given message via sha3 and encodes the hashed message to a hex string. 23 | func Sha3String(b []byte) string { 24 | b = Sha3(b).Bytes() // Hash 25 | 26 | return hex.EncodeToString(b) // Return string 27 | } 28 | 29 | // Sha3n hashes a given message via sha3 n times. 30 | func Sha3n(b []byte, n uint) common.Hash { 31 | hashSource := b // Init editable buffer 32 | 33 | for x := uint(0); x != n; x++ { // Hash n times 34 | hashSource = Sha3(hashSource).Bytes() // Hash 35 | } 36 | 37 | return common.NewHash(hashSource) // Return hashed 38 | } 39 | 40 | // Sha3nString hashes a given message via sha3 n times and encodes the hashed message to a hex string. 41 | func Sha3nString(b []byte, n uint) string { 42 | return hex.EncodeToString(Sha3n(b, n).Bytes()) // Return string hash 43 | } 44 | 45 | // Sha3d hashes a given message twice via sha3. 46 | func Sha3d(b []byte) common.Hash { 47 | return Sha3(Sha3(b).Bytes()) // Return sha3d result 48 | } 49 | 50 | // Sha3dString hashes a given message via sha3d and encodes the hashed message to a hex string. 51 | func Sha3dString(b []byte) string { 52 | return hex.EncodeToString(Sha3d(b).Bytes()) // Return string hash 53 | } 54 | 55 | /* END EXPORTED METHODS */ 56 | -------------------------------------------------------------------------------- /crypto/sha3_test.go: -------------------------------------------------------------------------------- 1 | // Package crypto provides cryptography helper methods. 2 | package crypto 3 | 4 | import "testing" 5 | 6 | /* BEGIN EXPORTED METHODS TESTS */ 7 | 8 | // TestSha3 tests the functionality of the sha3() helper method. 9 | func TestSha3(t *testing.T) { 10 | if Sha3([]byte("test")).IsNil() { // Check nil hash 11 | t.Fatal("hash should not be nil") // Panic 12 | } 13 | } 14 | 15 | // TestSha3String tests the functionality of the Sha3String() helper method. 16 | func TestSha3String(t *testing.T) { 17 | if Sha3String([]byte("test")) == "" { // Check nil hash 18 | t.Fatal("hash should not be nil") // Panic 19 | } 20 | } 21 | 22 | // TestSha3n tests the functionality of the Sha3n() helper method. 23 | func TestSha3n(t *testing.T) { 24 | if Sha3n([]byte("test"), 2).IsNil() { // Check nil hash 25 | t.Fatal("hash should not be nil") // Panic 26 | } 27 | } 28 | 29 | // TestSha3nString tests the functionality of the Sha3nString() helper method. 30 | func TestSha3nString(t *testing.T) { 31 | if Sha3nString([]byte("test"), 2) == "" { // Check nil hash 32 | t.Fatal("hash should not be nil") // Panic 33 | } 34 | } 35 | 36 | // TestSha3d tests the functionality of the Sha3d() helper method. 37 | func TestSha3d(t *testing.T) { 38 | if Sha3d([]byte("test")).IsNil() { // Check nil hash 39 | t.Fatal("hash should not be nil") // Panic 40 | } 41 | } 42 | 43 | // TestSha3dString tests the functionality of the Sha3dString() helper method. 44 | func TestSha3dString(t *testing.T) { 45 | if Sha3dString([]byte("test")) == "" { // Check nil hash 46 | t.Fatal("hash should not be nil") // Panic 47 | } 48 | } 49 | 50 | /* END EXPORTED METHODS TESTS */ 51 | -------------------------------------------------------------------------------- /doc/spec.md: -------------------------------------------------------------------------------- 1 | # Polaris Go Implementation Specifications 2 | 3 | ## Third-Party Dependencies 4 | 5 | ### Database 6 | 7 | For all applicable instances, [boltdb](https://github.com/boltdb/bolt) will deemed the working database engine and client. 8 | 9 | ### Sha3 10 | 11 | For hashing via Sha3, Go's [/x/Sha3]("golang.org/x/crypto/sha3") package will be used. 12 | 13 | ### Dependency Management 14 | 15 | To manage external dependencies, use Go's [module system](https://github.com/golang/go/wiki/Modules). To enable modules in Go... 16 | 17 | ```zsh 18 | # enable go modules: https://github.com/golang/go/wiki/Modules 19 | export GO111MODULE=on 20 | ``` 21 | 22 | To download all necessary dependencies into the vendor/ folder... 23 | 24 | ```zsh 25 | # download dependencies to vendor folder 26 | go mod vendor 27 | ``` 28 | 29 | ## Code Standards 30 | 31 | All code is documented in the [godoc-recognizable](https://blog.golang.org/godoc-documenting-go-code) format, that of which specifies each exported function should be preceded by a comment in the following format: 32 | 33 | ```Go 34 | // Fprint formats using the default formats for its operands and writes to w. 35 | // Spaces are added between operands when neither is a string. 36 | // It returns the number of bytes written and any write error encountered. 37 | func Fprint(w io.Writer, a ...interface{}) (n int, err error) { 38 | ``` 39 | 40 | Additionally, all package names--regardless of the file they're found in (but must be a .go file)--must be documented in the following format: 41 | 42 | ```Go 43 | // Package sort provides primitives for sorting slices and user-defined 44 | // collections. 45 | package sort 46 | ``` 47 | 48 | Finally, as would be found in the godoc "documenting Go code spec", all known bugs should be documented in the following format: 49 | 50 | ```Go 51 | // BUG(r): The rule Title uses for word boundaries does not handle Unicode punctuation properly. 52 | ``` 53 | 54 | In the aforementioned example, "r" would be replaced with the name or username of an individual responsible for or knowing of the bug. 55 | 56 | ## User Accounts 57 | 58 | Each user account is composed of an ecdsa private key. However, one should note that an "account" is not the same as an "address." An address is simply the 0x-prefix encoded sha3 hash of the byte value of a serialized ecdsa public key. Generally, an account's public key is derived from the account's private key (generated via `crypto/ecdsa`, `elliptic.p521()`, `crypto/rand`). 59 | 60 | An ecdsa key pair is represented by the `Account` struct, that of which stores a private key in the form of a pointer to an `ecdsa.PrivateKey`. Additionally, an account should also store a field called `SerializedPrivateKey`, that of which should be empty at all times except when the account is written to persistent memory. 61 | 62 | ### Generation 63 | 64 | As was mentioned earlier, each account's private key is derived from the Golang standard library ecdsa package `GenerateKey()` method. Generally, this `GenerateKey()` method will be used in conjunction with both a `crypto/rand` Reader (`rand.Reader` [make sure `crypto/rand` is imported, rather than `math/rand`]) and `elliptic.P521()`, though this can be substituted as seen fit. 65 | 66 | ### Serialization 67 | 68 | Accounts will be serialized via JSON and stored in a keystore path defined in the applicable common package (a child of the root Polaris data path specified in common). 69 | 70 | Whilst writing an account to persistent memory via JSON, the account's private key will be temporarily set to nil, and reset to its previous state after writing to memory. During the time that the ecdsa.privateKey pointer is set to nil, a field of `Account` will be set--`SerializedPrivateKey`. This `SerializedPrivateKey` field will take the value of an x509 encoded byte array value of the given private key. After having stored this serialized private key in the given account struct, the account will be written to persistent memory, and the value of `PrivateKey` subsequently reset to before writing to memory--`SerializedPrivateKey` should be set to nil after having reset `PrivateKey` to its previous state. 71 | 72 | Whilst reading an account from persistent memory via JSON, the account's serialized private key will be recovered from the given `"account\_{address}.json"` file (i.e. `0x000` => `"account_0x000.json"`), that of which should be deserialized into a pointer to an ecdsa private key. After having recovered the private key pointer from the serialized private key, the serialized private key should be set to nil, and the `PrivateKey` field be set to the deserialized private key (actual `ecdsa.PrivateKey` instance pointer). 73 | 74 | ### Addresses 75 | 76 | Account addresses will--as has been stated earlier--be derived from the account public key. To obtain the account address, one simply hashes the x509 encoded byte value of the account public key via Polaris's crypto package `Sha3` method. 77 | 78 | ### Code Structure 79 | 80 | Additionally, all of the `Account` functionality will be written in its own package, rather than in `common` or `types` (preferably in a package called `accounts`). Therefore, as the accounts logic will be written in its own package, all of the account related logic should be written in a folder called "accounts". 81 | 82 | ## Dag 83 | 84 | Unlike many other cryptographically secured digital currencies, Polaris is based around a directed-acyclic-graph data structure. This "dag" structure is composed of a list of transactions where each transaction contains the hash of its parents (previous transactions). 85 | 86 | No transaction--with the exception of the genesis--can have a parent transaction value of nil. 87 | 88 | Each entry into the acyclic graph will be treated as an entry into the dag's respective database. Additionally, all of the dag-related logic should take place in the types package. To ensure that the dag never reaches a size that is not indexable, the dag will not be treated as a strict slice of transaction pointers, but simply a key-value database instance, that of which will operate on [boltdb](https://github.com/boltdb/bolt). 89 | 90 | The only piece of information that the `dag.go` `Dag` struct will serve and store will be the hash of the genesis transaction, the dag's `DagConfig` pointer (contains supply allocation information and other metadata), and the dag length (should be stored as a pointer to a big integer). The dag's config stores an "identifier" that will be used to open a new database, as well write to memory (i.e. db stored under folder with name equivalent to identifier). The working dag db instance will be stored as a global variable in `dag.go` (all methods needing access to the dag db should not open a new db, but use the `dag.go` `WorkingDagDB` variable as a pointer to the db instance). In addition, the `dag.go` initializing pseudo-constructor method should accept a `DagConfig` struct instance pointer, that of which will provide the dag version, the genesis transaction information (`Alloc` address => float64 map), and the string dag identifier. 91 | 92 | ## Transaction 93 | 94 | As is the case with most other digital currency networks, a transaction is an atomic action on the network, that of which can represent the transfer of data or monetary value. In the case of Polaris, either may be true. 95 | 96 | ### Transaction Fields 97 | 98 | A single `Transaction` consists of the following fields: 99 | 100 | | Field | Value | Type | 101 | | ------------------ | -------------------------------------------------------------------------------------------------------------------------- | ---------------- | 102 | | AccountNonce | Transaction index in account list of transactions. | uint64 | 103 | | Amount | Transaction value. | \*big.Int | 104 | | Sender | Transaction sender address. | \*common.Address | 105 | | Recipient | Transaction recipient address. | \*common.Address | 106 | | ParentTransactions | Parent transaction hashes (usually 1, but in the case of a poorly synchronized network, may be more). | []common.Hash | 107 | | GasPrice | Amount of polaris willing to pay per single unit of gas (in increments of 0.000000001 polaris). | \*big.Int | 108 | | GasLimit | Amount of gas willing to pay at max. | uint64 | 109 | | Payload | Data sent with transaction (i.e. contract bytecode, message, etc...) | []byte | 110 | | Signature | ECDSA sender signature. | \*Signature | 111 | | Hash | Transaction hash including transaction signature (if set). To verify, exclude signature from tx hash as message to verify. | common.Hash | 112 | 113 | ## Transaction Signatures 114 | 115 | Transactions are signed via ECDSA. Furthermore, all of the signature-related logic has already been written, and is located in types/transaction_signature.go. Finally, each transaction contains a pointer to a signature struct instance. 116 | 117 | ### Signature Fields 118 | 119 | A single `Signature` consists of the following fields: 120 | 121 | | Field | Value | Type | 122 | | ----- | -------------------------------------------------------------------------------------- | --------- | 123 | | V | Signature value (in the case of a transaction, the hash before setting the signature). | []byte | 124 | | R | Signature recovery value. | \*big.Int | 125 | | S | Signature recovery value. | \*big.Int | 126 | 127 | ### Verifying Signatures 128 | 129 | Transaction signatures can be verified through the transaction_signature.go `Verify()` helper method. The `Verify()` helper method takes a public key as a parameter, that of which should be equivalent as the public key used to sign the message. 130 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/polaris-project/go-polaris 2 | 3 | require ( 4 | github.com/boltdb/bolt v1.3.1 5 | github.com/golang/protobuf v1.3.0 6 | github.com/juju/ansiterm v0.0.0-20180109212912-720a0952cc2a // indirect 7 | github.com/juju/loggo v0.0.0-20190212223446-d976af380377 8 | github.com/libp2p/go-libp2p v0.0.1 9 | github.com/libp2p/go-libp2p-crypto v0.0.1 10 | github.com/libp2p/go-libp2p-host v0.0.1 11 | github.com/libp2p/go-libp2p-kad-dht v0.0.3 12 | github.com/libp2p/go-libp2p-net v0.0.1 13 | github.com/libp2p/go-libp2p-peer v0.0.1 14 | github.com/libp2p/go-libp2p-peerstore v0.0.1 15 | github.com/libp2p/go-libp2p-protocol v0.0.1 16 | github.com/lunixbochs/vtclean v1.0.0 // indirect 17 | github.com/multiformats/go-multiaddr v0.0.1 18 | github.com/twitchtv/twirp v5.5.2+incompatible 19 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 20 | golang.org/x/net v0.0.0-20200226121028-0de0cce0169b // indirect 21 | golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect 22 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect 23 | ) 24 | 25 | go 1.13 26 | -------------------------------------------------------------------------------- /internal/proto/accounts/accounts.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: accounts.proto 3 | 4 | package accounts 5 | 6 | import ( 7 | fmt "fmt" 8 | math "math" 9 | 10 | proto "github.com/golang/protobuf/proto" 11 | ) 12 | 13 | // Reference imports to suppress errors if they are not otherwise used. 14 | var ( 15 | _ = proto.Marshal 16 | _ = fmt.Errorf 17 | _ = math.Inf 18 | ) 19 | 20 | // This is a compile-time assertion to ensure that this generated file 21 | // is compatible with the proto package it is being compiled against. 22 | // A compilation error at this line likely means your copy of the 23 | // proto package needs to be updated. 24 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 25 | 26 | type GeneralRequest struct { 27 | PrivatePublicKey string `protobuf:"bytes,1,opt,name=privatePublicKey,proto3" json:"privatePublicKey,omitempty"` 28 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 29 | XXX_unrecognized []byte `json:"-"` 30 | XXX_sizecache int32 `json:"-"` 31 | } 32 | 33 | func (m *GeneralRequest) Reset() { *m = GeneralRequest{} } 34 | func (m *GeneralRequest) String() string { return proto.CompactTextString(m) } 35 | func (*GeneralRequest) ProtoMessage() {} 36 | func (*GeneralRequest) Descriptor() ([]byte, []int) { 37 | return fileDescriptor_e1e7723af4c007b7, []int{0} 38 | } 39 | 40 | func (m *GeneralRequest) XXX_Unmarshal(b []byte) error { 41 | return xxx_messageInfo_GeneralRequest.Unmarshal(m, b) 42 | } 43 | 44 | func (m *GeneralRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 45 | return xxx_messageInfo_GeneralRequest.Marshal(b, m, deterministic) 46 | } 47 | 48 | func (m *GeneralRequest) XXX_Merge(src proto.Message) { 49 | xxx_messageInfo_GeneralRequest.Merge(m, src) 50 | } 51 | 52 | func (m *GeneralRequest) XXX_Size() int { 53 | return xxx_messageInfo_GeneralRequest.Size(m) 54 | } 55 | 56 | func (m *GeneralRequest) XXX_DiscardUnknown() { 57 | xxx_messageInfo_GeneralRequest.DiscardUnknown(m) 58 | } 59 | 60 | var xxx_messageInfo_GeneralRequest proto.InternalMessageInfo 61 | 62 | func (m *GeneralRequest) GetPrivatePublicKey() string { 63 | if m != nil { 64 | return m.PrivatePublicKey 65 | } 66 | return "" 67 | } 68 | 69 | type GeneralResponse struct { 70 | Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` 71 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 72 | XXX_unrecognized []byte `json:"-"` 73 | XXX_sizecache int32 `json:"-"` 74 | } 75 | 76 | func (m *GeneralResponse) Reset() { *m = GeneralResponse{} } 77 | func (m *GeneralResponse) String() string { return proto.CompactTextString(m) } 78 | func (*GeneralResponse) ProtoMessage() {} 79 | func (*GeneralResponse) Descriptor() ([]byte, []int) { 80 | return fileDescriptor_e1e7723af4c007b7, []int{1} 81 | } 82 | 83 | func (m *GeneralResponse) XXX_Unmarshal(b []byte) error { 84 | return xxx_messageInfo_GeneralResponse.Unmarshal(m, b) 85 | } 86 | 87 | func (m *GeneralResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 88 | return xxx_messageInfo_GeneralResponse.Marshal(b, m, deterministic) 89 | } 90 | 91 | func (m *GeneralResponse) XXX_Merge(src proto.Message) { 92 | xxx_messageInfo_GeneralResponse.Merge(m, src) 93 | } 94 | 95 | func (m *GeneralResponse) XXX_Size() int { 96 | return xxx_messageInfo_GeneralResponse.Size(m) 97 | } 98 | 99 | func (m *GeneralResponse) XXX_DiscardUnknown() { 100 | xxx_messageInfo_GeneralResponse.DiscardUnknown(m) 101 | } 102 | 103 | var xxx_messageInfo_GeneralResponse proto.InternalMessageInfo 104 | 105 | func (m *GeneralResponse) GetMessage() string { 106 | if m != nil { 107 | return m.Message 108 | } 109 | return "" 110 | } 111 | 112 | func init() { 113 | proto.RegisterType((*GeneralRequest)(nil), "accounts.GeneralRequest") 114 | proto.RegisterType((*GeneralResponse)(nil), "accounts.GeneralResponse") 115 | } 116 | 117 | func init() { proto.RegisterFile("accounts.proto", fileDescriptor_e1e7723af4c007b7) } 118 | 119 | var fileDescriptor_e1e7723af4c007b7 = []byte{ 120 | // 220 bytes of a gzipped FileDescriptorProto 121 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x4b, 0x4c, 0x4e, 0xce, 122 | 0x2f, 0xcd, 0x2b, 0x29, 0xd6, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x80, 0xf1, 0x95, 0x6c, 123 | 0xb8, 0xf8, 0xdc, 0x53, 0xf3, 0x52, 0x8b, 0x12, 0x73, 0x82, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 124 | 0x84, 0xb4, 0xb8, 0x04, 0x0a, 0x8a, 0x32, 0xcb, 0x12, 0x4b, 0x52, 0x03, 0x4a, 0x93, 0x72, 0x32, 125 | 0x93, 0xbd, 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0x30, 0xc4, 0x95, 0xb4, 0xb9, 126 | 0xf8, 0xe1, 0xba, 0x8b, 0x0b, 0xf2, 0xf3, 0x8a, 0x53, 0x85, 0x24, 0xb8, 0xd8, 0x73, 0x53, 0x8b, 127 | 0x8b, 0x13, 0xd3, 0x53, 0xa1, 0xba, 0x60, 0x5c, 0xa3, 0xb7, 0xcc, 0x5c, 0x1c, 0x8e, 0x50, 0x7b, 128 | 0x85, 0x9c, 0xb9, 0xb8, 0xfc, 0x52, 0xcb, 0xa1, 0x5c, 0x21, 0x09, 0x3d, 0xb8, 0x03, 0x51, 0x5d, 129 | 0x23, 0x25, 0x89, 0x45, 0x06, 0x62, 0x93, 0x12, 0x83, 0x90, 0x3b, 0xc8, 0xf1, 0x25, 0x8e, 0x39, 130 | 0x39, 0x70, 0x63, 0xc9, 0x37, 0x08, 0x6a, 0x84, 0x5b, 0x51, 0x7e, 0xae, 0x77, 0x6a, 0x25, 0xb9, 131 | 0x06, 0x39, 0x70, 0xb1, 0x3b, 0xa6, 0xa4, 0x14, 0xa5, 0x16, 0x93, 0xed, 0x14, 0x27, 0x2e, 0x4e, 132 | 0x78, 0xf8, 0x92, 0x6b, 0x86, 0x33, 0x17, 0x57, 0x00, 0x24, 0xaa, 0x28, 0x30, 0xc4, 0x9e, 0x8b, 133 | 0x2d, 0xb8, 0xa4, 0x28, 0x33, 0x2f, 0x9d, 0x4c, 0x03, 0x92, 0xd8, 0xc0, 0x69, 0xcd, 0x18, 0x10, 134 | 0x00, 0x00, 0xff, 0xff, 0xa2, 0x99, 0x6c, 0x04, 0x7d, 0x02, 0x00, 0x00, 135 | } 136 | -------------------------------------------------------------------------------- /internal/proto/config/config.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: config.proto 3 | 4 | package config 5 | 6 | import ( 7 | fmt "fmt" 8 | math "math" 9 | 10 | proto "github.com/golang/protobuf/proto" 11 | ) 12 | 13 | // Reference imports to suppress errors if they are not otherwise used. 14 | var ( 15 | _ = proto.Marshal 16 | _ = fmt.Errorf 17 | _ = math.Inf 18 | ) 19 | 20 | // This is a compile-time assertion to ensure that this generated file 21 | // is compatible with the proto package it is being compiled against. 22 | // A compilation error at this line likely means your copy of the 23 | // proto package needs to be updated. 24 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 25 | 26 | type GeneralRequest struct { 27 | FilePath string `protobuf:"bytes,1,opt,name=filePath,proto3" json:"filePath,omitempty"` 28 | Network string `protobuf:"bytes,2,opt,name=network,proto3" json:"network,omitempty"` 29 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 30 | XXX_unrecognized []byte `json:"-"` 31 | XXX_sizecache int32 `json:"-"` 32 | } 33 | 34 | func (m *GeneralRequest) Reset() { *m = GeneralRequest{} } 35 | func (m *GeneralRequest) String() string { return proto.CompactTextString(m) } 36 | func (*GeneralRequest) ProtoMessage() {} 37 | func (*GeneralRequest) Descriptor() ([]byte, []int) { 38 | return fileDescriptor_3eaf2c85e69e9ea4, []int{0} 39 | } 40 | 41 | func (m *GeneralRequest) XXX_Unmarshal(b []byte) error { 42 | return xxx_messageInfo_GeneralRequest.Unmarshal(m, b) 43 | } 44 | 45 | func (m *GeneralRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 46 | return xxx_messageInfo_GeneralRequest.Marshal(b, m, deterministic) 47 | } 48 | 49 | func (m *GeneralRequest) XXX_Merge(src proto.Message) { 50 | xxx_messageInfo_GeneralRequest.Merge(m, src) 51 | } 52 | 53 | func (m *GeneralRequest) XXX_Size() int { 54 | return xxx_messageInfo_GeneralRequest.Size(m) 55 | } 56 | 57 | func (m *GeneralRequest) XXX_DiscardUnknown() { 58 | xxx_messageInfo_GeneralRequest.DiscardUnknown(m) 59 | } 60 | 61 | var xxx_messageInfo_GeneralRequest proto.InternalMessageInfo 62 | 63 | func (m *GeneralRequest) GetFilePath() string { 64 | if m != nil { 65 | return m.FilePath 66 | } 67 | return "" 68 | } 69 | 70 | func (m *GeneralRequest) GetNetwork() string { 71 | if m != nil { 72 | return m.Network 73 | } 74 | return "" 75 | } 76 | 77 | type GeneralResponse struct { 78 | Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` 79 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 80 | XXX_unrecognized []byte `json:"-"` 81 | XXX_sizecache int32 `json:"-"` 82 | } 83 | 84 | func (m *GeneralResponse) Reset() { *m = GeneralResponse{} } 85 | func (m *GeneralResponse) String() string { return proto.CompactTextString(m) } 86 | func (*GeneralResponse) ProtoMessage() {} 87 | func (*GeneralResponse) Descriptor() ([]byte, []int) { 88 | return fileDescriptor_3eaf2c85e69e9ea4, []int{1} 89 | } 90 | 91 | func (m *GeneralResponse) XXX_Unmarshal(b []byte) error { 92 | return xxx_messageInfo_GeneralResponse.Unmarshal(m, b) 93 | } 94 | 95 | func (m *GeneralResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 96 | return xxx_messageInfo_GeneralResponse.Marshal(b, m, deterministic) 97 | } 98 | 99 | func (m *GeneralResponse) XXX_Merge(src proto.Message) { 100 | xxx_messageInfo_GeneralResponse.Merge(m, src) 101 | } 102 | 103 | func (m *GeneralResponse) XXX_Size() int { 104 | return xxx_messageInfo_GeneralResponse.Size(m) 105 | } 106 | 107 | func (m *GeneralResponse) XXX_DiscardUnknown() { 108 | xxx_messageInfo_GeneralResponse.DiscardUnknown(m) 109 | } 110 | 111 | var xxx_messageInfo_GeneralResponse proto.InternalMessageInfo 112 | 113 | func (m *GeneralResponse) GetMessage() string { 114 | if m != nil { 115 | return m.Message 116 | } 117 | return "" 118 | } 119 | 120 | func init() { 121 | proto.RegisterType((*GeneralRequest)(nil), "config.GeneralRequest") 122 | proto.RegisterType((*GeneralResponse)(nil), "config.GeneralResponse") 123 | } 124 | 125 | func init() { proto.RegisterFile("config.proto", fileDescriptor_3eaf2c85e69e9ea4) } 126 | 127 | var fileDescriptor_3eaf2c85e69e9ea4 = []byte{ 128 | // 187 bytes of a gzipped FileDescriptorProto 129 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x49, 0xce, 0xcf, 0x4b, 130 | 0xcb, 0x4c, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x83, 0xf0, 0x94, 0xdc, 0xb8, 0xf8, 131 | 0xdc, 0x53, 0xf3, 0x52, 0x8b, 0x12, 0x73, 0x82, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0xa4, 132 | 0xb8, 0x38, 0xd2, 0x32, 0x73, 0x52, 0x03, 0x12, 0x4b, 0x32, 0x24, 0x18, 0x15, 0x18, 0x35, 0x38, 133 | 0x83, 0xe0, 0x7c, 0x21, 0x09, 0x2e, 0xf6, 0xbc, 0xd4, 0x92, 0xf2, 0xfc, 0xa2, 0x6c, 0x09, 0x26, 134 | 0xb0, 0x14, 0x8c, 0xab, 0xa4, 0xcd, 0xc5, 0x0f, 0x37, 0xa7, 0xb8, 0x20, 0x3f, 0xaf, 0x38, 0x15, 135 | 0xa4, 0x38, 0x37, 0xb5, 0xb8, 0x38, 0x31, 0x3d, 0x15, 0x6a, 0x0e, 0x8c, 0x6b, 0x74, 0x9e, 0x91, 136 | 0x8b, 0xcd, 0x19, 0x6c, 0xbf, 0x90, 0x23, 0x17, 0x8f, 0x5f, 0x6a, 0xb9, 0x4b, 0x62, 0x3a, 0x94, 137 | 0x2f, 0xa6, 0x07, 0x75, 0x26, 0xaa, 0xab, 0xa4, 0xc4, 0x31, 0xc4, 0x21, 0xb6, 0x28, 0x31, 0x08, 138 | 0x39, 0x71, 0xf1, 0xba, 0xa7, 0x96, 0x38, 0xe6, 0xe4, 0x40, 0x8c, 0x28, 0x26, 0xc7, 0x0c, 0x3b, 139 | 0x2e, 0x4e, 0xf7, 0xd4, 0x12, 0xb2, 0xdd, 0x90, 0xc4, 0x06, 0x0e, 0x55, 0x63, 0x40, 0x00, 0x00, 140 | 0x00, 0xff, 0xff, 0xf2, 0xa9, 0x90, 0x2a, 0x65, 0x01, 0x00, 0x00, 141 | } 142 | -------------------------------------------------------------------------------- /internal/proto/crypto/crypto.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: crypto.proto 3 | 4 | package crypto 5 | 6 | import ( 7 | fmt "fmt" 8 | math "math" 9 | 10 | proto "github.com/golang/protobuf/proto" 11 | ) 12 | 13 | // Reference imports to suppress errors if they are not otherwise used. 14 | var ( 15 | _ = proto.Marshal 16 | _ = fmt.Errorf 17 | _ = math.Inf 18 | ) 19 | 20 | // This is a compile-time assertion to ensure that this generated file 21 | // is compatible with the proto package it is being compiled against. 22 | // A compilation error at this line likely means your copy of the 23 | // proto package needs to be updated. 24 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 25 | 26 | type GeneralRequest struct { 27 | PrivatePublicKey string `protobuf:"bytes,1,opt,name=privatePublicKey,proto3" json:"privatePublicKey,omitempty"` 28 | B []byte `protobuf:"bytes,2,opt,name=b,proto3" json:"b,omitempty"` 29 | N float64 `protobuf:"fixed64,3,opt,name=n,proto3" json:"n,omitempty"` 30 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 31 | XXX_unrecognized []byte `json:"-"` 32 | XXX_sizecache int32 `json:"-"` 33 | } 34 | 35 | func (m *GeneralRequest) Reset() { *m = GeneralRequest{} } 36 | func (m *GeneralRequest) String() string { return proto.CompactTextString(m) } 37 | func (*GeneralRequest) ProtoMessage() {} 38 | func (*GeneralRequest) Descriptor() ([]byte, []int) { 39 | return fileDescriptor_527278fb02d03321, []int{0} 40 | } 41 | 42 | func (m *GeneralRequest) XXX_Unmarshal(b []byte) error { 43 | return xxx_messageInfo_GeneralRequest.Unmarshal(m, b) 44 | } 45 | 46 | func (m *GeneralRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 47 | return xxx_messageInfo_GeneralRequest.Marshal(b, m, deterministic) 48 | } 49 | 50 | func (m *GeneralRequest) XXX_Merge(src proto.Message) { 51 | xxx_messageInfo_GeneralRequest.Merge(m, src) 52 | } 53 | 54 | func (m *GeneralRequest) XXX_Size() int { 55 | return xxx_messageInfo_GeneralRequest.Size(m) 56 | } 57 | 58 | func (m *GeneralRequest) XXX_DiscardUnknown() { 59 | xxx_messageInfo_GeneralRequest.DiscardUnknown(m) 60 | } 61 | 62 | var xxx_messageInfo_GeneralRequest proto.InternalMessageInfo 63 | 64 | func (m *GeneralRequest) GetPrivatePublicKey() string { 65 | if m != nil { 66 | return m.PrivatePublicKey 67 | } 68 | return "" 69 | } 70 | 71 | func (m *GeneralRequest) GetB() []byte { 72 | if m != nil { 73 | return m.B 74 | } 75 | return nil 76 | } 77 | 78 | func (m *GeneralRequest) GetN() float64 { 79 | if m != nil { 80 | return m.N 81 | } 82 | return 0 83 | } 84 | 85 | type GeneralResponse struct { 86 | Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` 87 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 88 | XXX_unrecognized []byte `json:"-"` 89 | XXX_sizecache int32 `json:"-"` 90 | } 91 | 92 | func (m *GeneralResponse) Reset() { *m = GeneralResponse{} } 93 | func (m *GeneralResponse) String() string { return proto.CompactTextString(m) } 94 | func (*GeneralResponse) ProtoMessage() {} 95 | func (*GeneralResponse) Descriptor() ([]byte, []int) { 96 | return fileDescriptor_527278fb02d03321, []int{1} 97 | } 98 | 99 | func (m *GeneralResponse) XXX_Unmarshal(b []byte) error { 100 | return xxx_messageInfo_GeneralResponse.Unmarshal(m, b) 101 | } 102 | 103 | func (m *GeneralResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 104 | return xxx_messageInfo_GeneralResponse.Marshal(b, m, deterministic) 105 | } 106 | 107 | func (m *GeneralResponse) XXX_Merge(src proto.Message) { 108 | xxx_messageInfo_GeneralResponse.Merge(m, src) 109 | } 110 | 111 | func (m *GeneralResponse) XXX_Size() int { 112 | return xxx_messageInfo_GeneralResponse.Size(m) 113 | } 114 | 115 | func (m *GeneralResponse) XXX_DiscardUnknown() { 116 | xxx_messageInfo_GeneralResponse.DiscardUnknown(m) 117 | } 118 | 119 | var xxx_messageInfo_GeneralResponse proto.InternalMessageInfo 120 | 121 | func (m *GeneralResponse) GetMessage() string { 122 | if m != nil { 123 | return m.Message 124 | } 125 | return "" 126 | } 127 | 128 | func init() { 129 | proto.RegisterType((*GeneralRequest)(nil), "crypto.GeneralRequest") 130 | proto.RegisterType((*GeneralResponse)(nil), "crypto.GeneralResponse") 131 | } 132 | 133 | func init() { proto.RegisterFile("crypto.proto", fileDescriptor_527278fb02d03321) } 134 | 135 | var fileDescriptor_527278fb02d03321 = []byte{ 136 | // 222 bytes of a gzipped FileDescriptorProto 137 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0xe2, 0x49, 0x2e, 0xaa, 0x2c, 138 | 0x28, 0xc9, 0xd7, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x83, 0xf0, 0x94, 0x22, 0xb8, 0xf8, 139 | 0xdc, 0x53, 0xf3, 0x52, 0x8b, 0x12, 0x73, 0x82, 0x52, 0x0b, 0x4b, 0x53, 0x8b, 0x4b, 0x84, 0xb4, 140 | 0xb8, 0x04, 0x0a, 0x8a, 0x32, 0xcb, 0x12, 0x4b, 0x52, 0x03, 0x4a, 0x93, 0x72, 0x32, 0x93, 0xbd, 141 | 0x53, 0x2b, 0x25, 0x18, 0x15, 0x18, 0x35, 0x38, 0x83, 0x30, 0xc4, 0x85, 0x78, 0xb8, 0x18, 0x93, 142 | 0x24, 0x98, 0x14, 0x18, 0x35, 0x78, 0x82, 0x18, 0x93, 0x40, 0xbc, 0x3c, 0x09, 0x66, 0x05, 0x46, 143 | 0x0d, 0xc6, 0x20, 0xc6, 0x3c, 0x25, 0x6d, 0x2e, 0x7e, 0xb8, 0xc9, 0xc5, 0x05, 0xf9, 0x79, 0xc5, 144 | 0xa9, 0x42, 0x12, 0x5c, 0xec, 0xb9, 0xa9, 0xc5, 0xc5, 0x89, 0xe9, 0xa9, 0x50, 0x13, 0x61, 0x5c, 145 | 0xa3, 0x4b, 0x4c, 0x5c, 0x6c, 0xce, 0x60, 0x17, 0x09, 0x79, 0x71, 0x89, 0x3a, 0xa6, 0xa4, 0x14, 146 | 0xa5, 0x16, 0x17, 0xbb, 0x15, 0xe5, 0xe7, 0x06, 0x40, 0xac, 0x04, 0x59, 0x26, 0xa6, 0x07, 0xf5, 147 | 0x01, 0xaa, 0x83, 0xa5, 0xc4, 0x31, 0xc4, 0x21, 0xd6, 0x29, 0x31, 0x08, 0x79, 0x72, 0x89, 0x20, 148 | 0x9b, 0x05, 0x77, 0x37, 0x19, 0x46, 0x59, 0x72, 0xb1, 0x04, 0x67, 0x24, 0x1a, 0x93, 0xa3, 0xd5, 149 | 0x8a, 0x8b, 0x15, 0xa4, 0x35, 0x8f, 0x02, 0xbd, 0x29, 0x64, 0xe8, 0x4d, 0x62, 0x03, 0x47, 0xb5, 150 | 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xc0, 0x8c, 0x85, 0xc6, 0xfa, 0x01, 0x00, 0x00, 151 | } 152 | -------------------------------------------------------------------------------- /internal/proto/dag/dag.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: dag.proto 3 | 4 | package dag 5 | 6 | import ( 7 | fmt "fmt" 8 | math "math" 9 | 10 | proto "github.com/golang/protobuf/proto" 11 | ) 12 | 13 | // Reference imports to suppress errors if they are not otherwise used. 14 | var ( 15 | _ = proto.Marshal 16 | _ = fmt.Errorf 17 | _ = math.Inf 18 | ) 19 | 20 | // This is a compile-time assertion to ensure that this generated file 21 | // is compatible with the proto package it is being compiled against. 22 | // A compilation error at this line likely means your copy of the 23 | // proto package needs to be updated. 24 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 25 | 26 | type GeneralRequest struct { 27 | Network string `protobuf:"bytes,1,opt,name=network,proto3" json:"network,omitempty"` 28 | TransactionHash string `protobuf:"bytes,2,opt,name=transactionHash,proto3" json:"transactionHash,omitempty"` 29 | Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` 30 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 31 | XXX_unrecognized []byte `json:"-"` 32 | XXX_sizecache int32 `json:"-"` 33 | } 34 | 35 | func (m *GeneralRequest) Reset() { *m = GeneralRequest{} } 36 | func (m *GeneralRequest) String() string { return proto.CompactTextString(m) } 37 | func (*GeneralRequest) ProtoMessage() {} 38 | func (*GeneralRequest) Descriptor() ([]byte, []int) { 39 | return fileDescriptor_228b96b95413374c, []int{0} 40 | } 41 | 42 | func (m *GeneralRequest) XXX_Unmarshal(b []byte) error { 43 | return xxx_messageInfo_GeneralRequest.Unmarshal(m, b) 44 | } 45 | 46 | func (m *GeneralRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 47 | return xxx_messageInfo_GeneralRequest.Marshal(b, m, deterministic) 48 | } 49 | 50 | func (m *GeneralRequest) XXX_Merge(src proto.Message) { 51 | xxx_messageInfo_GeneralRequest.Merge(m, src) 52 | } 53 | 54 | func (m *GeneralRequest) XXX_Size() int { 55 | return xxx_messageInfo_GeneralRequest.Size(m) 56 | } 57 | 58 | func (m *GeneralRequest) XXX_DiscardUnknown() { 59 | xxx_messageInfo_GeneralRequest.DiscardUnknown(m) 60 | } 61 | 62 | var xxx_messageInfo_GeneralRequest proto.InternalMessageInfo 63 | 64 | func (m *GeneralRequest) GetNetwork() string { 65 | if m != nil { 66 | return m.Network 67 | } 68 | return "" 69 | } 70 | 71 | func (m *GeneralRequest) GetTransactionHash() string { 72 | if m != nil { 73 | return m.TransactionHash 74 | } 75 | return "" 76 | } 77 | 78 | func (m *GeneralRequest) GetAddress() string { 79 | if m != nil { 80 | return m.Address 81 | } 82 | return "" 83 | } 84 | 85 | type GeneralResponse struct { 86 | Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` 87 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 88 | XXX_unrecognized []byte `json:"-"` 89 | XXX_sizecache int32 `json:"-"` 90 | } 91 | 92 | func (m *GeneralResponse) Reset() { *m = GeneralResponse{} } 93 | func (m *GeneralResponse) String() string { return proto.CompactTextString(m) } 94 | func (*GeneralResponse) ProtoMessage() {} 95 | func (*GeneralResponse) Descriptor() ([]byte, []int) { 96 | return fileDescriptor_228b96b95413374c, []int{1} 97 | } 98 | 99 | func (m *GeneralResponse) XXX_Unmarshal(b []byte) error { 100 | return xxx_messageInfo_GeneralResponse.Unmarshal(m, b) 101 | } 102 | 103 | func (m *GeneralResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 104 | return xxx_messageInfo_GeneralResponse.Marshal(b, m, deterministic) 105 | } 106 | 107 | func (m *GeneralResponse) XXX_Merge(src proto.Message) { 108 | xxx_messageInfo_GeneralResponse.Merge(m, src) 109 | } 110 | 111 | func (m *GeneralResponse) XXX_Size() int { 112 | return xxx_messageInfo_GeneralResponse.Size(m) 113 | } 114 | 115 | func (m *GeneralResponse) XXX_DiscardUnknown() { 116 | xxx_messageInfo_GeneralResponse.DiscardUnknown(m) 117 | } 118 | 119 | var xxx_messageInfo_GeneralResponse proto.InternalMessageInfo 120 | 121 | func (m *GeneralResponse) GetMessage() string { 122 | if m != nil { 123 | return m.Message 124 | } 125 | return "" 126 | } 127 | 128 | func init() { 129 | proto.RegisterType((*GeneralRequest)(nil), "dag.GeneralRequest") 130 | proto.RegisterType((*GeneralResponse)(nil), "dag.GeneralResponse") 131 | } 132 | 133 | func init() { proto.RegisterFile("dag.proto", fileDescriptor_228b96b95413374c) } 134 | 135 | var fileDescriptor_228b96b95413374c = []byte{ 136 | // 276 bytes of a gzipped FileDescriptorProto 137 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0xd2, 0xc1, 0x4e, 0xc3, 0x30, 138 | 0x0c, 0x00, 0x50, 0xc6, 0xd0, 0xd0, 0x8c, 0xc4, 0xa4, 0x30, 0x41, 0xc4, 0x09, 0xf5, 0x34, 0x09, 139 | 0x69, 0x07, 0x10, 0x17, 0x6e, 0x6b, 0x81, 0x72, 0x81, 0xc3, 0xe0, 0x07, 0x4c, 0x63, 0x75, 0xd5, 140 | 0x42, 0x32, 0xe2, 0x4c, 0xd3, 0xfe, 0x86, 0x4f, 0x45, 0x69, 0x3b, 0xa0, 0x70, 0xca, 0xad, 0x76, 141 | 0x9d, 0x67, 0x3b, 0x0a, 0x0c, 0x15, 0x96, 0xd3, 0x95, 0xb3, 0xde, 0x8a, 0xbe, 0xc2, 0x32, 0x31, 142 | 0x70, 0x9c, 0x93, 0x21, 0x87, 0x7a, 0x4e, 0x1f, 0x6b, 0x62, 0x2f, 0x24, 0x1c, 0x1a, 0xf2, 0x1b, 143 | 0xeb, 0x96, 0xb2, 0x77, 0xd1, 0x9b, 0x0c, 0xe7, 0xbb, 0x50, 0x4c, 0x60, 0xe4, 0x1d, 0x1a, 0xc6, 144 | 0xc2, 0x57, 0xd6, 0x3c, 0x22, 0x2f, 0xe4, 0x7e, 0x5d, 0xf1, 0x37, 0x1d, 0x0c, 0x54, 0xca, 0x11, 145 | 0xb3, 0xec, 0x37, 0x46, 0x1b, 0x26, 0x97, 0x30, 0xfa, 0xee, 0xc7, 0x2b, 0x6b, 0x98, 0x42, 0xf1, 146 | 0x3b, 0x31, 0x63, 0x49, 0xbb, 0x86, 0x6d, 0x78, 0xf5, 0x79, 0x00, 0xfd, 0x3b, 0x2c, 0xc5, 0x0d, 147 | 0x0c, 0x9e, 0x69, 0x13, 0xbe, 0x4e, 0xa6, 0x61, 0xfe, 0xee, 0xc4, 0xe7, 0xe3, 0x6e, 0xb2, 0x61, 148 | 0x93, 0x3d, 0x71, 0x0b, 0x47, 0x4f, 0xb8, 0xa4, 0xf0, 0x83, 0x2b, 0x8e, 0x3b, 0x9b, 0xc1, 0x38, 149 | 0x27, 0xff, 0xfa, 0xb3, 0x57, 0xba, 0xad, 0x37, 0x8b, 0x42, 0xee, 0xe1, 0xb4, 0x8b, 0x64, 0x8b, 150 | 0x4a, 0x2b, 0x47, 0x26, 0x8e, 0xc9, 0x41, 0x76, 0x19, 0x4e, 0xb7, 0xb3, 0xe6, 0x3e, 0xe3, 0xa0, 151 | 0x07, 0x38, 0xfb, 0x07, 0xbd, 0x90, 0x51, 0xe4, 0xe2, 0x9c, 0x19, 0x88, 0x9c, 0x7c, 0x4a, 0xfc, 152 | 0xdb, 0x8a, 0x1e, 0x25, 0x43, 0x5d, 0xac, 0x35, 0x7a, 0x6a, 0x77, 0x49, 0x51, 0xa3, 0x29, 0x28, 153 | 0xca, 0x79, 0x1b, 0xd4, 0x6f, 0xf9, 0xfa, 0x2b, 0x00, 0x00, 0xff, 0xff, 0xbc, 0x7a, 0x78, 0x01, 154 | 0xd8, 0x02, 0x00, 0x00, 155 | } 156 | -------------------------------------------------------------------------------- /internal/proto/transaction/transaction.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // source: transaction.proto 3 | 4 | package transaction 5 | 6 | import ( 7 | fmt "fmt" 8 | math "math" 9 | 10 | proto "github.com/golang/protobuf/proto" 11 | ) 12 | 13 | // Reference imports to suppress errors if they are not otherwise used. 14 | var ( 15 | _ = proto.Marshal 16 | _ = fmt.Errorf 17 | _ = math.Inf 18 | ) 19 | 20 | // This is a compile-time assertion to ensure that this generated file 21 | // is compatible with the proto package it is being compiled against. 22 | // A compilation error at this line likely means your copy of the 23 | // proto package needs to be updated. 24 | const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package 25 | 26 | type GeneralRequest struct { 27 | Nonce uint64 `protobuf:"varint,1,opt,name=nonce,proto3" json:"nonce,omitempty"` 28 | Amount []byte `protobuf:"bytes,2,opt,name=amount,proto3" json:"amount,omitempty"` 29 | Address string `protobuf:"bytes,3,opt,name=address,proto3" json:"address,omitempty"` 30 | Address2 string `protobuf:"bytes,4,opt,name=address2,proto3" json:"address2,omitempty"` 31 | TransactionHash []string `protobuf:"bytes,5,rep,name=transactionHash,proto3" json:"transactionHash,omitempty"` 32 | GasLimit uint64 `protobuf:"varint,6,opt,name=gasLimit,proto3" json:"gasLimit,omitempty"` 33 | GasPrice uint64 `protobuf:"varint,7,opt,name=gasPrice,proto3" json:"gasPrice,omitempty"` 34 | Payload []byte `protobuf:"bytes,8,opt,name=payload,proto3" json:"payload,omitempty"` 35 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 36 | XXX_unrecognized []byte `json:"-"` 37 | XXX_sizecache int32 `json:"-"` 38 | } 39 | 40 | func (m *GeneralRequest) Reset() { *m = GeneralRequest{} } 41 | func (m *GeneralRequest) String() string { return proto.CompactTextString(m) } 42 | func (*GeneralRequest) ProtoMessage() {} 43 | func (*GeneralRequest) Descriptor() ([]byte, []int) { 44 | return fileDescriptor_2cc4e03d2c28c490, []int{0} 45 | } 46 | 47 | func (m *GeneralRequest) XXX_Unmarshal(b []byte) error { 48 | return xxx_messageInfo_GeneralRequest.Unmarshal(m, b) 49 | } 50 | 51 | func (m *GeneralRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 52 | return xxx_messageInfo_GeneralRequest.Marshal(b, m, deterministic) 53 | } 54 | 55 | func (m *GeneralRequest) XXX_Merge(src proto.Message) { 56 | xxx_messageInfo_GeneralRequest.Merge(m, src) 57 | } 58 | 59 | func (m *GeneralRequest) XXX_Size() int { 60 | return xxx_messageInfo_GeneralRequest.Size(m) 61 | } 62 | 63 | func (m *GeneralRequest) XXX_DiscardUnknown() { 64 | xxx_messageInfo_GeneralRequest.DiscardUnknown(m) 65 | } 66 | 67 | var xxx_messageInfo_GeneralRequest proto.InternalMessageInfo 68 | 69 | func (m *GeneralRequest) GetNonce() uint64 { 70 | if m != nil { 71 | return m.Nonce 72 | } 73 | return 0 74 | } 75 | 76 | func (m *GeneralRequest) GetAmount() []byte { 77 | if m != nil { 78 | return m.Amount 79 | } 80 | return nil 81 | } 82 | 83 | func (m *GeneralRequest) GetAddress() string { 84 | if m != nil { 85 | return m.Address 86 | } 87 | return "" 88 | } 89 | 90 | func (m *GeneralRequest) GetAddress2() string { 91 | if m != nil { 92 | return m.Address2 93 | } 94 | return "" 95 | } 96 | 97 | func (m *GeneralRequest) GetTransactionHash() []string { 98 | if m != nil { 99 | return m.TransactionHash 100 | } 101 | return nil 102 | } 103 | 104 | func (m *GeneralRequest) GetGasLimit() uint64 { 105 | if m != nil { 106 | return m.GasLimit 107 | } 108 | return 0 109 | } 110 | 111 | func (m *GeneralRequest) GetGasPrice() uint64 { 112 | if m != nil { 113 | return m.GasPrice 114 | } 115 | return 0 116 | } 117 | 118 | func (m *GeneralRequest) GetPayload() []byte { 119 | if m != nil { 120 | return m.Payload 121 | } 122 | return nil 123 | } 124 | 125 | type GeneralResponse struct { 126 | Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` 127 | XXX_NoUnkeyedLiteral struct{} `json:"-"` 128 | XXX_unrecognized []byte `json:"-"` 129 | XXX_sizecache int32 `json:"-"` 130 | } 131 | 132 | func (m *GeneralResponse) Reset() { *m = GeneralResponse{} } 133 | func (m *GeneralResponse) String() string { return proto.CompactTextString(m) } 134 | func (*GeneralResponse) ProtoMessage() {} 135 | func (*GeneralResponse) Descriptor() ([]byte, []int) { 136 | return fileDescriptor_2cc4e03d2c28c490, []int{1} 137 | } 138 | 139 | func (m *GeneralResponse) XXX_Unmarshal(b []byte) error { 140 | return xxx_messageInfo_GeneralResponse.Unmarshal(m, b) 141 | } 142 | 143 | func (m *GeneralResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { 144 | return xxx_messageInfo_GeneralResponse.Marshal(b, m, deterministic) 145 | } 146 | 147 | func (m *GeneralResponse) XXX_Merge(src proto.Message) { 148 | xxx_messageInfo_GeneralResponse.Merge(m, src) 149 | } 150 | 151 | func (m *GeneralResponse) XXX_Size() int { 152 | return xxx_messageInfo_GeneralResponse.Size(m) 153 | } 154 | 155 | func (m *GeneralResponse) XXX_DiscardUnknown() { 156 | xxx_messageInfo_GeneralResponse.DiscardUnknown(m) 157 | } 158 | 159 | var xxx_messageInfo_GeneralResponse proto.InternalMessageInfo 160 | 161 | func (m *GeneralResponse) GetMessage() string { 162 | if m != nil { 163 | return m.Message 164 | } 165 | return "" 166 | } 167 | 168 | func init() { 169 | proto.RegisterType((*GeneralRequest)(nil), "transaction.GeneralRequest") 170 | proto.RegisterType((*GeneralResponse)(nil), "transaction.GeneralResponse") 171 | } 172 | 173 | func init() { proto.RegisterFile("transaction.proto", fileDescriptor_2cc4e03d2c28c490) } 174 | 175 | var fileDescriptor_2cc4e03d2c28c490 = []byte{ 176 | // 325 bytes of a gzipped FileDescriptorProto 177 | 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0xcd, 0x6a, 0xf2, 0x40, 178 | 0x14, 0x86, 0xbf, 0x7c, 0x6a, 0xd4, 0x63, 0x51, 0x3a, 0x2d, 0x65, 0xb0, 0x5d, 0x04, 0x57, 0x81, 179 | 0x82, 0x0b, 0x7b, 0x09, 0xa5, 0x3f, 0x94, 0x2a, 0x32, 0x8a, 0xfb, 0x63, 0x9c, 0xc6, 0x81, 0x71, 180 | 0xc6, 0xce, 0x4c, 0x28, 0xde, 0x4e, 0xaf, 0xb0, 0x97, 0x50, 0x9c, 0x68, 0x9a, 0x96, 0xee, 0xd2, 181 | 0x5d, 0x9e, 0xf3, 0x86, 0x37, 0xcf, 0x39, 0x10, 0x38, 0x75, 0x06, 0x95, 0xc5, 0xc4, 0x09, 0xad, 182 | 0x86, 0x5b, 0xa3, 0x9d, 0x26, 0x9d, 0xd2, 0x68, 0xf0, 0x11, 0x40, 0xf7, 0x81, 0x2b, 0x6e, 0x50, 183 | 0x32, 0xfe, 0x9a, 0x71, 0xeb, 0xc8, 0x39, 0x34, 0x94, 0x56, 0x09, 0xa7, 0x41, 0x14, 0xc4, 0x75, 184 | 0x96, 0x03, 0xb9, 0x80, 0x10, 0x37, 0x3a, 0x53, 0x8e, 0xfe, 0x8f, 0x82, 0xf8, 0x84, 0x1d, 0x88, 185 | 0x50, 0x68, 0xe2, 0x6a, 0x65, 0xb8, 0xb5, 0xb4, 0x16, 0x05, 0x71, 0x9b, 0x1d, 0x91, 0xf4, 0xa1, 186 | 0x75, 0x78, 0x1c, 0xd1, 0xba, 0x8f, 0x0a, 0x26, 0x31, 0xf4, 0x4a, 0x16, 0x8f, 0x68, 0xd7, 0xb4, 187 | 0x11, 0xd5, 0xe2, 0x36, 0xfb, 0x39, 0xde, 0xb7, 0xa4, 0x68, 0x9f, 0xc5, 0x46, 0x38, 0x1a, 0x7a, 188 | 0xa1, 0x82, 0x0f, 0xd9, 0xd4, 0x88, 0x84, 0xd3, 0x66, 0x91, 0x79, 0xde, 0x7b, 0x6d, 0x71, 0x27, 189 | 0x35, 0xae, 0x68, 0xcb, 0x0b, 0x1f, 0x71, 0x70, 0x0d, 0xbd, 0x62, 0x63, 0xbb, 0xd5, 0xca, 0xfa, 190 | 0x97, 0x37, 0xdc, 0x5a, 0x4c, 0xf3, 0xa5, 0xdb, 0xec, 0x88, 0xa3, 0xf7, 0x3a, 0x74, 0xe6, 0x5f, 191 | 0x4a, 0x64, 0x0c, 0xdd, 0x09, 0x7f, 0x2b, 0x4f, 0x2e, 0x87, 0xe5, 0x13, 0x7f, 0xbf, 0x65, 0xff, 192 | 0xea, 0xf7, 0x30, 0xff, 0xec, 0xe0, 0x1f, 0x61, 0x70, 0x76, 0x8b, 0x32, 0xc9, 0x24, 0x3a, 0x3e, 193 | 0xd7, 0x0e, 0xe5, 0x02, 0x65, 0xc6, 0xab, 0x75, 0x4e, 0xa0, 0x37, 0x13, 0xa9, 0xfa, 0x33, 0xc7, 194 | 0x7b, 0x68, 0x4e, 0xb3, 0xa5, 0x14, 0x76, 0x5d, 0xad, 0xe7, 0x09, 0x3a, 0x7b, 0xaf, 0x71, 0x7e, 195 | 0xd9, 0x6a, 0x5d, 0x77, 0x10, 0x2e, 0xb8, 0x11, 0x2f, 0xbb, 0xca, 0x35, 0x33, 0x67, 0x84, 0x4a, 196 | 0x2b, 0xd5, 0x2c, 0x43, 0xff, 0x63, 0xdd, 0x7c, 0x06, 0x00, 0x00, 0xff, 0xff, 0xfb, 0x8a, 0x42, 197 | 0x1d, 0x6d, 0x03, 0x00, 0x00, 198 | } 199 | -------------------------------------------------------------------------------- /internal/rpc/accounts/server.go: -------------------------------------------------------------------------------- 1 | // Package accounts represents the accounts RPC server. 2 | package accounts 3 | 4 | import ( 5 | "context" 6 | "crypto/elliptic" 7 | "crypto/x509" 8 | "encoding/hex" 9 | "encoding/pem" 10 | "strings" 11 | 12 | account "github.com/polaris-project/go-polaris/accounts" 13 | "github.com/polaris-project/go-polaris/common" 14 | 15 | accountsProto "github.com/polaris-project/go-polaris/internal/proto/accounts" 16 | ) 17 | 18 | // Server represents a Polaris RPC server. 19 | type Server struct{} 20 | 21 | /* BEGIN EXPORTED METHODS */ 22 | 23 | // NewAccount handles the NewAccount request method. 24 | func (server *Server) NewAccount(ctx context.Context, request *accountsProto.GeneralRequest) (*accountsProto.GeneralResponse, error) { 25 | account, err := account.NewAccount() // Initialize new account 26 | if err != nil { // Check for errors 27 | return &accountsProto.GeneralResponse{}, err // Return found error 28 | } 29 | 30 | err = account.WriteToMemory() // Write account to persistent memory 31 | 32 | if err != nil { // Check for errors 33 | return &accountsProto.GeneralResponse{}, err // Return found error 34 | } 35 | 36 | return &accountsProto.GeneralResponse{Message: hex.EncodeToString(account.Address().Bytes())}, nil // Return account address 37 | } 38 | 39 | // GetAllAccounts handles the GetAllAccounts request method. 40 | func (server *Server) GetAllAccounts(ctx context.Context, request *accountsProto.GeneralRequest) (*accountsProto.GeneralResponse, error) { 41 | accounts := account.GetAllAccounts() // Get all accounts 42 | 43 | var accountStrings []string // Init string buffer 44 | 45 | for _, account := range accounts { // Iterate through accounts 46 | accountStrings = append(accountStrings, hex.EncodeToString(account.Bytes())) // Append hex encoded address 47 | } 48 | 49 | return &accountsProto.GeneralResponse{Message: strings.Join(accountStrings, ", ")}, nil // Return accounts 50 | } 51 | 52 | // AccountFromKey handles the AccountFromKey request method. 53 | func (server *Server) AccountFromKey(ctx context.Context, request *accountsProto.GeneralRequest) (*accountsProto.GeneralResponse, error) { 54 | decodedBytes, err := hex.DecodeString(request.PrivatePublicKey) // Decode hex-encoded private key string 55 | if err != nil { // Check for errors 56 | return &accountsProto.GeneralResponse{}, err // Return found error 57 | } 58 | 59 | block, _ := pem.Decode(decodedBytes) // Decode private key pem 60 | 61 | privateKey, err := x509.ParseECPrivateKey(block.Bytes) // Parse PEM block 62 | if err != nil { // Check for errors 63 | return &accountsProto.GeneralResponse{}, err // Return found error 64 | } 65 | 66 | return &accountsProto.GeneralResponse{Message: hex.EncodeToString(account.AccountFromKey(privateKey).Address().Bytes())}, nil // Return account address 67 | } 68 | 69 | // Address handles the Address request method. 70 | func (server *Server) Address(ctx context.Context, request *accountsProto.GeneralRequest) (*accountsProto.GeneralResponse, error) { 71 | addressBytes, err := hex.DecodeString(request.PrivatePublicKey) // Decode address 72 | if err != nil { // Check for errors 73 | return &accountsProto.GeneralResponse{}, err // Return found error 74 | } 75 | 76 | account, err := account.ReadAccountFromMemory(common.NewAddress(addressBytes)) // Read account 77 | if err != nil { // Check for errors 78 | return &accountsProto.GeneralResponse{}, err // Return found error 79 | } 80 | 81 | return &accountsProto.GeneralResponse{Message: hex.EncodeToString(account.Address().Bytes())}, nil // Return account address 82 | } 83 | 84 | // PublicKey handles the PublicKey request method. 85 | func (server *Server) PublicKey(ctx context.Context, request *accountsProto.GeneralRequest) (*accountsProto.GeneralResponse, error) { 86 | addressBytes, err := hex.DecodeString(request.PrivatePublicKey) // Decode address 87 | if err != nil { // Check for errors 88 | return &accountsProto.GeneralResponse{}, err // Return found error 89 | } 90 | 91 | account, err := account.ReadAccountFromMemory(common.NewAddress(addressBytes)) // Read account 92 | if err != nil { // Check for errors 93 | return &accountsProto.GeneralResponse{}, err // Return found error 94 | } 95 | 96 | publicKeyBytes := elliptic.Marshal(elliptic.P521(), account.PublicKey().X, account.PublicKey().Y) // Marshal public key 97 | 98 | return &accountsProto.GeneralResponse{Message: hex.EncodeToString(publicKeyBytes)}, nil // Return marshaled account public key 99 | } 100 | 101 | // PrivateKey handles the PrivateKey request method. 102 | func (server *Server) PrivateKey(ctx context.Context, request *accountsProto.GeneralRequest) (*accountsProto.GeneralResponse, error) { 103 | addressBytes, err := hex.DecodeString(request.PrivatePublicKey) // Decode address 104 | if err != nil { // Check for errors 105 | return &accountsProto.GeneralResponse{}, err // Return found error 106 | } 107 | 108 | account, err := account.ReadAccountFromMemory(common.NewAddress(addressBytes)) // Read account 109 | if err != nil { // Check for errors 110 | return &accountsProto.GeneralResponse{}, err // Return found error 111 | } 112 | 113 | marshaledPrivateKey, err := x509.MarshalECPrivateKey(account.PrivateKey()) // Marshal private key 114 | if err != nil { // Check for errors 115 | return &accountsProto.GeneralResponse{}, err // Return found error 116 | } 117 | 118 | pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: marshaledPrivateKey}) // Encode to memory 119 | 120 | return &accountsProto.GeneralResponse{Message: hex.EncodeToString(pemEncoded)}, nil // Return hex encoded private key 121 | } 122 | 123 | // String handles the String request method. 124 | func (server *Server) String(ctx context.Context, request *accountsProto.GeneralRequest) (*accountsProto.GeneralResponse, error) { 125 | addressBytes, err := hex.DecodeString(request.PrivatePublicKey) // Decode address 126 | if err != nil { // Check for errors 127 | return &accountsProto.GeneralResponse{}, err // Return found error 128 | } 129 | 130 | account, err := account.ReadAccountFromMemory(common.NewAddress(addressBytes)) // Read account 131 | if err != nil { // Check for errors 132 | return &accountsProto.GeneralResponse{}, err // Return found error 133 | } 134 | 135 | return &accountsProto.GeneralResponse{Message: account.String()}, nil // Return account string 136 | } 137 | 138 | /* END EXPORTED METHODS */ 139 | -------------------------------------------------------------------------------- /internal/rpc/config/server.go: -------------------------------------------------------------------------------- 1 | // Package config represents the config RPC server. 2 | package config 3 | 4 | import ( 5 | "context" 6 | "io/ioutil" 7 | "strings" 8 | 9 | "github.com/polaris-project/go-polaris/common" 10 | 11 | "github.com/polaris-project/go-polaris/config" 12 | configProto "github.com/polaris-project/go-polaris/internal/proto/config" 13 | ) 14 | 15 | // Server represents a Polaris RPC server. 16 | type Server struct{} 17 | 18 | /* BEGIN EXPORTED METHODS */ 19 | 20 | // NewDagConfig handles the NewDagConfig request method. 21 | func (server *Server) NewDagConfig(ctx context.Context, request *configProto.GeneralRequest) (*configProto.GeneralResponse, error) { 22 | config, err := config.NewDagConfigFromGenesis(request.FilePath) // Initialize config 23 | if err != nil { // Check for errors 24 | return &configProto.GeneralResponse{}, err // Return found error 25 | } 26 | 27 | err = config.WriteToMemory() // Write config to memory 28 | 29 | if err != nil { // Check for errors 30 | return &configProto.GeneralResponse{}, err // Return found error 31 | } 32 | 33 | return &configProto.GeneralResponse{Message: config.String()}, nil // Return config 34 | } 35 | 36 | // GetAllConfigs handles the GetAllConfigs request method. 37 | func (server *Server) GetAllConfigs(ctx context.Context, request *configProto.GeneralRequest) (*configProto.GeneralResponse, error) { 38 | files, err := ioutil.ReadDir(common.ConfigDir) // Read all files in config dir 39 | if err != nil { // Check for errors 40 | return &configProto.GeneralResponse{}, err // Return found error 41 | } 42 | 43 | networkNames := []string{} // Init network name buffer 44 | 45 | for _, file := range files { // Iterate through files 46 | networkNames = append(networkNames, strings.Split(strings.Split(file.Name(), "config_")[1], ".json")[0]) // Append network name 47 | } 48 | 49 | return &configProto.GeneralResponse{Message: strings.Join(networkNames, ", ")}, nil // Return network names 50 | } 51 | 52 | // GetConfig handles the GetConfig request method. 53 | func (server *Server) GetConfig(ctx context.Context, request *configProto.GeneralRequest) (*configProto.GeneralResponse, error) { 54 | config, err := config.ReadDagConfigFromMemory(request.Network) // Read config from persistent memory 55 | if err != nil { // Check for errors 56 | return &configProto.GeneralResponse{}, err // Return found error 57 | } 58 | 59 | return &configProto.GeneralResponse{Message: config.String()}, nil // Return config 60 | } 61 | 62 | /* END EXPORTED METHODS */ 63 | -------------------------------------------------------------------------------- /internal/rpc/crypto/server.go: -------------------------------------------------------------------------------- 1 | // Package crypto represents the crypto RPC server. 2 | package crypto 3 | 4 | import ( 5 | "context" 6 | "crypto/ecdsa" 7 | "crypto/elliptic" 8 | "crypto/x509" 9 | "encoding/hex" 10 | "encoding/pem" 11 | 12 | "github.com/polaris-project/go-polaris/crypto" 13 | cryptoProto "github.com/polaris-project/go-polaris/internal/proto/crypto" 14 | ) 15 | 16 | // Server represents a Polaris RPC server. 17 | type Server struct{} 18 | 19 | /* BEGIN EXPORTED METHODS */ 20 | 21 | // AddressFromPrivateKey handles the AddressFromPrivateKey request method. 22 | func (server *Server) AddressFromPrivateKey(ctx context.Context, request *cryptoProto.GeneralRequest) (*cryptoProto.GeneralResponse, error) { 23 | decodedBytes, err := hex.DecodeString(request.PrivatePublicKey) // Decode hex-encoded private key string 24 | if err != nil { // Check for errors 25 | return &cryptoProto.GeneralResponse{}, err // Return found error 26 | } 27 | 28 | block, _ := pem.Decode(decodedBytes) // Decode private key pem 29 | 30 | privateKey, err := x509.ParseECPrivateKey(block.Bytes) // Parse PEM block 31 | if err != nil { // Check for errors 32 | return &cryptoProto.GeneralResponse{}, err // Return found error 33 | } 34 | 35 | return &cryptoProto.GeneralResponse{Message: hex.EncodeToString(crypto.AddressFromPrivateKey(privateKey).Bytes())}, nil // Return address value 36 | } 37 | 38 | // AddressFromPublicKey handles the AddressFromPublicKey request method. 39 | func (server *Server) AddressFromPublicKey(ctx context.Context, request *cryptoProto.GeneralRequest) (*cryptoProto.GeneralResponse, error) { 40 | decodedBytes, err := hex.DecodeString(request.PrivatePublicKey) // Decode hex-encoded private key string 41 | if err != nil { // Check for errors 42 | return &cryptoProto.GeneralResponse{}, err // Return found error 43 | } 44 | 45 | x, y := elliptic.Unmarshal(elliptic.P521(), decodedBytes) // Unmarshal public key 46 | 47 | publicKey := &ecdsa.PublicKey{ 48 | Curve: elliptic.P521(), // Set curve 49 | X: x, // Set x 50 | Y: y, // Set Y 51 | } // Init public key instance 52 | 53 | return &cryptoProto.GeneralResponse{Message: hex.EncodeToString(crypto.AddressFromPublicKey(publicKey).Bytes())}, nil // Return address value 54 | } 55 | 56 | // Sha3 handles the Sha3 request method. 57 | func (server *Server) Sha3(ctx context.Context, request *cryptoProto.GeneralRequest) (*cryptoProto.GeneralResponse, error) { 58 | return &cryptoProto.GeneralResponse{Message: hex.EncodeToString(crypto.Sha3(request.B).Bytes())}, nil // Return hash value 59 | } 60 | 61 | // Sha3n handles the Sha3n request method. 62 | func (server *Server) Sha3n(ctx context.Context, request *cryptoProto.GeneralRequest) (*cryptoProto.GeneralResponse, error) { 63 | return &cryptoProto.GeneralResponse{Message: hex.EncodeToString(crypto.Sha3n(request.B, uint(request.N)).Bytes())}, nil // Return hash value 64 | } 65 | 66 | // Sha3d handles the Sha3d request method. 67 | func (server *Server) Sha3d(ctx context.Context, request *cryptoProto.GeneralRequest) (*cryptoProto.GeneralResponse, error) { 68 | return &cryptoProto.GeneralResponse{Message: hex.EncodeToString(crypto.Sha3d(request.B).Bytes())}, nil // Return hash value 69 | } 70 | 71 | /* END EXPORTED METHODS */ 72 | -------------------------------------------------------------------------------- /internal/rpc/dag/server.go: -------------------------------------------------------------------------------- 1 | // Package dag represents the dag RPC server. 2 | package dag 3 | 4 | import ( 5 | "context" 6 | "encoding/hex" 7 | "strings" 8 | 9 | "github.com/polaris-project/go-polaris/p2p" 10 | 11 | "github.com/polaris-project/go-polaris/common" 12 | "github.com/polaris-project/go-polaris/config" 13 | dagProto "github.com/polaris-project/go-polaris/internal/proto/dag" 14 | "github.com/polaris-project/go-polaris/types" 15 | ) 16 | 17 | // Server represents a Polaris RPC server. 18 | type Server struct{} 19 | 20 | /* BEGIN EXPORTED METHODS */ 21 | 22 | // NewDag handles the NewDag request method. 23 | func (server *Server) NewDag(ctx context.Context, request *dagProto.GeneralRequest) (*dagProto.GeneralResponse, error) { 24 | config, err := config.ReadDagConfigFromMemory(request.Network) // Read config 25 | if err != nil { // Check for errors 26 | return &dagProto.GeneralResponse{}, err // Return found error 27 | } 28 | 29 | dag, err := types.NewDag(config) // Initialize dag 30 | if err != nil { // Check for errors 31 | return &dagProto.GeneralResponse{}, err // Return found error 32 | } 33 | 34 | err = dag.WriteToMemory() // Write dag to persistent memory 35 | 36 | if err != nil { // Check for errors 37 | return &dagProto.GeneralResponse{}, err // Return found error 38 | } 39 | 40 | dag.Close() // Close dag 41 | 42 | return &dagProto.GeneralResponse{Message: string(dag.Bytes())}, nil // Return dag db header string 43 | } 44 | 45 | // MakeGenesis handles the MakeGenesis request method. 46 | func (server *Server) MakeGenesis(ctx context.Context, request *dagProto.GeneralRequest) (*dagProto.GeneralResponse, error) { 47 | dag := (*p2p.WorkingClient.Validator).GetWorkingDag() // Get working dag 48 | 49 | genesisTransactions, err := dag.MakeGenesis() // Make genesis 50 | if err != nil { // Check for errors 51 | return &dagProto.GeneralResponse{}, err // Return found error 52 | } 53 | 54 | var genesisTransactionStrings []string // Init string value buffer 55 | 56 | for _, transaction := range genesisTransactions { // Iterate through genesis transactions 57 | genesisTransactionStrings = append(genesisTransactionStrings, hex.EncodeToString(transaction.Hash.Bytes())) // Append hash 58 | } 59 | 60 | return &dagProto.GeneralResponse{Message: strings.Join(genesisTransactionStrings, ", ")}, nil // Return hashes 61 | } 62 | 63 | // GetTransactionByHash handles the GetTransactionByHash request method. 64 | func (server *Server) GetTransactionByHash(ctx context.Context, request *dagProto.GeneralRequest) (*dagProto.GeneralResponse, error) { 65 | dag := (*p2p.WorkingClient.Validator).GetWorkingDag() // Get working dag 66 | 67 | transactionHashBytes, err := hex.DecodeString(request.TransactionHash) // Decode hash hex value 68 | if err != nil { // Check for errors 69 | return &dagProto.GeneralResponse{}, err // Return found error 70 | } 71 | 72 | transaction, err := dag.GetTransactionByHash(common.NewHash(transactionHashBytes)) // Query tx 73 | if err != nil { // Check for errors 74 | return &dagProto.GeneralResponse{}, err // Return found error 75 | } 76 | 77 | return &dagProto.GeneralResponse{Message: transaction.String()}, nil // Return tx JSON string value 78 | } 79 | 80 | // GetTransactionChildren handles the GetTransactionChildren request method. 81 | func (server *Server) GetTransactionChildren(ctx context.Context, request *dagProto.GeneralRequest) (*dagProto.GeneralResponse, error) { 82 | dag := (*p2p.WorkingClient.Validator).GetWorkingDag() // Get working dag 83 | 84 | transactionHashBytes, err := hex.DecodeString(request.TransactionHash) // Decode hash hex value 85 | if err != nil { // Check for errors 86 | return &dagProto.GeneralResponse{}, err // Return found error 87 | } 88 | 89 | children, err := dag.GetTransactionChildren(common.NewHash(transactionHashBytes)) // Query tx children 90 | if err != nil { // Check for errors 91 | return &dagProto.GeneralResponse{}, err // Return found error 92 | } 93 | 94 | var childHashStrings []string // Init string value buffer 95 | 96 | for _, transaction := range children { // Iterate through children 97 | childHashStrings = append(childHashStrings, hex.EncodeToString(transaction.Hash.Bytes())) // Append hash 98 | } 99 | 100 | return &dagProto.GeneralResponse{Message: strings.Join(childHashStrings, ", ")}, nil // Return child hashes 101 | } 102 | 103 | // GetTransactionsByAddress handles the GetTransactionByAddress request method. 104 | func (server *Server) GetTransactionsByAddress(ctx context.Context, request *dagProto.GeneralRequest) (*dagProto.GeneralResponse, error) { 105 | dag := (*p2p.WorkingClient.Validator).GetWorkingDag() // Get working dag 106 | 107 | addressBytes, err := hex.DecodeString(request.Address) // Decode address value 108 | if err != nil { // Check for errors 109 | return &dagProto.GeneralResponse{}, err // Return found error 110 | } 111 | 112 | transactions, err := dag.GetTransactionsByAddress(common.NewAddress(addressBytes)) // Query tx 113 | if err != nil { // Check for errors 114 | return &dagProto.GeneralResponse{}, err // Return found error 115 | } 116 | 117 | var hashStrings []string // Init string value buffer 118 | 119 | for _, transaction := range transactions { // Iterate through transactions 120 | hashStrings = append(hashStrings, hex.EncodeToString(transaction.Hash.Bytes())) // Append hash 121 | } 122 | 123 | return &dagProto.GeneralResponse{Message: strings.Join(hashStrings, ", ")}, nil // Return hashes 124 | } 125 | 126 | // GetTransactionsBySender handles the GetTransactionBySender request method. 127 | func (server *Server) GetTransactionsBySender(ctx context.Context, request *dagProto.GeneralRequest) (*dagProto.GeneralResponse, error) { 128 | dag := (*p2p.WorkingClient.Validator).GetWorkingDag() // Get working dag 129 | 130 | addressBytes, err := hex.DecodeString(request.Address) // Decode address hex value 131 | if err != nil { // Check for errors 132 | return &dagProto.GeneralResponse{}, err // Return found error 133 | } 134 | 135 | transactions, err := dag.GetTransactionsBySender(common.NewAddress(addressBytes)) // Query tx 136 | if err != nil { // Check for errors 137 | return &dagProto.GeneralResponse{}, err // Return found error 138 | } 139 | 140 | var hashStrings []string // Init string value buffer 141 | 142 | for _, transaction := range transactions { // Iterate through transactions 143 | hashStrings = append(hashStrings, hex.EncodeToString(transaction.Hash.Bytes())) // Append hash 144 | } 145 | 146 | return &dagProto.GeneralResponse{Message: strings.Join(hashStrings, ", ")}, nil // Return hashes 147 | } 148 | 149 | // GetBestTransaction handles the GetBestTransaction request method. 150 | func (server *Server) GetBestTransaction(ctx context.Context, request *dagProto.GeneralRequest) (*dagProto.GeneralResponse, error) { 151 | dag := (*p2p.WorkingClient.Validator).GetWorkingDag() // Get working dag 152 | 153 | bestTransaction, err := dag.GetBestTransaction() // Get best transaction 154 | if err != nil { // Check for errors 155 | return &dagProto.GeneralResponse{}, err // Return found error 156 | } 157 | 158 | return &dagProto.GeneralResponse{Message: hex.EncodeToString(bestTransaction.Hash.Bytes())}, nil // Return hash 159 | } 160 | 161 | // CalculateAddressBalance handles the CalculateAddressBalance request method. 162 | func (server *Server) CalculateAddressBalance(ctx context.Context, request *dagProto.GeneralRequest) (*dagProto.GeneralResponse, error) { 163 | dag := (*p2p.WorkingClient.Validator).GetWorkingDag() // Get working dag 164 | 165 | addressBytes, err := hex.DecodeString(request.Address) // Decode address hex value 166 | if err != nil { // Check for errors 167 | return &dagProto.GeneralResponse{}, err // Return found error 168 | } 169 | 170 | balance, err := dag.CalculateAddressBalance(common.NewAddress(addressBytes)) // Calculate balance 171 | if err != nil { // Check for errors 172 | return &dagProto.GeneralResponse{}, err // Return found error 173 | } 174 | 175 | return &dagProto.GeneralResponse{Message: balance.String()}, nil // Return balance 176 | } 177 | 178 | /* END EXPORTED METHODS */ 179 | -------------------------------------------------------------------------------- /internal/rpc/transaction/server.go: -------------------------------------------------------------------------------- 1 | // Package transaction represents the transaction RPC server. 2 | package transaction 3 | 4 | import ( 5 | "context" 6 | "encoding/hex" 7 | "errors" 8 | "fmt" 9 | "math/big" 10 | "strconv" 11 | 12 | "github.com/polaris-project/go-polaris/accounts" 13 | "github.com/polaris-project/go-polaris/common" 14 | transactionProto "github.com/polaris-project/go-polaris/internal/proto/transaction" 15 | "github.com/polaris-project/go-polaris/p2p" 16 | "github.com/polaris-project/go-polaris/types" 17 | ) 18 | 19 | var ( 20 | // ErrNilHashRequest defines an error describing a TransactionHash length of 0. 21 | ErrNilHashRequest = errors.New("request did not contain a valid transaction hash") 22 | 23 | // ErrInvalidHashRequest defines an error describing a MessageHash length >||< common.HashLength. 24 | ErrInvalidHashRequest = errors.New("request did not contain a valid message hash") 25 | ) 26 | 27 | // Server represents a Polaris RPC server. 28 | type Server struct{} 29 | 30 | /* BEGIN EXPORTED METHODS */ 31 | 32 | // NewTransaction handles the NewTransaction request method. 33 | func (server *Server) NewTransaction(ctx context.Context, request *transactionProto.GeneralRequest) (*transactionProto.GeneralResponse, error) { 34 | senderBytes, err := hex.DecodeString(request.Address) // Decode sender address hex-encoded string value 35 | if err != nil { // Check for errors 36 | return &transactionProto.GeneralResponse{}, err // Return found error 37 | } 38 | 39 | recipientBytes, err := hex.DecodeString(request.Address2) // Decode recipient address hex-encoded string value 40 | if err != nil { // Check for errors 41 | return &transactionProto.GeneralResponse{}, err // Return found error 42 | } 43 | 44 | amount, _, err := big.ParseFloat(string(request.Amount), 10, 18, big.ToNearestEven) // Parse amount value 45 | if err != nil { // Check for errors 46 | return &transactionProto.GeneralResponse{}, err // Return found error 47 | } 48 | 49 | var parentHashes []common.Hash // Init parent hash buffer 50 | 51 | for _, parentHashString := range request.TransactionHash { // Iterate through parent hashes 52 | parentHashBytes, err := hex.DecodeString(parentHashString) // Decode hash string value 53 | if err != nil { // Check for errors 54 | return &transactionProto.GeneralResponse{}, err // Return found error 55 | } 56 | 57 | parentHashes = append(parentHashes, common.NewHash(parentHashBytes)) // Append hash 58 | } 59 | 60 | transaction := types.NewTransaction(request.Nonce, amount, common.NewAddress(senderBytes), common.NewAddress(recipientBytes), parentHashes, request.GasLimit, big.NewInt(int64(request.GasPrice)), request.Payload) // Initialize transaction 61 | 62 | if err != nil { // Check for errors 63 | return &transactionProto.GeneralResponse{}, err // Return found error 64 | } 65 | 66 | err = transaction.WriteToMemory() // Write transaction to mempool 67 | 68 | if err != nil { // Check for errors 69 | return &transactionProto.GeneralResponse{}, err // Return found error 70 | } 71 | 72 | return &transactionProto.GeneralResponse{Message: hex.EncodeToString(transaction.Hash.Bytes())}, nil // Return transaction hash string value 73 | } 74 | 75 | // CalculateTotalValue handles the CalculateTotalValue request method. 76 | func (server *Server) CalculateTotalValue(ctx context.Context, request *transactionProto.GeneralRequest) (*transactionProto.GeneralResponse, error) { 77 | if len(request.TransactionHash) == 0 { // Check nothing to read 78 | return &transactionProto.GeneralResponse{}, ErrNilHashRequest // Return error 79 | } 80 | 81 | transactionHashBytes, err := hex.DecodeString(request.TransactionHash[0]) // Get transaction hash byte value 82 | if err != nil { // Check for errors 83 | return &transactionProto.GeneralResponse{}, err // Return found error 84 | } 85 | 86 | transaction, err := types.ReadTransactionFromMemory(common.NewHash(transactionHashBytes)) // Read transaction 87 | if err != nil { // Check for errors 88 | return &transactionProto.GeneralResponse{}, err // Return found error 89 | } 90 | 91 | return &transactionProto.GeneralResponse{Message: transaction.CalculateTotalValue().String()}, nil // Return total value 92 | } 93 | 94 | // SignTransaction handles the SignTransaction request method. 95 | func (server *Server) SignTransaction(ctx context.Context, request *transactionProto.GeneralRequest) (*transactionProto.GeneralResponse, error) { 96 | if len(request.TransactionHash) == 0 { // Check nothing to read 97 | return &transactionProto.GeneralResponse{}, ErrNilHashRequest // Return error 98 | } 99 | 100 | transactionHashBytes, err := hex.DecodeString(request.TransactionHash[0]) // Get transaction hash byte value 101 | if err != nil { // Check for errors 102 | return &transactionProto.GeneralResponse{}, err // Return found error 103 | } 104 | 105 | transaction, err := types.ReadTransactionFromMemory(common.NewHash(transactionHashBytes)) // Read transaction 106 | if err != nil { // Check for errors 107 | return &transactionProto.GeneralResponse{}, err // Return found error 108 | } 109 | 110 | account, err := accounts.ReadAccountFromMemory(common.NewAddress(transaction.Sender.Bytes())) // Open account 111 | if err != nil { // Check for errors 112 | return &transactionProto.GeneralResponse{}, err // Return found error 113 | } 114 | 115 | err = types.SignTransaction(transaction, account.PrivateKey()) // Sign transaction 116 | 117 | if err != nil { // Check for errors 118 | return &transactionProto.GeneralResponse{}, err // Return found error 119 | } 120 | 121 | err = transaction.WriteToMemory() // Write transaction to mempool 122 | 123 | if err != nil { // Check for errors 124 | return &transactionProto.GeneralResponse{}, err // Return found error 125 | } 126 | 127 | return &transactionProto.GeneralResponse{Message: hex.EncodeToString(transaction.Hash.Bytes())}, nil // Return signature 128 | } 129 | 130 | // Publish handles the Publish request method. 131 | func (server *Server) Publish(ctx context.Context, request *transactionProto.GeneralRequest) (*transactionProto.GeneralResponse, error) { 132 | if len(request.TransactionHash) == 0 { // Check nothing to read 133 | return &transactionProto.GeneralResponse{}, ErrNilHashRequest // Return error 134 | } 135 | 136 | transactionHashBytes, err := hex.DecodeString(request.TransactionHash[0]) // Get transaction hash byte value 137 | if err != nil { // Check for errors 138 | return &transactionProto.GeneralResponse{}, err // Return found error 139 | } 140 | 141 | transaction, err := types.ReadTransactionFromMemory(common.NewHash(transactionHashBytes)) // Read transaction 142 | if err != nil { // Check for errors 143 | return &transactionProto.GeneralResponse{}, err // Return found error 144 | } 145 | 146 | err = (*p2p.WorkingClient.Validator).GetWorkingDag().AddTransaction(transaction) // Add transaction 147 | 148 | if err != nil && err != types.ErrDuplicateTransaction { // Check for errors (other than duplicate transaction) 149 | return &transactionProto.GeneralResponse{}, err // Return found error 150 | } 151 | 152 | publishContext, cancel := context.WithCancel(ctx) // Get context 153 | 154 | defer cancel() // Cancel 155 | 156 | err = p2p.WorkingClient.PublishTransaction(publishContext, transaction) // Publish transaction 157 | 158 | if err != nil { // Check for errors 159 | return &transactionProto.GeneralResponse{}, err // Return found error 160 | } 161 | 162 | return &transactionProto.GeneralResponse{Message: fmt.Sprintf("published transaction %s successfully", hex.EncodeToString(transaction.Hash.Bytes()))}, nil // Return success 163 | } 164 | 165 | // SignMessage handles the SignMessage request method. 166 | func (server *Server) SignMessage(ctx context.Context, request *transactionProto.GeneralRequest) (*transactionProto.GeneralResponse, error) { 167 | senderBytes, err := hex.DecodeString(request.Address) // Decode sender address hex-encoded string value 168 | if err != nil { // Check for errors 169 | return &transactionProto.GeneralResponse{}, err // Return found error 170 | } 171 | 172 | account, err := accounts.ReadAccountFromMemory(common.NewAddress(senderBytes)) // Open account 173 | if err != nil { // Check for errors 174 | return &transactionProto.GeneralResponse{}, err // Return found error 175 | } 176 | 177 | if len(request.Payload) != common.HashLength { // Check invalid message hash 178 | return &transactionProto.GeneralResponse{}, ErrInvalidHashRequest 179 | } 180 | 181 | signature, err := types.SignMessage(common.NewHash(request.Payload), account.PrivateKey()) // Sign message 182 | if err != nil { // Check for errors 183 | return &transactionProto.GeneralResponse{}, err // Return found error 184 | } 185 | 186 | return &transactionProto.GeneralResponse{Message: signature.String()}, nil // Retrun signature 187 | } 188 | 189 | // Verify handles the Verify request method. 190 | func (server *Server) Verify(ctx context.Context, request *transactionProto.GeneralRequest) (*transactionProto.GeneralResponse, error) { 191 | transactionHashBytes, err := hex.DecodeString(request.TransactionHash[0]) // Get transaction hash byte value 192 | if err != nil { // Check for errors 193 | return &transactionProto.GeneralResponse{}, err // Return found error 194 | } 195 | 196 | transaction, err := types.ReadTransactionFromMemory(common.NewHash(transactionHashBytes)) // Read transaction 197 | if err != nil { // Check for errors 198 | return &transactionProto.GeneralResponse{}, err // Return found error 199 | } 200 | 201 | return &transactionProto.GeneralResponse{Message: strconv.FormatBool(transaction.Signature.Verify(transaction.Sender))}, nil // Return is valid 202 | } 203 | 204 | // String handles the String request method. 205 | func (server *Server) String(ctx context.Context, request *transactionProto.GeneralRequest) (*transactionProto.GeneralResponse, error) { 206 | transactionHashBytes, err := hex.DecodeString(request.TransactionHash[0]) // Get transaction hash byte value 207 | if err != nil { // Check for errors 208 | return &transactionProto.GeneralResponse{}, err // Return found error 209 | } 210 | 211 | transaction, err := types.ReadTransactionFromMemory(common.NewHash(transactionHashBytes)) // Read transaction 212 | if err != nil { // Check for errors 213 | return &transactionProto.GeneralResponse{}, err // Return found error 214 | } 215 | 216 | return &transactionProto.GeneralResponse{Message: transaction.String()}, nil // Return tx string value 217 | } 218 | 219 | /* END EXPORTED METHODS */ 220 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Package main is the main polaris mode entry point. 2 | package main 3 | 4 | import ( 5 | "bytes" 6 | "context" 7 | "errors" 8 | "flag" 9 | "fmt" 10 | "net" 11 | "os" 12 | "os/signal" 13 | "path/filepath" 14 | "strconv" 15 | "syscall" 16 | "time" 17 | 18 | routed "github.com/libp2p/go-libp2p/p2p/host/routed" 19 | 20 | "github.com/juju/loggo" 21 | "github.com/juju/loggo/loggocolor" 22 | 23 | "github.com/polaris-project/go-polaris/config" 24 | "github.com/polaris-project/go-polaris/types" 25 | 26 | "github.com/polaris-project/go-polaris/common" 27 | "github.com/polaris-project/go-polaris/p2p" 28 | "github.com/polaris-project/go-polaris/validator" 29 | 30 | "github.com/polaris-project/go-polaris/api" 31 | "github.com/polaris-project/go-polaris/cli" 32 | ) 33 | 34 | // errNoBootstrap defines an invalid bootstrap value error. 35 | var errNoBootstrap = errors.New("bootstrap failed: was expecting a bootstrap peer address, got 'localhost' (must be able to bootstrap dag config if no config exists locally)") 36 | 37 | var ( 38 | dataDirFlag = flag.String("data-dir", common.DataDir, "performs all node I/O operations in a given data directory") // Init data dir flag 39 | nodePortFlag = flag.Int("node-port", p2p.NodePort, "run p2p host on given port") // Init node port flag 40 | networkFlag = flag.String("network", "main_net", "run node on given network") // Init network flag 41 | bootstrapNodeAddressFlag = flag.String("bootstrap-address", p2p.BootstrapNodes[0], "manually prefer a given bootstrap node for all dht-related operations") // Init bootstrap node flag 42 | silencedFlag = flag.Bool("silence", false, "silence logs") // Init silence logs flag 43 | disableColoredOutputFlag = flag.Bool("no-colors", false, "disable colored output") // Init disable colored output flag 44 | disableLogFileFlag = flag.Bool("no-logs", false, "disable writing logs to a logs.txt file") // Init disable logs file flag 45 | debugFlag = flag.Bool("debug", false, "force node to log in debug mode") // Init debug flag 46 | disableAutoGenesisFlag = flag.Bool("no-genesis", false, "disables the automatic creation of a genesis transaction set if no dag can be bootstrapped") // Init disable auto genesis flag 47 | apiPortFlag = flag.Int("api-port", 8000, "incrementally start APIs on given port (i.e. RPC = 8080, HTTP = 8081, etc...)") // Init API port flag 48 | disableAPIFlag = flag.Bool("disable-api", false, "disable API") // Init disable API flag 49 | terminalFlag = flag.Bool("terminal", false, "launch with terminal") // Init terminal flag 50 | rpcPortFlag = flag.Int("rpc-port", 8000, "port to connect to via RPC") // Init RPC port flag 51 | rpcAddrFlag = flag.String("rpc-address", "localhost", "RPC addr to connect to") // Init RPC addr flag 52 | 53 | logger = loggo.GetLogger("") // Get logger 54 | 55 | logFile *os.File // Log file 56 | dag *types.Dag // Dag reference 57 | 58 | intermittentSyncContext, cancelIntermittent = context.WithCancel(context.Background()) // Get background sync context 59 | ) 60 | 61 | // Main starts all necessary Polaris services, and parses command line arguments. 62 | func main() { 63 | flag.Parse() // Parse flags 64 | 65 | err := setUserParams() // Set common params 66 | if err != nil { // Check for errors 67 | logger.Criticalf("main panicked: %s", err.Error()) // Log pending panic 68 | 69 | os.Exit(1) // Panic 70 | } 71 | 72 | defer dag.Close() // Close dag 73 | defer logFile.Close() // Close log file 74 | 75 | if !checkNodeAlreadyUp() { // Check no node already up 76 | defer cancelIntermittent() // Cancel 77 | 78 | err = startNode() // Start node 79 | 80 | if err != nil { // Check for errors 81 | logger.Criticalf("main panicked: %s", err.Error()) // Log pending panic 82 | 83 | os.Exit(1) // Panic 84 | } 85 | } 86 | 87 | if *terminalFlag { // Check should launch terminal 88 | cli.NewTerminal(uint(*rpcPortFlag), *rpcAddrFlag) // Initialize terminal 89 | } 90 | } 91 | 92 | // setUserParams sets the default values in the common, p2p package. 93 | func setUserParams() error { 94 | common.DataDir = filepath.FromSlash(*dataDirFlag) // Set data dir 95 | 96 | p2p.NodePort = *nodePortFlag // Set node port 97 | 98 | if !*disableColoredOutputFlag { // Check can log colored output 99 | if !*disableLogFileFlag { // Check can have log files 100 | err := common.CreateDirIfDoesNotExist(filepath.FromSlash(common.LogsDir)) // Create log dir 101 | if err != nil { // Check for errors 102 | return err // Return found error 103 | } 104 | 105 | logFile, err = os.OpenFile(filepath.FromSlash(fmt.Sprintf("%s/logs_%s.txt", common.LogsDir, time.Now().Format("2006-01-02_15-04-05"))), os.O_RDWR|os.O_CREATE|os.O_APPEND, 0o666) // Create log file 106 | 107 | if err != nil { // Check for errors 108 | return err // Return found error 109 | } 110 | 111 | loggo.ReplaceDefaultWriter(loggocolor.NewWriter(os.Stderr)) // Enabled colored output 112 | 113 | loggo.RegisterWriter("logs", loggo.NewSimpleWriter(logFile, loggo.DefaultFormatter)) // Register file writer 114 | } else { 115 | loggo.ReplaceDefaultWriter(loggocolor.NewWriter(os.Stderr)) // Enabled colored output 116 | } 117 | } 118 | 119 | if *silencedFlag { // Check should silence 120 | loggo.ResetLogging() // Silence 121 | } 122 | 123 | return nil // No error occurred, return nil. 124 | } 125 | 126 | // startNode creates a new libp2p host, and connects to the bootstrapped dht. 127 | func startNode() error { 128 | ctx, cancel := context.WithCancel(context.Background()) // Init context 129 | 130 | defer cancel() // Cancel context 131 | 132 | host, err := p2p.NewHost(ctx, p2p.NodePort) // Initialize host 133 | if err != nil { // Check for errors 134 | return err // Return found error 135 | } 136 | 137 | if *bootstrapNodeAddressFlag == p2p.BootstrapNodes[0] { // Check bootstrap node addr has not been set 138 | *bootstrapNodeAddressFlag = p2p.GetBestBootstrapAddress(context.Background(), host) // Get best bootstrap node 139 | } 140 | 141 | dagConfig, needsSync, err := getDagConfig(ctx, host) // Get dag config 142 | if err != nil { // Check for errors 143 | return err // Return found error 144 | } 145 | 146 | dag, err = types.NewDag(dagConfig) // Init dag 147 | 148 | if err != nil { // Check for errors 149 | return err // Return found error 150 | } 151 | 152 | c := make(chan os.Signal) // Get control c 153 | 154 | signal.Notify(c, os.Interrupt, syscall.SIGTERM) // Notify 155 | 156 | go func() { 157 | <-c // Wait for ^c 158 | 159 | cancelIntermittent() // Cancel intermittent sync 160 | cancel() // Cancel 161 | 162 | err = dag.Close() // Close dag 163 | 164 | if err != nil { // Check for errors 165 | logger.Criticalf("dag close errored: %s", err.Error()) // Return found error 166 | } 167 | 168 | logFile.Close() // Close log file 169 | 170 | os.Exit(0) // Exit 171 | }() 172 | 173 | validator := validator.Validator(validator.NewBeaconDagValidator(dagConfig, dag)) // Initialize validator 174 | 175 | client := p2p.NewClient(*networkFlag, &validator) // Initialize client 176 | 177 | needsSync, err = startInitialSync(ctx, needsSync, client) // Start initial sync 178 | 179 | if err != nil { // Check for errors 180 | return err // Return found error 181 | } 182 | 183 | p2p.WorkingClient = client // Set working client 184 | 185 | err = p2p.WorkingClient.StartServingStreams(*networkFlag) // Start handlers 186 | 187 | if err != nil { // Check for errors 188 | return err // Return found error 189 | } 190 | 191 | if !*disableAPIFlag { // Check API enabled 192 | err = startServingRPC(ctx, dagConfig.Identifier) // Start serving RPC 193 | 194 | if err != nil { // Check for errors 195 | return err // Return found error 196 | } 197 | } 198 | 199 | if needsSync { // Check must sync 200 | err = p2p.WorkingClient.SyncDag(ctx) // Sync network 201 | 202 | if err != nil { // Check for errors 203 | return err // Return found error 204 | } 205 | } 206 | 207 | if !*terminalFlag { // Check no terminal 208 | p2p.WorkingClient.StartIntermittentSync(intermittentSyncContext, 120*time.Second) // Sync every 120 seconds 209 | } else { 210 | go p2p.WorkingClient.StartIntermittentSync(intermittentSyncContext, 120*time.Second) // Sync every 120 seconds 211 | } 212 | 213 | return nil // No error occurred, return nil 214 | } 215 | 216 | // startInitialSync starts an initial sync with a given client. 217 | func startInitialSync(ctx context.Context, needsSync bool, client *p2p.Client) (bool, error) { 218 | localBestTransaction, _ := (*client.Validator).GetWorkingDag().GetBestTransaction() // Get local best transaction 219 | 220 | remoteBestTransactionHash, _ := client.RequestBestTransactionHash(ctx, 64) // Request best tx hash 221 | 222 | if !bytes.Equal(localBestTransaction.Hash.Bytes(), remoteBestTransactionHash.Bytes()) && !localBestTransaction.Hash.IsNil() && !remoteBestTransactionHash.IsNil() { // Check up to date 223 | needsSync = true // Set does need sync 224 | } 225 | 226 | if localBestTransaction.Hash.IsNil() && remoteBestTransactionHash.IsNil() { // Check nil genesis 227 | _, err := (*client.Validator).GetWorkingDag().MakeGenesis() // Make genesis 228 | if err != nil { // Check for errors 229 | return false, err // Return found error 230 | } 231 | } 232 | 233 | return needsSync, nil // No error occurred, return nil 234 | } 235 | 236 | // startServingRPC starts the RPC node interface. 237 | func startServingRPC(ctx context.Context, network string) error { 238 | rpcAPI, err := api.NewRPCAPI(network, fmt.Sprintf(":%d", *apiPortFlag)) // Initialize API 239 | if err != nil { // Check for errors 240 | return err // Return found error 241 | } 242 | 243 | go rpcAPI.StartServing(ctx) // Start serving 244 | 245 | return nil // No error occurred, return nil 246 | } 247 | 248 | // getDagConfig attempts to read an existing dag config, or bootstrap one. 249 | func getDagConfig(ctx context.Context, host *routed.RoutedHost) (*config.DagConfig, bool, error) { 250 | needsSync := false // Init buffer 251 | 252 | dagConfig, err := config.ReadDagConfigFromMemory(*networkFlag) // Read config 253 | 254 | if err != nil || dagConfig == nil { // Check no existing dag config 255 | if *bootstrapNodeAddressFlag == "localhost" { // Check no bootstrap node 256 | return &config.DagConfig{}, needsSync, errNoBootstrap // Return error 257 | } 258 | 259 | dagConfig, err = p2p.BootstrapConfig(ctx, host, *bootstrapNodeAddressFlag, *networkFlag) // Bootstrap dag config 260 | 261 | if err != nil { // Check for errors 262 | return &config.DagConfig{}, needsSync, err // Return found error 263 | } 264 | 265 | needsSync = true // Set does need sync 266 | } 267 | 268 | return dagConfig, needsSync, nil // Return found config 269 | } 270 | 271 | // checkNodeAlreadyUp checks if a node RPC API is already running. 272 | func checkNodeAlreadyUp() bool { 273 | ln, err := net.Listen("tcp", ":"+strconv.Itoa(*apiPortFlag)) // Attempt to listen 274 | if err != nil { 275 | return true // Already running 276 | } 277 | 278 | ln.Close() // Close 279 | 280 | return false // Not running 281 | } 282 | -------------------------------------------------------------------------------- /p2p/p2p.go: -------------------------------------------------------------------------------- 1 | // Package p2p provides common peer-to-peer communications helper methods and definitions. 2 | package p2p 3 | 4 | import ( 5 | "bufio" 6 | "bytes" 7 | "context" 8 | "crypto/ecdsa" 9 | "crypto/elliptic" 10 | "crypto/rand" 11 | "crypto/x509" 12 | "encoding/pem" 13 | "errors" 14 | "fmt" 15 | "io/ioutil" 16 | "os" 17 | "path/filepath" 18 | "strconv" 19 | "strings" 20 | "time" 21 | 22 | "github.com/libp2p/go-libp2p/p2p/protocol/ping" 23 | 24 | "github.com/libp2p/go-libp2p" 25 | crypto "github.com/libp2p/go-libp2p-crypto" 26 | host "github.com/libp2p/go-libp2p-host" 27 | dht "github.com/libp2p/go-libp2p-kad-dht" 28 | peer "github.com/libp2p/go-libp2p-peer" 29 | peerstore "github.com/libp2p/go-libp2p-peerstore" 30 | protocol "github.com/libp2p/go-libp2p-protocol" 31 | routed "github.com/libp2p/go-libp2p/p2p/host/routed" 32 | multiaddr "github.com/multiformats/go-multiaddr" 33 | "github.com/polaris-project/go-polaris/common" 34 | "github.com/polaris-project/go-polaris/config" 35 | ) 36 | 37 | // Stream header protocol definitions 38 | const ( 39 | PublishTransaction StreamHeaderProtocol = iota 40 | 41 | RequestConfig 42 | 43 | RequestBestTransaction 44 | 45 | RequestTransaction 46 | 47 | RequestGenesisHash 48 | 49 | RequestChildHashes 50 | ) 51 | 52 | var ( 53 | // StreamHeaderProtocolNames represents all stream header protocol names. 54 | StreamHeaderProtocolNames = []string{ 55 | "pub_transaction", 56 | "req_config", 57 | "req_best_transaction", 58 | "req_transaction", 59 | "req_genesis_hash", 60 | "req_transaction_children_hashes", 61 | } 62 | 63 | // BootstrapNodes represents all default bootstrap nodes on the given network. 64 | BootstrapNodes = []string{ 65 | "/ip4/108.41.124.60/tcp/3030/ipfs/QmWy8fZPX4hnTmXtFzgUTa8ZGceHhdhUEj3wonj1r3bMEG", 66 | } 67 | 68 | // WorkingHost is the current global routed host. 69 | WorkingHost *routed.RoutedHost 70 | 71 | // WorkingClient is the current global client. 72 | WorkingClient *Client 73 | 74 | // NodePort is the current node port 75 | NodePort = 3030 76 | 77 | // ErrTimedOut is an error definition representing a timeout. 78 | ErrTimedOut = errors.New("timed out") 79 | ) 80 | 81 | // StreamHeaderProtocol represents the stream protocol type enum. 82 | type StreamHeaderProtocol int 83 | 84 | /* BEGIN EXPORTED METHODS */ 85 | 86 | // NewHost initializes a new libp2p host with the given context. 87 | func NewHost(ctx context.Context, port int) (*routed.RoutedHost, error) { 88 | peerIdentity, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) // Generate private key 89 | if err != nil { // Check for errors 90 | return nil, err // Return found error 91 | } 92 | 93 | if _, err := os.Stat(filepath.FromSlash(fmt.Sprintf("%s/identity.pem", common.PeerIdentityDir))); err == nil { // Check existing p2p identity 94 | data, err := ioutil.ReadFile(filepath.FromSlash(fmt.Sprintf("%s/identity.pem", common.PeerIdentityDir))) // Read identity 95 | if err != nil { // Check for errors 96 | return nil, err // Return found error 97 | } 98 | 99 | block, _ := pem.Decode(data) // Decode pem 100 | 101 | peerIdentity, err = x509.ParseECPrivateKey(block.Bytes) // Parse private key pem block 102 | 103 | if err != nil { // Check for errors 104 | return nil, err // Return found error 105 | } 106 | } else { // No existing p2p identity 107 | x509Encoded, err := x509.MarshalECPrivateKey(peerIdentity) // Marshal identity 108 | if err != nil { // Check for errors 109 | return nil, err // Return found error 110 | } 111 | 112 | pemEncoded := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: x509Encoded}) // Encode to pem 113 | 114 | err = common.CreateDirIfDoesNotExist(common.PeerIdentityDir) // Create identity dir if it doesn't already exist 115 | 116 | if err != nil { // Check for errors 117 | return nil, err // Return found error 118 | } 119 | 120 | err = ioutil.WriteFile(filepath.FromSlash(fmt.Sprintf("%s/identity.pem", common.PeerIdentityDir)), pemEncoded, 0o644) // Write identity 121 | 122 | if err != nil { // Check for errors 123 | return nil, err // Return found error 124 | } 125 | } 126 | 127 | privateKey, _, err := crypto.ECDSAKeyPairFromKey(peerIdentity) // Get privateKey key 128 | if err != nil { // Check for errors 129 | return nil, err // Return found error 130 | } 131 | 132 | host, err := libp2p.New(ctx, libp2p.NATPortMap(), libp2p.ListenAddrStrings("/ip4/0.0.0.0/tcp/"+strconv.Itoa(port), "/ip6/::1/tcp/"+strconv.Itoa(port)), libp2p.Identity(privateKey)) // Initialize libp2p host 133 | if err != nil { // Check for errors 134 | return nil, err // Return found error 135 | } 136 | 137 | dht, err := BootstrapDht(ctx, host) // Bootstrap dht 138 | if err != nil { // Check for errors 139 | return nil, err // Return found error 140 | } 141 | 142 | routedHost := routed.Wrap(host, dht) // Initialize routed host 143 | 144 | WorkingHost = routedHost // Set routed host 145 | 146 | logger.Infof("initialized host with ID: %s on listening port: %s with multiaddr: %s", host.ID().Pretty(), strconv.Itoa(port), host.Addrs()[0].String()) // Log init host 147 | 148 | return WorkingHost, nil // Return working routed host 149 | } 150 | 151 | // GetBestBootstrapAddress attempts to fetch the best bootstrap node. 152 | func GetBestBootstrapAddress(ctx context.Context, host *routed.RoutedHost) string { 153 | for _, bootstrapAddress := range BootstrapNodes { // Iterate through bootstrap nodes 154 | multiaddr, err := multiaddr.NewMultiaddr(bootstrapAddress) // Parse address 155 | if err != nil { // Check for errors 156 | continue // Continue 157 | } 158 | 159 | peerID, err := peer.IDB58Decode(strings.Split(bootstrapAddress, "ipfs/")[1]) // Get peer ID 160 | if err != nil { // Check for errors 161 | continue // Continue 162 | } 163 | 164 | host.Peerstore().AddAddr(peerID, multiaddr, 10*time.Second) // Add bootstrap peer 165 | 166 | peerInfo, err := peerstore.InfoFromP2pAddr(multiaddr) // Get peer info 167 | if err != nil { // Check for errors 168 | continue // Continue 169 | } 170 | 171 | bootstrapCheckCtx, cancel := context.WithCancel(ctx) // Get context 172 | 173 | err = host.Connect(bootstrapCheckCtx, *peerInfo) // Connect to peer 174 | 175 | if err != nil { // Check for errors 176 | cancel() // Cancel 177 | continue // Continue 178 | } 179 | 180 | _, err = ping.Ping(bootstrapCheckCtx, host, peerID) // Attempt to ping 181 | 182 | if err == nil { // Check no errors 183 | cancel() // Cancel 184 | return bootstrapAddress // Return bootstrap address 185 | } 186 | 187 | cancel() // Cancel 188 | } 189 | 190 | return "localhost" // Return localhost 191 | } 192 | 193 | // BootstrapConfig bootstraps a dag config to the list of bootstrap nodes. 194 | func BootstrapConfig(ctx context.Context, host *routed.RoutedHost, bootstrapAddress, network string) (*config.DagConfig, error) { 195 | peerID, err := peer.IDB58Decode(strings.Split(bootstrapAddress, "ipfs/")[1]) // Get peer ID 196 | if err != nil { // Check for errors 197 | return &config.DagConfig{}, err // Return found error 198 | } 199 | 200 | readCtx, cancel := context.WithCancel(ctx) // Get context 201 | 202 | stream, err := (*host).NewStream(readCtx, peerID, protocol.ID(GetStreamHeaderProtocolPath(network, RequestConfig))) // Initialize new stream 203 | if err != nil { // Check for errors 204 | cancel() // Cancel 205 | 206 | return &config.DagConfig{}, err // Return found error 207 | } 208 | 209 | reader := bufio.NewReader(stream) // Initialize reader from stream 210 | 211 | dagConfigBytes, err := readAsync(reader) // Read async 212 | if err != nil { // Check for errors 213 | cancel() // Cancel 214 | 215 | return &config.DagConfig{}, err // Return found error 216 | } 217 | 218 | deserializedConfig := config.DagConfigFromBytes(dagConfigBytes) // Deserialize 219 | 220 | if deserializedConfig == nil { // Check nil 221 | cancel() // Cancel 222 | 223 | return &config.DagConfig{}, config.ErrCouldNotDeserializeConfig // Return error 224 | } 225 | 226 | cancel() // Cancel 227 | 228 | return deserializedConfig, nil // Return deserialized dag config 229 | } 230 | 231 | // BootstrapDht bootstraps the WorkingDHT to the list of bootstrap nodes. 232 | func BootstrapDht(ctx context.Context, host host.Host) (*dht.IpfsDHT, error) { 233 | dht, err := dht.New(ctx, host) // Initialize DHT with host and context 234 | if err != nil { // Check for errors 235 | return nil, err // Return found error 236 | } 237 | 238 | err = dht.Bootstrap(ctx) // Bootstrap 239 | 240 | if err != nil { // Check for errors 241 | return nil, err // Return found error 242 | } 243 | 244 | for _, addr := range BootstrapNodes { // Iterate through bootstrap nodes 245 | address, err := multiaddr.NewMultiaddr(addr) // Parse multi address 246 | if err != nil { // Check for errors 247 | continue // Continue to next peer 248 | } 249 | 250 | peerInfo, err := peerstore.InfoFromP2pAddr(address) // Get peer info 251 | if err != nil { // Check for errors 252 | continue // Continue to next peer 253 | } 254 | 255 | err = host.Connect(ctx, *peerInfo) // Connect to discovered peer 256 | 257 | if err != nil { // Check for errors 258 | continue // Continue to next peer 259 | } 260 | } 261 | 262 | return dht, nil // No error occurred, return nil 263 | } 264 | 265 | // BroadcastDht attempts to send a given message to all nodes in a dht at a given endpoint. 266 | func BroadcastDht(ctx context.Context, host *routed.RoutedHost, message []byte, streamProtocol, dagIdentifier string) error { 267 | peers := host.Peerstore().Peers() // Get peers 268 | 269 | for _, peer := range peers { // Iterate through peers 270 | if peer == (*host).ID() { // Check not same node 271 | continue // Continue 272 | } 273 | 274 | stream, err := (*host).NewStream(ctx, peer, protocol.ID(streamProtocol)) // Connect 275 | if err != nil { // Check for errors 276 | continue // Continue 277 | } 278 | 279 | writer := bufio.NewWriter(stream) // Initialize writer 280 | 281 | _, err = writer.Write(append(message, '\f')) // Write message 282 | 283 | if err != nil { // Check for errors 284 | continue // Continue 285 | } 286 | 287 | writer.Flush() // Flush 288 | } 289 | 290 | return nil // No error occurred, return nil 291 | } 292 | 293 | // BroadcastDhtResult send a given message to all nodes in a dht, and returns the result from each node. 294 | func BroadcastDhtResult(ctx context.Context, host *routed.RoutedHost, message []byte, streamProtocol, dagIdentifier string, nPeers int) ([][]byte, error) { 295 | peers := host.Peerstore().Peers() // Get peers 296 | 297 | results := [][]byte{} // Init results buffer 298 | 299 | for x, peer := range peers { // Iterate through peers 300 | if x >= nPeers { // Check has sent to enough peers 301 | break // Break 302 | } 303 | 304 | if peer == (*host).ID() { // Check not same node 305 | continue // Continue 306 | } 307 | 308 | stream, err := (*host).NewStream(ctx, peer, protocol.ID(streamProtocol)) // Connect 309 | if err != nil { // Check for errors 310 | continue // Continue 311 | } 312 | 313 | readWriter := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream)) // Initialize reader/writer 314 | 315 | _, err = readWriter.Write(append(message, byte('\f'))) // Write message 316 | 317 | if err != nil { // Check for errors 318 | continue // Continue 319 | } 320 | 321 | readWriter.Flush() // Flush 322 | 323 | responseBytes, err := readAsync(readWriter.Reader) // Read async 324 | if err != nil { // Check for errors 325 | continue // Continue 326 | } 327 | 328 | results = append(results, responseBytes) // Append response 329 | 330 | readWriter.Flush() // Flush 331 | } 332 | 333 | return results, nil // No error occurred, return response 334 | } 335 | 336 | // GetStreamHeaderProtocolPath attempts to determine the libp2p stream header protocol URI from a given stream protocol and network. 337 | func GetStreamHeaderProtocolPath(network string, streamProtocol StreamHeaderProtocol) string { 338 | return fmt.Sprintf("/%s/%s", network, StreamHeaderProtocolNames[streamProtocol]) // Return URI 339 | } 340 | 341 | /* END EXPORTED METHODS */ 342 | 343 | /* BEGIN INTERNAL METHODS */ 344 | 345 | // readAsync asynchronously reads from a given reader. 346 | func readAsync(reader *bufio.Reader) ([]byte, error) { 347 | readBytes, err := reader.ReadBytes('\f') // Read bytes up to and including delimiter 348 | if err != nil { // Check for errors 349 | return nil, err // Return found error 350 | } 351 | 352 | readBytes = bytes.Trim(readBytes, "\f") // Trim delimiter 353 | 354 | return readBytes, nil // Return read bytes 355 | } 356 | 357 | /* END INTERNAL METHODS */ 358 | -------------------------------------------------------------------------------- /p2p/p2p_client_stream_handlers.go: -------------------------------------------------------------------------------- 1 | package p2p 2 | 3 | import ( 4 | "bufio" 5 | "encoding/hex" 6 | 7 | inet "github.com/libp2p/go-libp2p-net" 8 | protocol "github.com/libp2p/go-libp2p-protocol" 9 | "github.com/polaris-project/go-polaris/common" 10 | "github.com/polaris-project/go-polaris/types" 11 | ) 12 | 13 | /* BEGIN EXPORTED METHODS */ 14 | 15 | /* 16 | BEGIN HANDLER REGISTRATION HELPERS 17 | */ 18 | 19 | // StartServingStreams attempts to start serving all necessary streams 20 | func (client *Client) StartServingStreams(network string) error { 21 | logger.Infof("setting up node stream handlers") // Log set up stream handlers 22 | 23 | err := client.StartServingStream(GetStreamHeaderProtocolPath(network, PublishTransaction), client.HandleReceiveTransaction) // Register tx handler 24 | if err != nil { // Check for errors 25 | return err // Return found error 26 | } 27 | 28 | err = client.StartServingStream(GetStreamHeaderProtocolPath(network, RequestConfig), client.HandleReceiveConfigRequest) // Register config request handler 29 | 30 | if err != nil { // Check for errors 31 | return err // Return found error 32 | } 33 | 34 | err = client.StartServingStream(GetStreamHeaderProtocolPath(network, RequestBestTransaction), client.HandleReceiveBestTransactionRequest) // Register best tx request handler 35 | 36 | if err != nil { // Check for errors 37 | return err // Return found error 38 | } 39 | 40 | err = client.StartServingStream(GetStreamHeaderProtocolPath(network, RequestTransaction), client.HandleReceiveTransactionRequest) // Register transaction request handler 41 | 42 | if err != nil { // Check for errors 43 | return err // Return found error 44 | } 45 | 46 | err = client.StartServingStream(GetStreamHeaderProtocolPath(network, RequestGenesisHash), client.HandleReceiveGenesisHashRequest) // Register genesis hash request handler 47 | 48 | if err != nil { // Check for errors 49 | return err // Return found error 50 | } 51 | 52 | err = client.StartServingStream(GetStreamHeaderProtocolPath(network, RequestChildHashes), client.HandleReceiveTransactionChildHashesRequest) // Register child hashes request handler 53 | 54 | if err != nil { // Check for errors 55 | return err // Return found error 56 | } 57 | 58 | return nil // No error occurred, return nil 59 | } 60 | 61 | // StartServingStream starts serving a stream on a given header protocol path. 62 | func (client *Client) StartServingStream(streamHeaderProtocolPath string, handler func(inet.Stream)) error { 63 | if WorkingHost == nil { // Check no host 64 | return ErrNoWorkingHost // Return found error 65 | } 66 | 67 | WorkingHost.SetStreamHandler(protocol.ID(streamHeaderProtocolPath), handler) // Set handler 68 | 69 | return nil // No error occurred, return nil 70 | } 71 | 72 | /* 73 | END HANDLER REGISTRATION HELPERS 74 | */ 75 | 76 | /* 77 | BEGIN HANDLERS 78 | */ 79 | 80 | // HandleReceiveTransaction handles a new stream sending a transaction. 81 | func (client *Client) HandleReceiveTransaction(stream inet.Stream) { 82 | logger.Infof("handling new publish transaction stream") // Log handle stream 83 | 84 | reader := bufio.NewReader(stream) // Initialize reader from stream 85 | 86 | transactionBytes, err := readAsync(reader) // Read async 87 | if err != nil { // Check for errors 88 | return // Return 89 | } 90 | 91 | transaction := types.TransactionFromBytes(transactionBytes) // Deserialize transaction 92 | 93 | logger.Infof("validating received transaction with hash: %s", hex.EncodeToString(transaction.Hash.Bytes())) // Log receive tx 94 | 95 | if err := (*client.Validator).ValidateTransaction(transaction); err == nil { // Check transaction valid 96 | logger.Infof("transaction was valid; adding to dag") // Log add to dag 97 | 98 | (*client.Validator).GetWorkingDag().AddTransaction(transaction) // Add transaction to working dag 99 | } 100 | } 101 | 102 | // HandleReceiveBestTransactionRequest handle a new stream requesting for the best transaction hash. 103 | func (client *Client) HandleReceiveBestTransactionRequest(stream inet.Stream) { 104 | logger.Infof("handling new best transaction request stream") // Log handle stream 105 | 106 | writer := bufio.NewWriter(stream) // Initialize writer from stream 107 | 108 | defer writer.Flush() // Flush 109 | 110 | bestTransaction, _ := (*client.Validator).GetWorkingDag().GetBestTransaction() // Get best transaction 111 | 112 | logger.Infof("responding with best transaction hash %s", hex.EncodeToString(bestTransaction.Hash.Bytes())) // Log handle stream 113 | 114 | writer.Write(append(bestTransaction.Hash.Bytes(), byte('\f'))) // Write best transaction hash 115 | } 116 | 117 | // HandleReceiveTransactionRequest handles a new stream requesting transaction metadata with a given hash. 118 | func (client *Client) HandleReceiveTransactionRequest(stream inet.Stream) { 119 | logger.Infof("handling new transaction with hash request stream") // Log handle stream 120 | 121 | readWriter := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream)) // Init reader/writer for stream 122 | 123 | defer readWriter.Flush() // Flush 124 | 125 | targetHashBytes, err := readAsync(readWriter.Reader) // Read async 126 | if err != nil { // Check for errors 127 | return // Return 128 | } 129 | 130 | logger.Infof("handling request for transaction with hash: %s", hex.EncodeToString(targetHashBytes)) // Log handle request 131 | 132 | transaction, _ := (*client.Validator).GetWorkingDag().GetTransactionByHash(common.NewHash(targetHashBytes)) // Get transaction with hash 133 | 134 | logger.Infof("responding with serialized transaction bytes: %s (len: %d), hash: %s", hex.EncodeToString(transaction.Bytes())[:36], len(transaction.Bytes()), hex.EncodeToString(transaction.Hash.Bytes())) // Log respond 135 | 136 | readWriter.Write(append(transaction.Bytes(), byte('\f'))) // Write transaction bytes 137 | } 138 | 139 | // HandleReceiveConfigRequest handles a new stream requesting the working dag config. 140 | func (client *Client) HandleReceiveConfigRequest(stream inet.Stream) { 141 | logger.Infof("handling new config request stream") // Log handle stream 142 | 143 | writer := bufio.NewWriter(stream) // Initialize writer 144 | 145 | defer writer.Flush() // Flush 146 | 147 | logger.Infof("responding with serialized config bytes: %s", hex.EncodeToString((*client.Validator).GetWorkingConfig().Bytes())[:36]) // Log response 148 | 149 | writer.Write(append((*client.Validator).GetWorkingConfig().Bytes(), byte('\f'))) // Write config bytes 150 | } 151 | 152 | // HandleReceiveGenesisHashRequest handles a new stream requesting for the genesis hash of the working dag. 153 | func (client *Client) HandleReceiveGenesisHashRequest(stream inet.Stream) { 154 | logger.Infof("handling new genesis hash request stream") // Log handle stream 155 | 156 | writer := bufio.NewWriter(stream) // Initialize writer 157 | 158 | defer writer.Flush() // Flush 159 | 160 | logger.Infof("responding with genesis hash: %s", hex.EncodeToString((*client.Validator).GetWorkingDag().Genesis.Bytes())) // Log response 161 | 162 | writer.Write(append((*client.Validator).GetWorkingDag().Genesis.Bytes(), byte('\f'))) // Write genesis hash 163 | } 164 | 165 | // HandleReceiveTransactionChildHashesRequest handles a new stream requesting for the child hashes of a given transaction. 166 | func (client *Client) HandleReceiveTransactionChildHashesRequest(stream inet.Stream) { 167 | logger.Infof("handling new child hash request stream") // Log handle stream 168 | 169 | readWriter := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream)) // Initialize reader/writer from stream 170 | 171 | defer readWriter.Flush() // Flush 172 | 173 | parentHashBytes, err := readAsync(readWriter.Reader) // Read async 174 | if err != nil { // Check for errors 175 | return // Return 176 | } 177 | 178 | children, err := (*client.Validator).GetWorkingDag().GetTransactionChildren(common.NewHash(parentHashBytes)) // Get children 179 | 180 | if err == nil { // Check no error 181 | var summarizedChildHashes []byte // Init summarized child hashes buffer 182 | 183 | for x, child := range children { // Iterate through children 184 | if x == len(children)-1 { // Check is last 185 | summarizedChildHashes = append(summarizedChildHashes, child.Hash[:]...) // Append hash 186 | } 187 | 188 | summarizedChildHashes = append(summarizedChildHashes, append(child.Hash[:], []byte("end_hash")...)...) // Append hash 189 | } 190 | 191 | if hexEncodedChildHashes := hex.EncodeToString(summarizedChildHashes); hexEncodedChildHashes != "" { // Check can log 192 | logger.Infof("responding with child hashes: %s", hex.EncodeToString(summarizedChildHashes)[:36]) // Log response 193 | } 194 | 195 | readWriter.Write(append(summarizedChildHashes, byte('\f'))) // Write child hashes 196 | 197 | readWriter.Flush() // Flush 198 | } 199 | } 200 | 201 | /* 202 | END HANDLERS 203 | */ 204 | 205 | /* END EXPORTED METHODS */ 206 | -------------------------------------------------------------------------------- /p2p/p2p_client_stream_handlers_test.go: -------------------------------------------------------------------------------- 1 | package p2p 2 | 3 | import ( 4 | "context" 5 | "os" 6 | "path/filepath" 7 | "testing" 8 | 9 | inet "github.com/libp2p/go-libp2p-net" 10 | "github.com/polaris-project/go-polaris/config" 11 | "github.com/polaris-project/go-polaris/types" 12 | "github.com/polaris-project/go-polaris/validator" 13 | ) 14 | 15 | /* BEGIN EXPORTED METHODS TESTS */ 16 | 17 | // TestStartServingStream tests the functionality of the StartServingStream() helper method. 18 | func TestStartServingStream(t *testing.T) { 19 | os.RemoveAll(filepath.FromSlash("data/db/test_network.db")) // Remove existing db 20 | 21 | dagConfig := config.NewDagConfig(nil, "test_network", 1) // Initialize new dag config with test genesis file. 22 | 23 | dag, err := types.NewDag(dagConfig) // Initialize dag with dag config 24 | if err != nil { // Check for errors 25 | t.Fatal(err) // Panic 26 | } 27 | 28 | validator := validator.Validator(validator.NewBeaconDagValidator(dagConfig, dag)) // Initialize validator 29 | 30 | client := NewClient("test_network", &validator) // Initialize client 31 | 32 | if client == nil { // Check client is nil 33 | t.Fatal("client should not be nil") // Panic 34 | } 35 | 36 | ctx, cancel := context.WithCancel(context.Background()) // Initialize context 37 | 38 | defer cancel() // Cancel 39 | 40 | _, err = NewHost(ctx, 3000) // Initialize host 41 | 42 | if err != nil { // Check for errors 43 | t.Fatal(err) // Panic 44 | } 45 | 46 | err = client.StartServingStream("test_stream", func(inet.Stream) {}) // Start serving stream 47 | 48 | if err != nil { // Check for errors 49 | t.Fatal(err) // Panic 50 | } 51 | 52 | os.RemoveAll(filepath.FromSlash("data/db/test_network.db")) // Remove existing db 53 | } 54 | 55 | /* END EXPORTED METHODS TESTS */ 56 | -------------------------------------------------------------------------------- /p2p/p2p_client_test.go: -------------------------------------------------------------------------------- 1 | package p2p 2 | 3 | import ( 4 | "context" 5 | "os" 6 | "path/filepath" 7 | "testing" 8 | 9 | "github.com/polaris-project/go-polaris/config" 10 | "github.com/polaris-project/go-polaris/types" 11 | "github.com/polaris-project/go-polaris/validator" 12 | ) 13 | 14 | /* BEGIN EXPORTED METHODS TESTS */ 15 | 16 | // TestNewClient tests the functionality of the client initializer. 17 | func TestNewClient(t *testing.T) { 18 | os.RemoveAll(filepath.FromSlash("data/db/test_network.db")) // Remove existing db 19 | 20 | dagConfig := config.NewDagConfig(nil, "test_network", 1) // Initialize new dag config with test genesis file. 21 | 22 | dag, err := types.NewDag(dagConfig) // Initialize dag with dag config 23 | if err != nil { // Check for errors 24 | t.Fatal(err) // Panic 25 | } 26 | 27 | _, err = NewHost(context.Background(), 2831) // Initialize host 28 | 29 | if err != nil { // Check for errors 30 | t.Fatal(err) // Panic 31 | } 32 | 33 | validator := validator.Validator(validator.NewBeaconDagValidator(dagConfig, dag)) // Initialize validator 34 | 35 | client := NewClient("test_network", &validator) // Initialize client 36 | 37 | if client == nil { // Check client is nil 38 | t.Fatal("client should not be nil") // Panic 39 | } 40 | 41 | types.WorkingDagDB.Close() // Close dag db 42 | 43 | os.RemoveAll(filepath.FromSlash("data/db/test_network.db")) // Remove existing db 44 | } 45 | 46 | /* END EXPORTED METHODS TESTS */ 47 | -------------------------------------------------------------------------------- /p2p/p2p_stream_handlers.go: -------------------------------------------------------------------------------- 1 | package p2p 2 | 3 | import ( 4 | inet "github.com/libp2p/go-libp2p-net" 5 | ) 6 | 7 | /* BEGIN EXPORTED METHODS */ 8 | 9 | // HandlePubTransaction handles the 10 | func (client *Client) HandlePubTransaction(stream inet.Stream) { 11 | //_ := bufio.NewWriter(stream) // Open stream writer 12 | } 13 | 14 | /* END EXPORTED METHODS */ 15 | -------------------------------------------------------------------------------- /p2p/p2p_test.go: -------------------------------------------------------------------------------- 1 | // Package p2p provides common peer-to-peer communications helper methods and definitions. 2 | package p2p 3 | 4 | import ( 5 | "context" 6 | "crypto/ecdsa" 7 | "crypto/elliptic" 8 | "crypto/rand" 9 | "math/big" 10 | "testing" 11 | 12 | protocol "github.com/libp2p/go-libp2p-protocol" 13 | "github.com/polaris-project/go-polaris/config" 14 | "github.com/polaris-project/go-polaris/crypto" 15 | "github.com/polaris-project/go-polaris/types" 16 | "github.com/polaris-project/go-polaris/validator" 17 | ) 18 | 19 | /* BEGIN EXPORTED METHODS TESTS */ 20 | 21 | // TestNewHost tests the functionality of the NewHost() helper method. 22 | func TestNewHost(t *testing.T) { 23 | _, err := NewHost(context.Background(), 2831) // Initialize host 24 | if err != nil { // Check for errors 25 | t.Fatal(err) // Panic 26 | } 27 | } 28 | 29 | // TestGetBestBootstrap tests the functionality of the GetBestBootstrap() helper method. 30 | func TestGetBestBootstrap(t *testing.T) { 31 | host, err := NewHost(context.Background(), 2831) // Initialize host 32 | if err != nil { // Check for errors 33 | t.Fatal(err) // Panic 34 | } 35 | 36 | bestBootstrap := GetBestBootstrapAddress(context.Background(), host) // Get best bootstrap node 37 | 38 | t.Log(bestBootstrap) // Log best 39 | } 40 | 41 | // TestBootstrapDht tests the functionality of the BootstrapDht() helper method. 42 | func TestBootstrapDht(t *testing.T) { 43 | ctx, cancel := context.WithCancel(context.Background()) // Get context 44 | 45 | defer cancel() // Cancel 46 | 47 | BootstrapNodes = []string{ 48 | "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", 49 | "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", 50 | } // Set bootstrap nodes 51 | 52 | _, err := NewHost(ctx, 2831) // Initialize libp2p host with context and nat manager 53 | if err != nil { // Check for errors 54 | t.Fatal(err) // Panic 55 | } 56 | } 57 | 58 | // TestBroadcastDht tests the functionality of the BroadcastDht() helper method. 59 | func TestBroadcastDht(t *testing.T) { 60 | ctx, cancel := context.WithCancel(context.Background()) // Get context 61 | 62 | defer cancel() // Cancel 63 | 64 | BootstrapNodes = []string{ 65 | "/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", 66 | "/ip4/104.236.179.241/tcp/4001/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM", 67 | } // Set bootstrap nodes 68 | 69 | host, err := NewHost(ctx, 2831) // Initialize libp2p host with context and nat manager 70 | if err != nil { // Check for errors 71 | t.Fatal(err) // Panic 72 | } 73 | 74 | err = BroadcastDht(ctx, host, []byte("test"), "/test/1.0.0", "test_network") // Broadcast 75 | 76 | if err != nil { // Check for errors 77 | t.Fatal(err) // Panic 78 | } 79 | } 80 | 81 | // TestPublish tests the functionality of the Publish() helper method. 82 | func TestPublish(t *testing.T) { 83 | privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) // Generate private key 84 | if err != nil { // Check for errors 85 | t.Fatal(err) // Panic 86 | } 87 | 88 | address := crypto.AddressFromPrivateKey(privateKey) // Generate address 89 | 90 | transaction := types.NewTransaction( 91 | 0, // Nonce 92 | big.NewFloat(0), // Amount 93 | address, // Sender 94 | nil, // Recipient 95 | nil, // Parents 96 | 0, // Gas limit 97 | big.NewInt(0), // Gas price 98 | []byte("test payload"), // Payload 99 | ) // Initialize a new transaction 100 | 101 | err = types.SignTransaction(transaction, privateKey) // Sign transaction 102 | 103 | if err != nil { // Check for errors 104 | t.Fatal(err) // Panic 105 | } 106 | 107 | ctx, cancel := context.WithCancel(context.Background()) // Get context 108 | 109 | defer cancel() // Cancel 110 | 111 | _, err = NewHost(ctx, 3861) // Initialize host 112 | 113 | if err != nil { // Check for errors 114 | t.Fatal(err) // Panic 115 | } 116 | 117 | dagConfig := config.NewDagConfig(nil, "test_network", 1) // Initialize new dag config with test genesis file. 118 | 119 | dag, err := types.NewDag(dagConfig) // Initialize dag with dag config 120 | if err != nil { // Check for errors 121 | t.Fatal(err) // Panic 122 | } 123 | 124 | validator := validator.Validator(validator.NewBeaconDagValidator(dagConfig, dag)) // Initialize validator 125 | 126 | client := NewClient("test_network", &validator) // Initialize client 127 | 128 | if client == nil { // Check client is nil 129 | t.Fatal("client should not be nil") // Panic 130 | } 131 | 132 | err = client.PublishTransaction(context.Background(), transaction) // Publish transaction 133 | 134 | if err != nil { // Check for errors 135 | t.Fatal(err) // Panic 136 | } 137 | } 138 | 139 | // TestGetStreamHeaderProtocolPath tests the functionality of the GetStreamHeaderProtocol() helper method. 140 | func TestGetStreamHeaderProtocolPath(t *testing.T) { 141 | streamHeaderProtocolPath := GetStreamHeaderProtocolPath("test_network", PublishTransaction) // Get stream header protocol URI 142 | 143 | t.Log(protocol.ID(streamHeaderProtocolPath)) // Get libp2p representation 144 | } 145 | 146 | /* END EXPORTED METHODS TESTS */ 147 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | echo "" > coverage.txt 5 | 6 | for d in $(go list ./... | grep -v vendor | grep -v types | grep -v upnp | grep -v accounts); do 7 | go test -coverprofile=profile.out -covermode=atomic "$d" 8 | if [ -f profile.out ]; then 9 | cat profile.out >> coverage.txt 10 | rm profile.out 11 | fi 12 | done -------------------------------------------------------------------------------- /types/dag.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; // Specify compiler version 2 | 3 | package dag; 4 | 5 | service Dag { 6 | rpc NewDag(GeneralRequest) returns (GeneralResponse) {} // Attempt to initialize dag with given config dir 7 | rpc MakeGenesis(GeneralRequest) returns (GeneralResponse) {} // Attempt to make genesis on provided network dag 8 | rpc GetTransactionByHash(GeneralRequest) returns (GeneralResponse) {} // Query transaction by hash 9 | rpc GetTransactionChildren(GeneralRequest) returns (GeneralResponse) {} // Query childreh for tx 10 | rpc GetTransactionsByAddress(GeneralRequest) returns (GeneralResponse) {} // Query transactions by address 11 | rpc GetTransactionsBySender(GeneralRequest) returns (GeneralResponse) {} // Query transactions by sender 12 | rpc GetBestTransaction(GeneralRequest) returns (GeneralResponse) {} // Attempt to query best transaction 13 | rpc CalculateAddressBalance(GeneralRequest) returns (GeneralResponse) {} // Calculate address balance 14 | } 15 | 16 | /* BEGIN REQUESTS */ 17 | 18 | message GeneralRequest { 19 | string network = 1; // Network 20 | 21 | string transactionHash = 2; // Transaction hash 22 | 23 | string address = 3; // Address 24 | } 25 | 26 | /* END REQUESTS */ 27 | 28 | /* BEGIN RESPONSES */ 29 | 30 | message GeneralResponse { 31 | string message = 1; // Response 32 | } 33 | 34 | /* END REPSONSES */ -------------------------------------------------------------------------------- /types/dag_io.go: -------------------------------------------------------------------------------- 1 | // Package types provides core primitives for the operation 2 | // of the Polaris protocol. 3 | package types 4 | 5 | import ( 6 | "encoding/json" 7 | "fmt" 8 | "io/ioutil" 9 | "path/filepath" 10 | 11 | "github.com/polaris-project/go-polaris/common" 12 | ) 13 | 14 | /* BEGIN EXPORTED METHODS */ 15 | 16 | // Bytes serializes a given dag header to a byte array via JSON. 17 | func (dag *Dag) Bytes() []byte { 18 | marshaledVal, _ := json.MarshalIndent(*dag, "", " ") // Marshal 19 | 20 | return marshaledVal // Return bytes 21 | } 22 | 23 | // WriteToMemory writes the dag header to persistent memory. 24 | func (dag *Dag) WriteToMemory() error { 25 | err := common.CreateDirIfDoesNotExist(common.DbDir) // Create db dir if necessary 26 | if err != nil { // Check for errors 27 | return err // Return found error 28 | } 29 | 30 | return ioutil.WriteFile(filepath.FromSlash(fmt.Sprintf("%s/db_header_%s.json", common.DbDir, dag.DagConfig.Identifier)), dag.Bytes(), 0o644) // Write dag header to persistent memory 31 | } 32 | 33 | /* END EXPORTED METHODS */ 34 | 35 | /* BEGIN INTERNAL METHODS */ 36 | 37 | // readDagDbHeaderFromMemory attempts to read the dag db header with the given identifier from persistent memory. 38 | func readDagDbHeaderFromMemory(identifier string) (*Dag, error) { 39 | data, err := ioutil.ReadFile(filepath.FromSlash(fmt.Sprintf("%s/db_header_%s.json", common.DbDir, identifier))) // Read header 40 | if err != nil { // Check for errors 41 | return &Dag{}, err // Return found error 42 | } 43 | 44 | buffer := &Dag{} // Initialize db header buffer 45 | 46 | err = json.Unmarshal(data, buffer) // Unmarshal JSON into buffer 47 | 48 | if err != nil { // Check for errors 49 | return &Dag{}, err // Return found error 50 | } 51 | 52 | return buffer, nil // No error occurred, retrun nil 53 | } 54 | 55 | /* END INTERNAL METHODS */ 56 | -------------------------------------------------------------------------------- /types/dag_io_test.go: -------------------------------------------------------------------------------- 1 | // Package types provides core primitives for the operation 2 | // of the Polaris protocol. 3 | package types 4 | 5 | import ( 6 | "bytes" 7 | "testing" 8 | 9 | "github.com/polaris-project/go-polaris/config" 10 | ) 11 | 12 | /* BEGIN EXPORTED METHODS TESTS */ 13 | 14 | // TestBytesDag tests the functionality of the dag Bytes() helper method. 15 | func TestBytesDag(t *testing.T) { 16 | dagConfig := config.NewDagConfig(nil, "test_network", 1) // Initialize new dag config with test genesis file. 17 | 18 | dag, err := NewDag(dagConfig) // Initialize dag with dag config 19 | if err != nil { // Check for errors 20 | t.Fatal(err) // Panic 21 | } 22 | 23 | t.Log(dag.Bytes()) // Log dag bytes 24 | 25 | WorkingDagDB.Close() // Close dag db 26 | } 27 | 28 | /* END EXPORTED METHODS TESTS */ 29 | 30 | /* BEGIN INTERNAL METHODS TESTS */ 31 | 32 | // TestReadDagDbHeaderFromMemory tests the functionality of the readDagDbHeaderFromMemory() helper method. 33 | func TestReadDagDbHeaderFromMemory(t *testing.T) { 34 | dagConfig := config.NewDagConfig(nil, "test_network", 1) // Initialize new dag config with test genesis file. 35 | 36 | dag, err := NewDag(dagConfig) // Initialize dag with dag config 37 | if err != nil { // Check for errors 38 | t.Fatal(err) // Panic 39 | } 40 | 41 | err = dag.WriteToMemory() // Write dag db header to persistent memory 42 | 43 | if err != nil { // Check for errors 44 | t.Fatal(err) // Panic 45 | } 46 | 47 | readDag, err := readDagDbHeaderFromMemory(dag.DagConfig.Identifier) // Read dag db header 48 | if err != nil { // Check for errors 49 | t.Fatal(err) // Panic 50 | } 51 | 52 | if !bytes.Equal(readDag.Bytes(), dag.Bytes()) { // Check dags not equivalent 53 | t.Fatal("dags should be equivalent") // Panic 54 | } 55 | 56 | WorkingDagDB.Close() // Close dag db 57 | } 58 | 59 | // TestWriteToMemoryDagDbHeader tests the functionality of the writeToMemory() dag db header helper. 60 | func TestWriteToMemoryDagDbHeader(t *testing.T) { 61 | dagConfig := config.NewDagConfig(nil, "test_network", 1) // Initialize new dag config with test genesis file. 62 | 63 | dag, err := NewDag(dagConfig) // Initialize dag with dag config 64 | if err != nil { // Check for errors 65 | t.Fatal(err) // Panic 66 | } 67 | 68 | err = dag.WriteToMemory() // Write dag db header to persistent memory 69 | 70 | if err != nil { // Check for errors 71 | t.Fatal(err) // Panic 72 | } 73 | 74 | WorkingDagDB.Close() // Close working dag db 75 | } 76 | 77 | /* END INTERNAL METHODS TESTS */ 78 | -------------------------------------------------------------------------------- /types/transaction.go: -------------------------------------------------------------------------------- 1 | // Package types provides core primitives for the operation 2 | // of the Polaris protocol. 3 | package types 4 | 5 | import ( 6 | "errors" 7 | "math/big" 8 | "time" 9 | 10 | "github.com/polaris-project/go-polaris/common" 11 | "github.com/polaris-project/go-polaris/crypto" 12 | ) 13 | 14 | var ( 15 | // ErrNoWorkingHost represents an error describing a p2p.WorkingHost value of nil. 16 | ErrNoWorkingHost = errors.New("no valid global host was found") 17 | 18 | // BestTransactionRequest represents the global best transaction request message byte value. 19 | BestTransactionRequest = []byte("best_transaction_request") 20 | 21 | // TransactionRequest represents the global transaction request message byte value. 22 | TransactionRequest = []byte("transaction_request") 23 | 24 | // GenesisHashRequest represents the global genesis transaction request message byte value. 25 | GenesisHashRequest = []byte("genesis_hash_request") 26 | ) 27 | 28 | // Transaction is a data type representing a transfer of monetary value between addresses. 29 | // A transactions does not necessarily imply the transfer of value between human peers, but also contracts. 30 | type Transaction struct { 31 | AccountNonce uint64 `json:"nonce" gencodec:"required"` // Index in account transaction list 32 | 33 | Amount *big.Float `json:"amount" gencodec:"required"` // Transaction value 34 | 35 | Sender *common.Address `json:"sender" gencodec:"required"` // Transaction sender 36 | Recipient *common.Address `json:"recipient" gencodec:"required"` // Transaction recipient 37 | 38 | ParentTransactions []common.Hash `json:"parent" gencodec:"required"` // Parent hash 39 | 40 | GasPrice *big.Int `json:"gas_price" gencodec:"required"` // Gas price in units equivalent to 0.000000001 of a single unit 41 | GasLimit uint64 `json:"gas_limit" gencodec:"required"` // Value of gas price willing to pay for transaction 42 | 43 | Payload []byte `json:"payload" gencodec:"required"` // Data sent with transaction (i.e. contract bytecode, message, etc...) 44 | 45 | Signature *Signature `json:"signature" gencodec:"required"` // ECDSA transaction signature 46 | 47 | Timestamp time.Time `json:"timestamp" gencodec:"required"` // Transaction timestamp 48 | 49 | Hash common.Hash `json:"hash" gencodec:"required"` // Transaction hash 50 | } 51 | 52 | /* BEGIN EXPORTED METHODS */ 53 | 54 | // NewTransaction creates a new transaction with the given account nonce, value, sender, recipient, gas price, gas limit, and payload. 55 | func NewTransaction(accountNonce uint64, amount *big.Float, sender, recipient *common.Address, parentTransactions []common.Hash, gasLimit uint64, gasPrice *big.Int, payload []byte) *Transaction { 56 | transaction := &Transaction{ 57 | AccountNonce: accountNonce, // Set account nonce 58 | Amount: amount, // Set amount 59 | Sender: sender, // Set sender 60 | Recipient: recipient, // Set recipient 61 | ParentTransactions: parentTransactions, // Set parents 62 | GasPrice: gasPrice, // Set gas price 63 | GasLimit: gasLimit, // Set gas limit 64 | Payload: payload, // Set payload 65 | Signature: nil, // Set signature 66 | Timestamp: time.Now().UTC(), // Set timestamp 67 | } 68 | 69 | (*transaction).Hash = crypto.Sha3(transaction.Bytes()) // Set transaction hash 70 | 71 | return transaction // Return initialized transaction 72 | } 73 | 74 | // CalculateTotalValue calculates the total value of a transaction, including both its amount and total gas. 75 | func (transaction *Transaction) CalculateTotalValue() *big.Float { 76 | return new(big.Float).Add(transaction.Amount, new(big.Float).SetInt(transaction.GasPrice.Mul(transaction.GasPrice, big.NewInt(int64(transaction.GasLimit))))) // Return total value 77 | } 78 | 79 | /* BEGIN EXPORTED METHODS */ 80 | -------------------------------------------------------------------------------- /types/transaction.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; // Specify compiler version 2 | 3 | package transaction; 4 | 5 | service Transaction { 6 | rpc NewTransaction(GeneralRequest) returns (GeneralResponse) {} // Attempt to initialize transaction primitive 7 | rpc CalculateTotalValue(GeneralRequest) returns (GeneralResponse) {} // Calculate the total value of a transaction, including both its amount and total gas 8 | rpc SignTransaction(GeneralRequest) returns (GeneralResponse) {} // Sign a given transaction via ecdsa, and set the transaction signature to the new signature 9 | rpc Publish(GeneralRequest) returns (GeneralResponse) {} // Publish a given transaction 10 | rpc SignMessage(GeneralRequest) returns (GeneralResponse) {} // Sign a given message hash via ecdsa, and return a new signature 11 | rpc Verify(GeneralRequest) returns (GeneralResponse) {} // Check that a given signature is valid, and return whether or not the given signature is valid 12 | rpc String(GeneralRequest) returns (GeneralResponse) {} // Serialize a given transaction to a string via json 13 | } 14 | 15 | /* BEGIN REQUESTS */ 16 | 17 | message GeneralRequest { 18 | uint64 nonce = 1; // Transaction nonce in account tx set 19 | 20 | bytes amount = 2; // Tx amount 21 | 22 | string address = 3; // Transaction sender 23 | 24 | string address2 = 4; // Transaction recipient 25 | 26 | repeated string transactionHash = 5; // Hashes of parents or tx-to-sign 27 | 28 | uint64 gasLimit = 6; // Gas limit 29 | 30 | uint64 gasPrice = 7; // Gas price 31 | 32 | bytes payload = 8; // Tx payload 33 | } 34 | 35 | /* END REQUESTS */ 36 | 37 | /* BEGIN RESPONSES */ 38 | 39 | message GeneralResponse { 40 | string message = 1; // Response 41 | } 42 | 43 | /* END REPSONSES */ -------------------------------------------------------------------------------- /types/transaction_io.go: -------------------------------------------------------------------------------- 1 | // Package types provides core primitives for the operation 2 | // of the Polaris protocol. 3 | package types 4 | 5 | import ( 6 | "encoding/hex" 7 | "encoding/json" 8 | "fmt" 9 | "io/ioutil" 10 | "path/filepath" 11 | 12 | "github.com/polaris-project/go-polaris/common" 13 | ) 14 | 15 | /* BEGIN EXPORTED METHODS */ 16 | 17 | // TransactionFromBytes deserializes a transaction from a given byte array. 18 | func TransactionFromBytes(b []byte) *Transaction { 19 | buffer := &Transaction{} // Initialize tx buffer 20 | 21 | err := json.Unmarshal(b, buffer) // Unmarshal 22 | if err != nil { // Check for errors 23 | return &Transaction{} 24 | } 25 | 26 | return buffer // Return deserialized transaction 27 | } 28 | 29 | // Bytes serializes a given transaction to a byte array via json. 30 | func (transaction *Transaction) Bytes() []byte { 31 | marshaledVal, _ := json.MarshalIndent(*transaction, "", " ") // Marshal JSON 32 | 33 | return marshaledVal // Return marshaled value 34 | } 35 | 36 | // String serializes a given transaction to a string via json. 37 | func (transaction *Transaction) String() string { 38 | marshaledVal, _ := json.MarshalIndent(*transaction, "", " ") // Marshal JSON 39 | 40 | return string(marshaledVal) // Returned the marshalled JSON as a string 41 | } 42 | 43 | // WriteToMemory writes a given transaction to persistent memory in the mempool. 44 | func (transaction *Transaction) WriteToMemory() error { 45 | err := common.CreateDirIfDoesNotExist(common.MempoolDir) // Create mempool dir if necessary 46 | if err != nil { // Check for errors 47 | return err // Return found error 48 | } 49 | 50 | err = ioutil.WriteFile(filepath.FromSlash(fmt.Sprintf("%s/transaction_%s.json", common.MempoolDir, hex.EncodeToString(transaction.Hash.Bytes()))), transaction.Bytes(), 0o644) // Write transaction to persistent memory 51 | 52 | if err != nil { // Check for errors 53 | return err // Return error 54 | } 55 | 56 | return nil // No error occurred, return nil 57 | } 58 | 59 | // ReadTransactionFromMemory reads a given transaction (specified by hash) from persistent memory. 60 | func ReadTransactionFromMemory(hash common.Hash) (*Transaction, error) { 61 | data, err := ioutil.ReadFile(filepath.FromSlash(fmt.Sprintf("%s/transaction_%s.json", common.MempoolDir, hex.EncodeToString(hash.Bytes())))) // Read transaction 62 | if err != nil { // Check for errors 63 | return &Transaction{}, err // Return found error 64 | } 65 | 66 | buffer := &Transaction{} // Initialize buffer 67 | 68 | err = json.Unmarshal(data, buffer) // Deserialize JSON into buffer. 69 | 70 | if err != nil { // Check for errors 71 | return &Transaction{}, err // Return found error 72 | } 73 | 74 | return buffer, nil // No error occurred, return read transaction 75 | } 76 | 77 | /* END EXPORTED METHODS */ 78 | -------------------------------------------------------------------------------- /types/transaction_io_test.go: -------------------------------------------------------------------------------- 1 | // Package types provides core primitives for the operation 2 | // of the Polaris protocol. 3 | package types 4 | 5 | import ( 6 | "bytes" 7 | "math/big" 8 | "testing" 9 | ) 10 | 11 | /* BEGIN EXPORTED METHODS TESTS */ 12 | 13 | // TestTransactionFromBytes tests the functionality of the TransactionFromBytes() transaction helper method. 14 | func TestTransactionFromBytes(t *testing.T) { 15 | transaction := NewTransaction( 16 | 0, // Nonce 17 | big.NewFloat(10), // Amount 18 | nil, // Sender 19 | nil, // Recipient 20 | nil, // Parents 21 | 1, // Gas limit 22 | big.NewInt(1000), // Gas price 23 | []byte("test payload"), // Payload 24 | ) // Initialize a new transaction using the NewTransaction method 25 | 26 | if !bytes.Equal(transaction.Bytes(), TransactionFromBytes(transaction.Bytes()).Bytes()) { // Check transactions not equal 27 | t.Fatal("deserialized transaction should be equivalent to source") // Panic 28 | } 29 | } 30 | 31 | // TestBytesTransaction tests the functionality of the Bytes() transaction helper method. 32 | func TestBytesTransaction(t *testing.T) { 33 | transaction := NewTransaction( 34 | 0, // Nonce 35 | big.NewFloat(10), // Amount 36 | nil, // Sender 37 | nil, // Recipient 38 | nil, // Parents 39 | 1, // Gas limit 40 | big.NewInt(1000), // Gas price 41 | []byte("test payload"), // Payload 42 | ) // Initialize a new transaction using the NewTransaction method 43 | 44 | t.Log(transaction.Bytes()) // Log transaction bytes & test the Bytes() method 45 | } 46 | 47 | // TestBytesTransaction tests the functionality of the String() transaction helper method. 48 | func TestStringTransaction(t *testing.T) { 49 | transaction := NewTransaction( 50 | 0, // Nonce 51 | big.NewFloat(10), // Amount 52 | nil, // Sender 53 | nil, // Recipient 54 | nil, // Parents 55 | 1, // Gas limit 56 | big.NewInt(1000), // Gas price 57 | []byte("test payload"), // Payload 58 | ) // Initialize a new transaction using the NewTransaction method 59 | 60 | t.Log(transaction.String()) // Log transaction string & test the String() method 61 | } 62 | 63 | /* END EXPORTED METHODS TESTS */ 64 | -------------------------------------------------------------------------------- /types/transaction_signature.go: -------------------------------------------------------------------------------- 1 | // Package types provides core primitives for the operation 2 | // of the Polaris protocol. 3 | package types 4 | 5 | import ( 6 | "crypto/ecdsa" 7 | "crypto/elliptic" 8 | "crypto/rand" 9 | "errors" 10 | "math/big" 11 | 12 | "github.com/polaris-project/go-polaris/common" 13 | "github.com/polaris-project/go-polaris/crypto" 14 | ) 15 | 16 | var ( 17 | // ErrAlreadySigned defines an error describing a situation in which a message has already been signed. 18 | ErrAlreadySigned = errors.New("already signed") 19 | 20 | // ErrNilHash defines an error describing a situation in which a message has no hash. 21 | ErrNilHash = errors.New("hash not set") 22 | ) 23 | 24 | // Signature is a data type representing a verifiable ECDSA signature--that of which 25 | // is not necessarily a transaction signature. 26 | type Signature struct { 27 | MarshaledPublicKey []byte `json:"pub" gencodec:"required"` // Signature public key 28 | 29 | V []byte `json:"v" gencodec:"required"` // Signature message 30 | R *big.Int `json:"r" gencodec:"required"` // Signature retrieval 31 | S *big.Int `json:"s" gencodec:"required"` // Signature retrieval 32 | } 33 | 34 | /* BEGIN EXPORTED METHODS */ 35 | 36 | // SignTransaction signs a given transaction via ecdsa, and sets the transaction signature to the new signature. 37 | // Returns a new signature composed of v, r, s values. 38 | // If the transaction has already been signed, returns an ErrAlreadySigned error, as well as a nil signature pointer. 39 | // If the transaction has no hash, returns an ErrNilHash error, as well as a nil signature pointer. 40 | func SignTransaction(transaction *Transaction, privateKey *ecdsa.PrivateKey) error { 41 | if transaction.Hash.IsNil() { // Check no existing hash 42 | return ErrNilHash // Return no hash error 43 | } 44 | 45 | if transaction.Signature == nil { // Check no existing signature 46 | r, s, err := ecdsa.Sign(rand.Reader, privateKey, transaction.Hash.Bytes()) // Sign via ECDSA 47 | if err != nil { // Check for errors 48 | return err // Return found error 49 | } 50 | 51 | (*transaction).Signature = &Signature{ 52 | MarshaledPublicKey: elliptic.Marshal(elliptic.P521(), privateKey.PublicKey.X, privateKey.PublicKey.Y), // Set marshaled public key 53 | V: transaction.Hash.Bytes(), // Set hash 54 | R: r, // Set R 55 | S: s, // Set S 56 | } // Set transaction signature 57 | 58 | (*transaction).Hash = common.NewHash(nil) // Set hash to nil 59 | 60 | (*transaction).Hash = crypto.Sha3(transaction.Bytes()) // Set transaction hash 61 | 62 | return nil // Return signature 63 | } 64 | 65 | return ErrAlreadySigned // Return already signed error 66 | } 67 | 68 | // SignMessage signs a given message hash via ecdsa, and returns a new signature 69 | func SignMessage(messageHash common.Hash, privateKey *ecdsa.PrivateKey) (*Signature, error) { 70 | if messageHash.IsNil() { // Check nil hash 71 | return nil, ErrNilHash // Return no hash error 72 | } 73 | 74 | r, s, err := ecdsa.Sign(rand.Reader, privateKey, messageHash.Bytes()) // Sign via ECDSA 75 | if err != nil { // Check for errors 76 | return nil, err // Return found error 77 | } 78 | 79 | signature := &Signature{ 80 | V: messageHash.Bytes(), // Set hash 81 | R: r, // Set R 82 | S: s, // Set S 83 | } // Set transaction signature 84 | 85 | return signature, nil // Return signature 86 | } 87 | 88 | // Verify checks that a given signature is valid, and returns whether or not the given signature is valid. 89 | // If no signature exists at the given memory address, false is returned. 90 | func (signature *Signature) Verify(address *common.Address) bool { 91 | x, y := elliptic.Unmarshal(elliptic.P521(), signature.MarshaledPublicKey) // Unmarshal public key 92 | 93 | publicKey := &ecdsa.PublicKey{ 94 | Curve: elliptic.P521(), // Set curve 95 | X: x, // Set x 96 | Y: y, // Set y 97 | } // Recover public key 98 | 99 | if signature == nil { // Check no existent signature 100 | return false // No signature to verify 101 | } 102 | 103 | if *crypto.AddressFromPublicKey(publicKey) != *address { // Check invalid public key 104 | return false // Invalid 105 | } 106 | 107 | return ecdsa.Verify(publicKey, signature.V, signature.R, signature.S) // Verify signature contents 108 | } 109 | 110 | /* END EXPORTED METHODS */ 111 | -------------------------------------------------------------------------------- /types/transaction_signature_io.go: -------------------------------------------------------------------------------- 1 | // Package types provides core primitives for the operation 2 | // of the Polaris protocol. 3 | package types 4 | 5 | import ( 6 | "encoding/json" 7 | ) 8 | 9 | /* BEGIN EXPORTED METHODS */ 10 | 11 | // String marshals the contents of a given ECDA signature via JSON. 12 | func (signature *Signature) String() string { 13 | marshaledVal, _ := json.MarshalIndent(*signature, "", " ") // Marshal indent 14 | 15 | return string(marshaledVal) // Return JSON string 16 | } 17 | 18 | /* END EXPORTED METHODS */ 19 | -------------------------------------------------------------------------------- /types/transaction_signature_test.go: -------------------------------------------------------------------------------- 1 | // Package types provides core primitives for the operation 2 | // of the Polaris protocol. 3 | package types 4 | 5 | import ( 6 | "crypto/ecdsa" 7 | "crypto/elliptic" 8 | "crypto/rand" 9 | "math/big" 10 | "testing" 11 | 12 | "github.com/polaris-project/go-polaris/crypto" 13 | ) 14 | 15 | /* BEGIN EXPORTED METHODS TESTS */ 16 | 17 | // TestSignTransaction tests the functionality of the SignTransaction() method. 18 | func TestSignTransaction(t *testing.T) { 19 | privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) // Generate ecdsa private key 20 | if err != nil { // Check for errors 21 | t.Fatal(err) // Panic 22 | } 23 | 24 | transaction := &Transaction{ 25 | AccountNonce: 0, // Set nonce 26 | Sender: nil, // Set sender 27 | Recipient: nil, // Set recipient 28 | GasPrice: big.NewInt(1000), // Set gas price 29 | Payload: []byte("test"), // Set payload 30 | Signature: nil, // Set signature 31 | } // Initialize transaction 32 | 33 | transaction.Hash = crypto.Sha3(transaction.Bytes()) // Set hash 34 | 35 | err = SignTransaction(transaction, privateKey) // Sign transaction 36 | 37 | if err != nil { // Check for errors 38 | t.Fatal(err) // Panic 39 | } 40 | 41 | if transaction.Signature == nil { // Check was not signed 42 | t.Fatal("transaction not signed") // Panic 43 | } 44 | } 45 | 46 | // TestVerifySignature tests the functionality of the VerifySignature() method. 47 | func TestVerifySignature(t *testing.T) { 48 | privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) // Generate ecdsa private key 49 | if err != nil { // Check for errors 50 | t.Fatal(err) // Panic 51 | } 52 | 53 | transaction := &Transaction{ 54 | AccountNonce: 0, // Set nonce 55 | Sender: nil, // Set sender 56 | Recipient: nil, // Set recipient 57 | GasPrice: big.NewInt(1000), // Set gas price 58 | Payload: []byte("test"), // Set payload 59 | Signature: nil, // Set signature 60 | } // Initialize transaction 61 | 62 | transaction.Hash = crypto.Sha3(transaction.Bytes()) // Set hash 63 | 64 | err = SignTransaction(transaction, privateKey) // Sign transaction 65 | 66 | if err != nil { // Check for errors 67 | t.Fatal(err) // Panic 68 | } 69 | 70 | if !transaction.Signature.Verify(crypto.AddressFromPrivateKey(privateKey)) { // Check that signature is valid 71 | t.Fatal("signature should be valid") // Panic 72 | } 73 | } 74 | 75 | /* END EXPORTED METHODS TESTS */ 76 | -------------------------------------------------------------------------------- /types/transaction_test.go: -------------------------------------------------------------------------------- 1 | // Package types provides core primitives for the operation 2 | // of the Polaris protocol. 3 | package types 4 | 5 | import ( 6 | "crypto/ecdsa" 7 | "crypto/elliptic" 8 | "crypto/rand" 9 | "math/big" 10 | "testing" 11 | 12 | "github.com/polaris-project/go-polaris/crypto" 13 | ) 14 | 15 | /* BEGIN EXPORTED METHODS TESTS */ 16 | 17 | // TestNewTransactions tests the functionality of the NewTransaction method. 18 | func TestNewTransactions(t *testing.T) { 19 | transaction := NewTransaction( 20 | 0, // Nonce 21 | big.NewFloat(10), // Amount 22 | nil, // Sender 23 | nil, // Recipient 24 | nil, // Parents 25 | 1, // Gas limit 26 | big.NewInt(1000), // Gas price 27 | []byte("test payload"), // Payload 28 | ) // Create a new transaction using the NewTransaction method 29 | 30 | t.Log(transaction) // Log the initialized transaction 31 | } 32 | 33 | // TestCalculateTotalValue tests the functionality of the CalculateTotalValue() helper method. 34 | func TestCalculateTotalValue(t *testing.T) { 35 | privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) // Generate private key 36 | if err != nil { // Check for errors 37 | t.Fatal(err) // Panic 38 | } 39 | 40 | address := crypto.AddressFromPrivateKey(privateKey) // Generate address 41 | 42 | transaction := NewTransaction( 43 | 0, // Nonce 44 | big.NewFloat(5), // Amount 45 | address, // Sender 46 | nil, // Recipient 47 | nil, // Parents 48 | 1000, // Gas limit 49 | big.NewInt(1), // Gas price 50 | []byte("test payload"), // Payload 51 | ) // Initialize a new transaction 52 | 53 | if transaction.CalculateTotalValue().Cmp(big.NewFloat(5+1000)) != 0 { // Check invalid value calculation 54 | t.Fatal("invalid total value calculation") // Panic 55 | } 56 | } 57 | 58 | /* END EXPORTED METHODS TESTS */ 59 | -------------------------------------------------------------------------------- /validator/beacon_dag_validator.go: -------------------------------------------------------------------------------- 1 | // Package validator represents a collection of helper methods useful for validators in the Polaris network. 2 | // Methods in the validator package are specified in terms of a validator interface, that of which is 3 | // also implemented in the validator package. 4 | package validator 5 | 6 | import ( 7 | "bytes" 8 | "errors" 9 | 10 | "github.com/polaris-project/go-polaris/common" 11 | "github.com/polaris-project/go-polaris/config" 12 | "github.com/polaris-project/go-polaris/crypto" 13 | "github.com/polaris-project/go-polaris/types" 14 | ) 15 | 16 | const ( 17 | // BeaconDagValidatorValidationProtocol represents the validation protocol of the beacon dag validator. 18 | BeaconDagValidatorValidationProtocol = "beacon_simple_sig_ver" 19 | ) 20 | 21 | var ( 22 | // ErrInvalidTransactionHash is an error definition representing a transaction hash of invalid value. 23 | ErrInvalidTransactionHash = errors.New("transaction hash is invalid") 24 | 25 | // ErrInvalidTransactionTimestamp is an error definition representing a transaction timestamp of invalid value. 26 | ErrInvalidTransactionTimestamp = errors.New("invalid transaction timestamp") 27 | 28 | // ErrInvalidTransactionSignature is an error definition representing a transaction signature of invalid value. 29 | ErrInvalidTransactionSignature = errors.New("invalid transaction signature") 30 | 31 | // ErrInsufficientSenderBalance is an error definition representing a sender balance of insufficient value. 32 | ErrInsufficientSenderBalance = errors.New("insufficient sender balance") 33 | 34 | // ErrDuplicateTransaction is an error definition representing a transaction of duplicate value in the working dag. 35 | ErrDuplicateTransaction = errors.New("transaction already exists in the working dag (duplicate)") 36 | 37 | // ErrInvalidTransactionDepth is an error definition representing a transaction of invalid depth value. 38 | ErrInvalidTransactionDepth = errors.New("invalid transaction depth (not best transaction)") 39 | 40 | // ErrInvalidNonce is an error definition representing a transaction of invalid nonce value. 41 | ErrInvalidNonce = errors.New("invalid transaction nonce") 42 | ) 43 | 44 | // BeaconDagValidator represents a main dag validator. 45 | type BeaconDagValidator struct { 46 | Config *config.DagConfig `json:"config"` // Config represents the beacon dag config 47 | 48 | WorkingDag *types.Dag `json:"dag"` // Working validator dag 49 | } 50 | 51 | /* BEGIN EXPORTED METHODS */ 52 | 53 | // NewBeaconDagValidator initializes a new beacon dag with a given config and working dag. 54 | func NewBeaconDagValidator(config *config.DagConfig, workingDag *types.Dag) *BeaconDagValidator { 55 | return &BeaconDagValidator{ 56 | Config: config, // Set config 57 | WorkingDag: workingDag, // Set working dag 58 | } 59 | } 60 | 61 | // ValidateTransaction validates the given transaction, transaction via the standard beacon dag validator. 62 | // Each validation issue is returned as an error. 63 | func (validator *BeaconDagValidator) ValidateTransaction(transaction *types.Transaction) error { 64 | if !validator.ValidateTransactionHash(transaction) { // Check invalid hash 65 | return ErrInvalidTransactionHash // Invalid hash 66 | } 67 | 68 | if !validator.ValidateTransactionTimestamp(transaction) { // Check invalid timestamp 69 | return ErrInvalidTransactionTimestamp // Invalid timestamp 70 | } 71 | 72 | if !validator.ValidateTransactionSignature(transaction) { // Check invalid signature 73 | return ErrInvalidTransactionSignature // Invalid signature 74 | } 75 | 76 | if !validator.ValidateTransactionSenderBalance(transaction) { // Check invalid value 77 | return ErrInsufficientSenderBalance // Invalid value 78 | } 79 | 80 | if !validator.ValidateTransactionIsNotDuplicate(transaction) { // Check duplicate 81 | return ErrDuplicateTransaction // Duplicate 82 | } 83 | 84 | if !validator.ValidateTransactionDepth(transaction) { // Check valid depth 85 | return ErrInvalidTransactionDepth // Invalid depth 86 | } 87 | 88 | if !validator.ValidateTransactionNonce(transaction) { // Check valid nonce 89 | return ErrInvalidNonce // Invalid nonce 90 | } 91 | 92 | return nil // Transaction is valid 93 | } 94 | 95 | // ValidateTransactionHash checks that a given transaction's hash is equivalent to the calculated hash of that given transaction. 96 | func (validator *BeaconDagValidator) ValidateTransactionHash(transaction *types.Transaction) bool { 97 | if transaction.Hash.IsNil() { // Check transaction doesn't have transaction 98 | return false // No valid hash 99 | } 100 | 101 | unsignedTx := *transaction // Get unsigned 102 | 103 | unsignedTx.Hash = common.NewHash(nil) // Set hash to nil 104 | 105 | unsignedTx.Signature = transaction.Signature // Reset signature 106 | 107 | return bytes.Equal(transaction.Hash.Bytes(), crypto.Sha3(unsignedTx.Bytes()).Bytes()) // Return hashes equivalent 108 | } 109 | 110 | // ValidateTransactionTimestamp validates the given transaction's timestamp against that of its parents. 111 | // If the timestamp of any one of the given transaction's parents is after the given transaction's timestamp, false is returned. 112 | // If any one of the transaction's parent transactions cannot be found in the working dag, false is returned. 113 | func (validator *BeaconDagValidator) ValidateTransactionTimestamp(transaction *types.Transaction) bool { 114 | for _, parentHash := range transaction.ParentTransactions { // Iterate through parent hashes 115 | parentTransaction, err := validator.WorkingDag.GetTransactionByHash(parentHash) // Get parent transaction pointer 116 | if err != nil { // Check for errors 117 | return false // Invalid parent 118 | } 119 | 120 | if parentTransaction.Timestamp.After(transaction.Timestamp) { 121 | return false // Invalid timestamp 122 | } 123 | } 124 | 125 | return true // Valid timestamp 126 | } 127 | 128 | // ValidateTransactionSignature validates the given transaction's signature against the transaction sender's public key. 129 | // If the transaction's signature is nil, false is returned. 130 | func (validator *BeaconDagValidator) ValidateTransactionSignature(transaction *types.Transaction) bool { 131 | if transaction.Signature == nil { // Check has no signature 132 | return false // Nil signature 133 | } 134 | 135 | return transaction.Signature.Verify(transaction.Sender) // Return signature validity 136 | } 137 | 138 | // ValidateTransactionSenderBalance checks that a given transaction's sender has a balance greater than or equal to the transaction's total value (including gas costs). 139 | func (validator *BeaconDagValidator) ValidateTransactionSenderBalance(transaction *types.Transaction) bool { 140 | balance, err := validator.WorkingDag.CalculateAddressBalance(transaction.Sender) // Calculate balance 141 | if err != nil { // Check for errors 142 | return false // Invalid 143 | } 144 | 145 | return balance.Cmp(transaction.CalculateTotalValue()) == 0 || balance.Cmp(transaction.CalculateTotalValue()) == 1 // Return sender balance adequate 146 | } 147 | 148 | // ValidateTransactionIsNotDuplicate checks that a given transaction does not already exist in the working dag. 149 | func (validator *BeaconDagValidator) ValidateTransactionIsNotDuplicate(transaction *types.Transaction) bool { 150 | transaction, err := validator.WorkingDag.GetTransactionByHash(transaction.Hash) // Attempt to get tx by hash 151 | 152 | if err == nil && !transaction.Hash.IsNil() { // Check transaction exists 153 | return false // Transaction is duplicate 154 | } 155 | 156 | return true // Transaction is unique 157 | } 158 | 159 | // ValidateTransactionDepth checks that a given transaction's parent hash is a member of the last edge. 160 | func (validator *BeaconDagValidator) ValidateTransactionDepth(transaction *types.Transaction) bool { 161 | for _, parentHash := range transaction.ParentTransactions { // Iterate through parent hashes 162 | if bytes.Equal(parentHash.Bytes(), transaction.Hash.Bytes()) { // Check self in parent hashes 163 | return false // Invalid 164 | } 165 | 166 | children, err := validator.WorkingDag.GetTransactionChildren(parentHash) // Get children of transaction 167 | if err != nil { // Check for errors 168 | return false // Invalid 169 | } 170 | 171 | for _, child := range children { // Iterate through children 172 | currentChildren, err := validator.WorkingDag.GetTransactionChildren(child.Hash) // Get children of current child 173 | if err != nil { // Check for errors 174 | return false // Invalid 175 | } 176 | 177 | if len(currentChildren) != 0 { // Check child has children 178 | return false // Invalid depth 179 | } 180 | } 181 | } 182 | 183 | return true // Valid 184 | } 185 | 186 | // ValidateTransactionNonce checks that a given transaction's nonce is equivalent to the sending account's last nonce + 1. 187 | func (validator *BeaconDagValidator) ValidateTransactionNonce(transaction *types.Transaction) bool { 188 | senderTransactions, err := validator.WorkingDag.GetTransactionsBySender(transaction.Sender) // Get sender txs 189 | if err != nil { // Check for errors 190 | return false // Invalid 191 | } 192 | 193 | if len(senderTransactions) == 0 { // Check is genesis 194 | if transaction.AccountNonce != 0 { // Check nonce is not 0 195 | return false // Invalid nonce 196 | } 197 | 198 | return true // Valid nonce 199 | } 200 | 201 | lastNonce := uint64(0) // Init nonce buffer 202 | 203 | for _, currentTransaction := range senderTransactions { // Iterate through sender txs 204 | if currentTransaction.AccountNonce > lastNonce { // Check greater than last nonce 205 | lastNonce = currentTransaction.AccountNonce // Set last nonce 206 | } 207 | } 208 | 209 | if transaction.AccountNonce != lastNonce+1 { // Check invalid nonce 210 | return false // Invalid nonce 211 | } 212 | 213 | return true // Valid nonce 214 | } 215 | 216 | // ValidationProtocol fetches the current validator's validation protocol. 217 | func (validator *BeaconDagValidator) ValidationProtocol() string { 218 | return BeaconDagValidatorValidationProtocol // Return validation protocol 219 | } 220 | 221 | // GetWorkingDag attempts to fetch the working dag instance. 222 | func (validator *BeaconDagValidator) GetWorkingDag() *types.Dag { 223 | return validator.WorkingDag // Return working dag 224 | } 225 | 226 | // GetWorkingConfig attempts to fetch the working config instance. 227 | func (validator *BeaconDagValidator) GetWorkingConfig() *config.DagConfig { 228 | return validator.Config // Return working config 229 | } 230 | 231 | /* END EXPORTED METHODS */ 232 | -------------------------------------------------------------------------------- /validator/beacon_dag_validator_test.go: -------------------------------------------------------------------------------- 1 | // Package validator represents a collection of helper methods useful for validators in the Polaris network. 2 | // Methods in the validator package are specified in terms of a validator interface, that of which is 3 | // also implemented in the validator package. 4 | package validator 5 | 6 | import ( 7 | "crypto/ecdsa" 8 | "crypto/elliptic" 9 | "crypto/rand" 10 | "math/big" 11 | "os" 12 | "path/filepath" 13 | "testing" 14 | 15 | "github.com/polaris-project/go-polaris/common" 16 | "github.com/polaris-project/go-polaris/config" 17 | "github.com/polaris-project/go-polaris/crypto" 18 | "github.com/polaris-project/go-polaris/types" 19 | ) 20 | 21 | /* BEGIN EXPORTED METHODS TESTS */ 22 | 23 | // TestNewBeaconDagValidator tests the functionality of the NewBeaconDagValidator() helper method. 24 | func TestNewBeaconDagValidator(t *testing.T) { 25 | os.RemoveAll(filepath.FromSlash("data/db/test_network.db")) // Remove existing db 26 | 27 | dagConfig := config.NewDagConfig(nil, "test_network", 1) // Initialize new dag config with test genesis file. 28 | 29 | dag, err := types.NewDag(dagConfig) // Initialize dag with dag config 30 | if err != nil { // Check for errors 31 | t.Fatal(err) // Panic 32 | } 33 | 34 | validator := NewBeaconDagValidator(dagConfig, dag) // Initialize validator 35 | 36 | if validator == nil { // Check validator is nil 37 | t.Fatal("validator should not be nil") // Panic 38 | } 39 | 40 | types.WorkingDagDB.Close() // Close dag db 41 | 42 | os.RemoveAll(filepath.FromSlash("data/db/test_network.db")) // Remove existing db 43 | } 44 | 45 | // TestValidateTransaction tests the functionality of the ValidateTransaction() helper method. 46 | func TestValidateTransaction(t *testing.T) { 47 | os.RemoveAll(filepath.FromSlash("data/db/test_network.db")) // Remove existing db 48 | 49 | dagConfig := config.NewDagConfig(nil, "test_network", 1) // Initialize new dag config with test genesis file. 50 | 51 | dag, err := types.NewDag(dagConfig) // Initialize dag with dag config 52 | if err != nil { // Check for errors 53 | t.Fatal(err) // Panic 54 | } 55 | 56 | privateKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) // Generate private key 57 | if err != nil { // Check for errors 58 | t.Fatal(err) // Panic 59 | } 60 | 61 | address := crypto.AddressFromPrivateKey(privateKey) // Generate address 62 | 63 | transaction := types.NewTransaction( 64 | 0, // Nonce 65 | big.NewFloat(0), // Amount 66 | address, // Sender 67 | nil, // Recipient 68 | nil, // Parents 69 | 0, // Gas limit 70 | big.NewInt(0), // Gas price 71 | []byte("test payload"), // Payload 72 | ) // Initialize a new transaction 73 | 74 | err = types.SignTransaction(transaction, privateKey) // Sign transaction 75 | 76 | if err != nil { // Check for errors 77 | t.Fatal(err) // Panic 78 | } 79 | 80 | validator := NewBeaconDagValidator(dagConfig, dag) // Initialize validator 81 | 82 | if validator == nil { // Check validator is nil 83 | t.Fatal("validator should not be nil") // Panic 84 | } 85 | 86 | if err := validator.ValidateTransaction(transaction); err != nil { // Validate 87 | t.Fatalf("tx should be valid; got %s error", err.Error()) // Panic 88 | } 89 | 90 | err = dag.AddTransaction(transaction) // Add transaction 91 | 92 | if err != nil { // Check for errors 93 | t.Fatal(err) // Panic 94 | } 95 | 96 | child := types.NewTransaction( 97 | 1, // Nonce 98 | big.NewFloat(0), // Amount 99 | address, // Sender 100 | nil, // Recipient 101 | []common.Hash{transaction.Hash}, // Parents 102 | 0, // Gas limit 103 | big.NewInt(0), // Gas price 104 | []byte("test payload"), // Payload 105 | ) // Create child transaction 106 | 107 | sibling := types.NewTransaction( 108 | 2, // Nonce 109 | big.NewFloat(0), // Amount 110 | address, // Sender 111 | nil, // Recipient 112 | []common.Hash{transaction.Hash}, // Parents 113 | 0, // Gas limit 114 | big.NewInt(0), // Gas price 115 | []byte("test payload"), // Payload 116 | ) // Create child transaction 117 | 118 | err = types.SignTransaction(child, privateKey) // Sign transaction 119 | 120 | if err != nil { // Check for errors 121 | t.Fatal(err) // Panic 122 | } 123 | 124 | err = types.SignTransaction(sibling, privateKey) // Sign transaction 125 | 126 | if err != nil { // Check for errors 127 | t.Fatal(err) // Panic 128 | } 129 | 130 | if err := validator.ValidateTransaction(child); err != nil { // Validate 131 | t.Fatalf("tx should be valid; got %s error", err.Error()) // Panic 132 | } 133 | 134 | err = dag.AddTransaction(child) // Add child transaction 135 | 136 | if err != nil { // Check for errors 137 | t.Fatal(err) // Panic 138 | } 139 | 140 | if err := validator.ValidateTransaction(sibling); err != nil { // Validate 141 | t.Fatalf("tx should be valid; got %s error", err.Error()) // Panic 142 | } 143 | 144 | types.WorkingDagDB.Close() // Close dag db 145 | 146 | os.RemoveAll(filepath.FromSlash("data/db/test_network.db")) // Remove existing db 147 | } 148 | 149 | func TestBeaconDagValidationProtocol(t *testing.T) { 150 | os.RemoveAll(filepath.FromSlash("data/db/test_network.db")) // Remove existing db 151 | 152 | dagConfig := config.NewDagConfig(nil, "test_network", 1) // Initialize new dag config with test genesis file. 153 | 154 | dag, err := types.NewDag(dagConfig) // Initialize dag with dag config 155 | if err != nil { // Check for errors 156 | t.Fatal(err) // Panic 157 | } 158 | 159 | validator := NewBeaconDagValidator(dagConfig, dag) // Initialize validator 160 | 161 | if validator == nil { // Check validator is nil 162 | t.Fatal("validator should not be nil") // Panic 163 | } 164 | 165 | if protocol := validator.ValidationProtocol(); protocol != BeaconDagValidatorValidationProtocol { // Check invalid validation protocol 166 | t.Fatalf("invalid validation protocol: %s", protocol) // Log invalid validation protocol 167 | } 168 | 169 | types.WorkingDagDB.Close() // Close dag db 170 | 171 | os.RemoveAll(filepath.FromSlash("data/db/test_network.db")) // Remove existing db 172 | } 173 | 174 | /* END EXPORTED METHODS TESTS */ 175 | -------------------------------------------------------------------------------- /validator/validator.go: -------------------------------------------------------------------------------- 1 | // Package validator represents a collection of helper methods useful for validators in the Polaris network. 2 | // Methods in the validator package are specified in terms of a validator interface, that of which is 3 | // also implemented in the validator package. 4 | package validator 5 | 6 | import ( 7 | "github.com/polaris-project/go-polaris/config" 8 | "github.com/polaris-project/go-polaris/types" 9 | ) 10 | 11 | // Validator represents any generic validator. 12 | type Validator interface { 13 | ValidateTransaction(transaction *types.Transaction) error // Validate a given transaction 14 | 15 | ValidateTransactionHash(transaction *types.Transaction) bool // Validate a given transaction's hash 16 | 17 | ValidateTransactionTimestamp(transaction *types.Transaction) bool // Validate a given transaction's timestamp 18 | 19 | ValidateTransactionSignature(transaction *types.Transaction) bool // Validate a given transaction's signature 20 | 21 | ValidateTransactionSenderBalance(transaction *types.Transaction) bool // Validate a given transaction's sender has 22 | 23 | ValidateTransactionIsNotDuplicate(transaction *types.Transaction) bool // Validate that a given transaction does not already exist in the working dag 24 | 25 | ValidateTransactionDepth(transaction *types.Transaction) bool // Validate that a given transaction's parent is a current edge 26 | 27 | ValidateTransactionNonce(transaction *types.Transaction) bool // Validate that a given transaction's nonce is equivalent to the current account index + 1 28 | 29 | ValidationProtocol() string // Get the current validator's validation protocol 30 | 31 | GetWorkingDag() *types.Dag // Get current validator's working dag 32 | 33 | GetWorkingConfig() *config.DagConfig // Get current validator's working config 34 | } 35 | -------------------------------------------------------------------------------- /vm/protocol.go: -------------------------------------------------------------------------------- 1 | // Package vm defines the VirtualMachine interface, as well as standard helper 2 | // methods for configuring the standard WASM VM. 3 | package vm 4 | 5 | // Protocol defines a virtual machine protocol. 6 | type Protocol struct { 7 | LanguagesSupported []string `json:"languages"` // Languages supported by the VirtualMachine (e.g. wasm). 8 | } 9 | -------------------------------------------------------------------------------- /vm/vm.go: -------------------------------------------------------------------------------- 1 | // Package vm defines the VirtualMachine interface, as well as standard helper 2 | // methods for configuring the standard WASM VM. 3 | package vm 4 | 5 | // VirtualMachine defines a Polaris Virtual Machine. 6 | type VirtualMachine interface { 7 | GetVirtualMachineProtocol() *Protocol // Get virtual machine protocol. 8 | } 9 | --------------------------------------------------------------------------------