Browse Source

Derosuite Status Update Release 2

master
Captain Dero 6 years ago
parent
commit
9687ad9cb4
424 changed files with 179081 additions and 1242 deletions
  1. +1
    -0
      LICENSE
  2. +85
    -42
      README.md
  3. +90
    -0
      address/LICENSE
  4. +32
    -8
      address/address.go
  5. +23
    -9
      address/address_test.go
  6. +16
    -1
      address/base58.go
  7. +90
    -0
      block/LICENSE
  8. +31
    -15
      block/block.go
  9. +17
    -2
      block/block_test.go
  10. +20
    -2
      blockchain/alt_blocks.go
  11. +124
    -0
      blockchain/block_chain_input.go
  12. +569
    -136
      blockchain/blockchain.go
  13. +60
    -0
      blockchain/blockheader.go
  14. +16
    -0
      blockchain/caller.go
  15. +52
    -10
      blockchain/checkpoints_static.go
  16. +23
    -0
      blockchain/const.go
  17. +76
    -0
      blockchain/create_miner_tx.go
  18. +135
    -0
      blockchain/create_miner_tx_test.go
  19. +22
    -6
      blockchain/genesis.go
  20. +16
    -0
      blockchain/genesis_test.go
  21. +90
    -0
      blockchain/inputmaturity/LICENSE
  22. +66
    -0
      blockchain/inputmaturity/inputmaturity.go
  23. +144
    -0
      blockchain/inputmaturity/inputmaturity_test.go
  24. +50
    -0
      blockchain/median.go
  25. +66
    -0
      blockchain/median_test.go
  26. +0
    -97
      blockchain/mempool.go
  27. +90
    -0
      blockchain/mempool/LICENSE
  28. +216
    -0
      blockchain/mempool/mempool.go
  29. +132
    -0
      blockchain/mempool/mempool_test.go
  30. +308
    -28
      blockchain/outputs_index.go
  31. +2
    -2
      blockchain/readme.txt
  32. +16
    -1
      blockchain/reorg_test.go
  33. +90
    -0
      blockchain/rpcserver/LICENSE
  34. +12
    -0
      blockchain/rpcserver/dummy_test.go
  35. +47
    -0
      blockchain/rpcserver/echo.go
  36. +93
    -0
      blockchain/rpcserver/getblock.go
  37. +58
    -0
      blockchain/rpcserver/getblock_template.go
  38. +43
    -0
      blockchain/rpcserver/getblockcount.go
  39. +61
    -0
      blockchain/rpcserver/getblockheaderbyhash.go
  40. +72
    -0
      blockchain/rpcserver/getblockheaderbyheight.go
  41. +94
    -0
      blockchain/rpcserver/getinfo.go
  42. +49
    -0
      blockchain/rpcserver/getlastblockheader.go
  43. +95
    -0
      blockchain/rpcserver/getoutputs.bin.go
  44. +125
    -0
      blockchain/rpcserver/gettransactions.go
  45. +51
    -0
      blockchain/rpcserver/gettxpool.go
  46. +55
    -0
      blockchain/rpcserver/on_getblockhash.go
  47. +150
    -0
      blockchain/rpcserver/rpcserver.go
  48. +58
    -0
      blockchain/rpcserver/submit.go
  49. +0
    -9
      blockchain/signature.go
  50. +175
    -63
      blockchain/store.go
  51. +0
    -83
      blockchain/transaction_ringct_test.go
  52. +299
    -0
      blockchain/transaction_verify.go
  53. +96
    -0
      blockchain/tx_fees.go
  54. +13
    -61
      build_all.sh
  55. +78
    -0
      build_package.sh
  56. +106
    -0
      checkpoints/checkpoints.go
  57. +13
    -0
      checkpoints/dummy_test.go
  58. BIN
      checkpoints/mainnet_checkpoints.dat
  59. +84756
    -0
      checkpoints/mainnet_checkpoints.go
  60. +0
    -0
      checkpoints/testnet_checkpoints.dat
  61. +4
    -0
      checkpoints/testnet_checkpoints.go
  62. +90
    -0
      cmd/dero-wallet-cli/LICENSE
  63. +167
    -0
      cmd/dero-wallet-cli/daemon_communication.go
  64. +13
    -0
      cmd/dero-wallet-cli/dummy_test.go
  65. +107
    -0
      cmd/dero-wallet-cli/easymenu_post_open.go
  66. +132
    -0
      cmd/dero-wallet-cli/easymenu_pre_open.go
  67. BIN
      cmd/dero-wallet-cli/getoutputs.bin
  68. +502
    -0
      cmd/dero-wallet-cli/main.go
  69. +207
    -0
      cmd/dero-wallet-cli/prompt.go
  70. +90
    -0
      cmd/derod/LICENSE
  71. +6
    -2
      cmd/derod/dummy_test.go
  72. +101
    -27
      cmd/derod/main.go
  73. +90
    -0
      cmd/explorer/LICENSE
  74. +12
    -0
      cmd/explorer/dummy_test.go
  75. +673
    -0
      cmd/explorer/explorer.go
  76. +489
    -0
      cmd/explorer/templates.go
  77. +90
    -0
      config/LICENSE
  78. +39
    -2
      config/config.go
  79. +6
    -2
      config/dummy_test.go
  80. +90
    -0
      crypto/LICENSE
  81. +1444
    -0
      crypto/const.go
  82. +196
    -0
      crypto/crypto_test.go
  83. +3176
    -0
      crypto/edwards25519.go
  84. +1630
    -0
      crypto/edwards25519_test.go
  85. +21
    -0
      crypto/hash.go
  86. +16
    -2
      crypto/keccak.go
  87. +16
    -22
      crypto/keccak_test.go
  88. +392
    -1
      crypto/key.go
  89. +163
    -0
      crypto/public_private_test.go
  90. +90
    -0
      crypto/ringct/LICENSE
  91. +25
    -9
      crypto/ringct/basic.go
  92. +19
    -2
      crypto/ringct/const.go
  93. +15
    -0
      crypto/ringct/edwards25519.go
  94. +16
    -0
      crypto/ringct/edwards25519_test.go
  95. +103
    -17
      crypto/ringct/key.go
  96. +224
    -30
      crypto/ringct/mlsag.go
  97. +36
    -0
      crypto/ringct/order_test.go
  98. +123
    -118
      crypto/ringct/range.go
  99. +28
    -17
      crypto/ringct/range_test.go
  100. +156
    -68
      crypto/ringct/ringct.go

+ 1
- 0
LICENSE

@ -87,3 +87,4 @@ READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING.
BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS. BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS.
IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM. IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM.

+ 85
- 42
README.md

@ -1,34 +1,78 @@
# DERO: Secure, Private Blockchain with Smart Contracts # DERO: Secure, Private Blockchain with Smart Contracts
## DERO Project : Cryptonote + Smart contracts + Lightning fast transactions.
## DERO Project : Cryptonote + Smart contracts
DERO blockchain is a complete new blockchain supporting privacy on cryptonote protocol and smart contracts with lightning fast transactions.
DERO blockchain is a complete new blockchain supporting CryptoNote Privacy and Smart Contracts.
DERO blockchain is being implemented in Golang. DERO blockchain is being implemented in Golang.
We are pleased to announce status update release 1 of DERO Blockchain.
We are pleased to announce Status Update Release 2 of DERO Blockchain.
Release 2 include following:
1. Dero daemon
2. Dero wallet both offline and online
3. Dero Explorer
| Operating System | Download |
| ---------------- | -------- |
| Windows 32 | http://seeds.dero.io/build/derod-windows-386.exe |
| Windows 64 | http://seeds.dero.io/build/derod-windows-amd64.exe |
| Mac 10.8 & Later | http://seeds.dero.io/build/derod-darwin-amd64 |
| Linux 32 | http://seeds.dero.io/build/derod-linux-386 |
| Linux 64 | http://seeds.dero.io/build/derod-linux-amd64 |
| OpenBSD 64 | http://seeds.dero.io/build/derod-openbsd-amd64 |
| FreeBSD 64 | http://seeds.dero.io/build/derod-freebsd-amd64 |
| Linux ARM 64 | http://seeds.dero.io/build/derod-linux-arm64 |
| More Builds | http://seeds.dero.io/build/ |
** NOTE: All above are strictly for evaluation and have limitations, see below for more details.**
| Operating System | Download |
| ---------------- | ---------------------------------------- |
| Windows 32 | http://seeds.dero.io/build/dero_windows_386.zip |
| Windows 64 | http://seeds.dero.io/build/dero_windows_amd64.zip |
| Mac 10.8 & Later | http://seeds.dero.io/build/dero_darwin_amd64.tar.gz |
| Linux 32 | http://seeds.dero.io/build/dero_linux_386.tar.gz |
| Linux 64 | http://seeds.dero.io/build/dero_linux_amd64.tar.gz |
| OpenBSD 64 | http://seeds.dero.io/build/dero_openbsd_amd64.tar.gz |
| FreeBSD 64 | http://seeds.dero.io/build/dero_freebsd_amd64.tar.gz |
| Linux ARM 64 | http://seeds.dero.io/build/dero_linux_arm64.tar.gz |
| Solaris AMD64 | http://seeds.dero.io/build/dero_solaris_amd64.tar.gz |
| More Builds | http://seeds.dero.io/build/ |
**NOTE: DO NOT MIGRATE to this daemon. This is strictly for evaluation.** **NOTE: DO NOT MIGRATE to this daemon. This is strictly for evaluation.**
![Status-release-update-1](http://seeds.dero.io/images/status-release-1.png)
DERO Daemon\
![Status-Update-Release-2 DERO Daemon](http://seeds.dero.io/images/derod.png)\
DERO Wallet\
![Status-Update-Release-2 DERO Wallet](http://seeds.dero.io/images/dero_wallet_offline.png)\
DERO Explorer\
![Status-Update-Release-2 DERO Explorer](http://seeds.dero.io/images/dero_explorer.png)\
In the status update release 2, Golang DERO daemon can sync and verify blockchain and show users their wallet balance with the existing DERO network. This update marks the release of
1. **Dero Wallet** : The new version of wallet has easy to use menu-driven interface. The new wallet has ability to work in both on-line and completely off-line modes.
It can be used to
1. create new accounts,
2. check balance,
3. display and recover using recovery seeds, ( 25 words). The seeds are compatible with existing wallet.
4. 11 languages are supported for recovery seeds
1. English,
2. Japanese (日本語)
3. Chinese_Simplified(简体中文 (中国)),
4. Dutch (Nederlands),
5. Esperanto ,
6. Russian (русский язык),
7. Spanish (Español),
8. Portuguese (Português),
9. French (Français),
10. German (Deutsch),
11. Italian (Italiano),
4. display and recover using recovery key (64 hex chars)
5. view only wallets.
6. Online mode ( connects live to the daemon using RPC)
7. Offline mode ( works without internet or daemon). The wallet can work in completely offline mode. To use the wallet in offline mode, download and copy this file URL to wallet directory. You can yourself create this data file if you run the golang daemon and execute ```wget http://127.0.0.1:9999/getoutputs.bin ``` .
2. **Blockchain Explorer** : A tool to monitor and interact the DERO network and its state. It allows anyone to browse/parse/locate any transaction/block etc. The tool works over RPC interface and connects with dero daemon golang version. Anyone running the golang dero daemon, can run the explorer and immediately and access it using browser at http://127.0.0.1:8080/ . This increases privacy as some users do not want to use the publicly hosted block explorers. The explorer is almost complete (except 1 feature). Any ideas on increasing usability of block explorer are welcome. More features will be implemented as the smart contracts are implemented.
3. **Dero Daemon**: It is mostly complete. However, mining has been disabled until more testing is complete. RPC is implemented.
In the status update release 1, Following parts of cryptonote has been rewritten in golang.
At present, Golang DERO daemon can sync and verify blockchain with the existing DERO network.
For specific details of current DERO core implementation and capabilities, see below:
**REMEMBER to save your seeds (otherwise you will loose access to wallet when you exit wallet program).**
For specific details of current DERO core (daemon) implementation and capabilities, see below:
1. **Cryptonight Hash:** This is an ASIC resistant, memory-bound algorithm. This provides assurance that all miners are equal. ( No miner has any advantage over common miners). 1. **Cryptonight Hash:** This is an ASIC resistant, memory-bound algorithm. This provides assurance that all miners are equal. ( No miner has any advantage over common miners).
2. **Wire protocol (90% completed):** This protocol is used to exchange data between 2 DERO daemon nodes. At this point, Go daemon can connect to C daemon and vice-versa, sync blockchain and exchange, already possible. Complete interoperability has been achieved. This has 3 sub protocols: 2. **Wire protocol (90% completed):** This protocol is used to exchange data between 2 DERO daemon nodes. At this point, Go daemon can connect to C daemon and vice-versa, sync blockchain and exchange, already possible. Complete interoperability has been achieved. This has 3 sub protocols:
@ -38,41 +82,40 @@ For specific details of current DERO core implementation and capabilities, see b
3. **Pederson Commitment:** (Part of ring confidential transactions): Pederson commitment algorithm is a cryptographic primitive that allows user to commit to a chosen value while keeping it hidden to others. Pederson commitment is used to hide all amounts without revealing the actual amount. It is a homomorphic commitment scheme. 3. **Pederson Commitment:** (Part of ring confidential transactions): Pederson commitment algorithm is a cryptographic primitive that allows user to commit to a chosen value while keeping it hidden to others. Pederson commitment is used to hide all amounts without revealing the actual amount. It is a homomorphic commitment scheme.
4. **Borromean Signature:** (Part of ring confidential transactions): Borromean Signatures are used to prove that the commitment has a specific value, without revealing the value itself. 4. **Borromean Signature:** (Part of ring confidential transactions): Borromean Signatures are used to prove that the commitment has a specific value, without revealing the value itself.
5. **Additive Homomorphic Encryption:** Additive Homomorphic Encryption is used to prove that sum of encrypted Input transaction amounts is EQUAL to sum of encrypted output amounts. This is based on Homomorphic Pederson commitment scheme. 5. **Additive Homomorphic Encryption:** Additive Homomorphic Encryption is used to prove that sum of encrypted Input transaction amounts is EQUAL to sum of encrypted output amounts. This is based on Homomorphic Pederson commitment scheme.
6. **Multilayered Linkable Spontaneous Anonymous Group (MLSAG) Work-in-Progress:** (Part of ring confidential transactions): MLSAG gives DERO untraceability and increases privacy and fungibility. MLSAG is a user controlled parameter ( Mixin) which the user can change to improve his privacy. Mixin of minimal amount is enforced and user cannot disable it.
7. **Core-Consensus Protocol implemented:** Consensus protocol serves 2 major purpose
6. **Multilayered Linkable Spontaneous Anonymous Group (MLSAG) :** (Part of ring confidential transactions): MLSAG gives DERO untraceability and increases privacy and fungibility. MLSAG is a user controlled parameter ( Mixin) which the user can change to improve his privacy. Mixin of minimal amount is enforced and user cannot disable it.
7. **Ring Confidential Transactions:** Gives untraceability , privacy and fungibility while making sure that the system is stable and secure.
8. **Core-Consensus Protocol implemented:** Consensus protocol serves 2 major purpose
1. Protects the system from adversaries and protects it from forking and tampering. 1. Protects the system from adversaries and protects it from forking and tampering.
2. Next block in the chain is the one and only correct version of truth ( balances)
8. **Proof-of-Work(PoW) algorithm:** PoW part of core consensus protocol which is used to cryptographically prove that X amount of work has been done to successfully find a block. To deter use of specialized hardware, an ASIC resistant, memory bound cryptonight algorithm is used in DERO project.
9. **Difficulty algorithm**: Difficulty algorithm controls the system so as blocks are found roughly at the same speed, irrespective of the number and amount of mining power deployed.
10. **Serialization/De-serialization of blocks**: Capability to encode/decode/process blocks .
11. **Serialization/De-serialization of transactions**: Capability to encode/decode/process transactions.
12. **Socks proxy:** Socks proxy has been implemented and integrated within the daemon to decrease user identifiability and improve user anonymity.
13. **Interactive daemon** can print blocks, txs, even entire blockchain from within the daemon
14. **status, diff, print_bc, print_block, print_tx** and several other commands implemented
15. GO DERO Daemon has both mainnet, testnet support.
16. Tree-hash for transactions (based on keccak): This merkle root allows user to verify transactions as needed without adding transaction body to block header.
17. BOLT Database: DERO Blockchain uses BoltDB for future scalability and low latency reads.
18. **Enhanced Reliability, Privacy, Security, Useability, Portabilty assured.** For discussion on each point how pls visit forum.
2. Next block in the chain is the one and only correct version of truth ( balances).
9. **Proof-of-Work(PoW) algorithm:** PoW part of core consensus protocol which is used to cryptographically prove that X amount of work has been done to successfully find a block. To deter use of specialized hardware, an ASIC resistant, memory bound cryptonight algorithm is used in DERO project.
10. **Difficulty algorithm**: Difficulty algorithm controls the system so as blocks are found roughly at the same speed, irrespective of the number and amount of mining power deployed.
11. **Serialization/De-serialization of blocks**: Capability to encode/decode/process blocks .
12. **Serialization/De-serialization of transactions**: Capability to encode/decode/process transactions.
13. **Transaction validity and verification**: Any transactions flowing within the DERO network are validated,verified
14. **Mempool**: Mempool has been implemented .
15. **Socks proxy:** Socks proxy has been implemented and integrated within the daemon to decrease user identifiability and improve user anonymity.
16. **Interactive daemon** can print blocks, txs, even entire blockchain from within the daemon
17. **status, diff, print_bc, print_block, print_tx** and several other commands implemented
18. GO DERO Daemon has both mainnet, testnet support.
19. Tree-hash for transactions (based on keccak): This merkle root allows user to verify transactions as needed without adding transaction body to block header.
20. **Enhanced Reliability, Privacy, Security, Useability, Portabilty assured.** For discussion on each point how pls visit forum.
The daemon is only for limited testing and evaluation purposes only.
The daemon and other programs are only for limited testing and evaluation purposes only.
**NOTE: DO NOT MIGRATE to this daemon. This is strictly for evaluation.** **NOTE: DO NOT MIGRATE to this daemon. This is strictly for evaluation.**
**NOTE:** Following limitations apply in the current derosuite version.
**NOTE:** Following limitations apply in the current golang version.
- Go Daemon has hard-code seed node address.
- RPC interface not exported
- Daemon mining is disabled until more testing complete.
- The wallet cannot create and send new transactions.
- The golang versions of derosuite are using non-standard ports so as it does NOT clash with already running daemon.
## Build: ## Build:
In go workspace: **go get -u github.com/deroproject/derosuite/...** In go workspace: **go get -u github.com/deroproject/derosuite/...**
Check bin folder for derod binary. Use golang-1.9 version minimum.
Check bin folder for derod, explorer and wallet binaries. Use golang-1.9 version minimum.
For technical issues and discussion, please visit https://forum.dero.io For technical issues and discussion, please visit https://forum.dero.io

+ 90
- 0
address/LICENSE

@ -0,0 +1,90 @@
RESEARCH LICENSE
Version 1.1.2
I. DEFINITIONS.
"Licensee " means You and any other party that has entered into and has in effect a version of this License.
“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees.
"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology.
"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage.
"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License.
"Technology Site" means the website designated by Licensor for accessing the Technology.
"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License.
II. PURPOSE.
Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology.
COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT <url>.
III. RESEARCH USE RIGHTS.
A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only:
1. reproduce, create Modifications of, and use the Technology alone, or with Modifications;
2. share source code of the Technology alone, or with Modifications, with other Licensees;
3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and
4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology.
B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights.
C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License.
D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution.
IV. INTELLECTUAL PROPERTY REQUIREMENTS
As a condition to Your License, You agree to comply with the following restrictions and responsibilities:
A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology.
B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License.
V. GENERAL TERMS.
A. Disclaimer Of Warranties.
TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE.
B. Infringement; Limitation Of Liability.
1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site.
2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY.
C. Termination.
1. You may terminate this License at any time by notifying Licensor in writing.
2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance.
3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination.
D. Miscellaneous.
1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor.
2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof.
3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate.
4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter.
5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications.
READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING.
BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS.
IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM.

+ 32
- 8
address/address.go

@ -1,3 +1,19 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package address package address
import "fmt" import "fmt"
@ -6,11 +22,12 @@ import "encoding/binary"
import "github.com/deroproject/derosuite/crypto" import "github.com/deroproject/derosuite/crypto"
// see https://cryptonote.org/cns/cns007.txt to understand address more
type Address struct { type Address struct {
Network uint64
SpendingKey []byte
ViewingKey []byte
Network uint64
SpendKey crypto.Key
ViewKey crypto.Key
//TODO add support for integrated address //TODO add support for integrated address
} }
@ -32,11 +49,16 @@ func (a *Address) Base58() (result string) {
n := binary.PutUvarint(prefix, a.Network) n := binary.PutUvarint(prefix, a.Network)
prefix = prefix[:n] prefix = prefix[:n]
checksum := GetChecksum(prefix, a.SpendingKey, a.ViewingKey)
result = EncodeDeroBase58(prefix, a.SpendingKey, a.ViewingKey, checksum[:])
checksum := GetChecksum(prefix, a.SpendKey[:], a.ViewKey[:])
result = EncodeDeroBase58(prefix, a.SpendKey[:], a.ViewKey[:], checksum[:])
return return
} }
// stringifier
func (a Address) String() string {
return a.Base58()
}
func NewAddress(address string) (result *Address, err error) { func NewAddress(address string) (result *Address, err error) {
raw := DecodeDeroBase58(address) raw := DecodeDeroBase58(address)
@ -62,10 +84,12 @@ func NewAddress(address string) (result *Address, err error) {
raw = raw[done:] raw = raw[done:]
result = &Address{ result = &Address{
Network: address_prefix,
SpendingKey: raw[0:32],
ViewingKey: raw[32:64],
Network: address_prefix,
//SpendKey: raw[0:32],
//ViewKey: raw[32:64],
} }
copy(result.SpendKey[:], raw[0:32])
copy(result.ViewKey[:], raw[32:64])
return return
} }

+ 23
- 9
address/address_test.go

@ -1,3 +1,19 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package address package address
import "fmt" import "fmt"
@ -7,8 +23,6 @@ import "encoding/hex"
import "github.com/deroproject/derosuite/config" import "github.com/deroproject/derosuite/config"
func TestAddressError(t *testing.T) { func TestAddressError(t *testing.T) {
_, err := NewAddress("") _, err := NewAddress("")
/*want := "Address is the wrong length" /*want := "Address is the wrong length"
@ -24,9 +38,9 @@ func TestAddressError(t *testing.T) {
} }
func TestAddress(t *testing.T) { func TestAddress(t *testing.T) {
const Monero_MainNetwork = 18
const Monero_TestNetwork = 53
const Monero_MainNetwork = 18
const Monero_TestNetwork = 53
tests := []struct { tests := []struct {
name string name string
@ -101,12 +115,12 @@ func TestAddress(t *testing.T) {
continue continue
} }
if bytes.Compare(address.SpendingKey, spendingKey) != 0 {
t.Errorf("%s: want: %x, got: %x", test.name, spendingKey, address.SpendingKey)
if bytes.Compare(address.SpendKey[:], spendingKey) != 0 {
t.Errorf("%s: want: %x, got: %x", test.name, spendingKey, address.SpendKey)
continue continue
} }
if bytes.Compare(address.ViewingKey, viewingKey) != 0 {
t.Errorf("%s: want: %x, got: %x", test.name, viewingKey, address.ViewingKey)
if bytes.Compare(address.ViewKey[:], viewingKey) != 0 {
t.Errorf("%s: want: %x, got: %x", test.name, viewingKey, address.ViewKey)
continue continue
} }

+ 16
- 1
address/base58.go

@ -1,9 +1,24 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package address package address
import "strings" import "strings"
import "math/big" import "math/big"
// all characters in the base58 // all characters in the base58
const BASE58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz" const BASE58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"

+ 90
- 0
block/LICENSE

@ -0,0 +1,90 @@
RESEARCH LICENSE
Version 1.1.2
I. DEFINITIONS.
"Licensee " means You and any other party that has entered into and has in effect a version of this License.
“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees.
"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology.
"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage.
"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License.
"Technology Site" means the website designated by Licensor for accessing the Technology.
"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License.
II. PURPOSE.
Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology.
COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT <url>.
III. RESEARCH USE RIGHTS.
A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only:
1. reproduce, create Modifications of, and use the Technology alone, or with Modifications;
2. share source code of the Technology alone, or with Modifications, with other Licensees;
3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and
4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology.
B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights.
C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License.
D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution.
IV. INTELLECTUAL PROPERTY REQUIREMENTS
As a condition to Your License, You agree to comply with the following restrictions and responsibilities:
A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology.
B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License.
V. GENERAL TERMS.
A. Disclaimer Of Warranties.
TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE.
B. Infringement; Limitation Of Liability.
1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site.
2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY.
C. Termination.
1. You may terminate this License at any time by notifying Licensor in writing.
2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance.
3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination.
D. Miscellaneous.
1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor.
2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof.
3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate.
4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter.
5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications.
READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING.
BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS.
IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM.

blockchain/block.go → block/block.go

@ -1,4 +1,20 @@
package blockchain
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package block
import "fmt" import "fmt"
import "bytes" import "bytes"
@ -10,8 +26,7 @@ import "github.com/romana/rlog"
import "github.com/deroproject/derosuite/crypto" import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/config" import "github.com/deroproject/derosuite/config"
import "github.com/deroproject/derosuite/cryptonight" import "github.com/deroproject/derosuite/cryptonight"
import "github.com/deroproject/derosuite/transaction"
// these are defined in file // these are defined in file
//https://github.com/monero-project/monero/src/cryptonote_basic/cryptonote_basic.h //https://github.com/monero-project/monero/src/cryptonote_basic/cryptonote_basic.h
@ -25,13 +40,19 @@ type Block_Header struct {
type Block struct { type Block struct {
Block_Header Block_Header
Miner_tx Transaction `json:"miner_tx"`
Merkle_Root crypto.Hash `json:"-"`
Tx_hashes []crypto.Hash `json:"tx_hashes"`
Miner_tx transaction.Transaction `json:"miner_tx"`
Merkle_Root crypto.Hash `json:"-"`
Tx_hashes []crypto.Hash `json:"tx_hashes"`
treehash crypto.Hash treehash crypto.Hash
} }
// we process incoming blocks in this format
type Complete_Block struct {
Bl *Block
Txs []*transaction.Transaction
}
// see spec here https://cryptonote.org/cns/cns003.txt // see spec here https://cryptonote.org/cns/cns003.txt
// this function gets the block identifier hash // this function gets the block identifier hash
func (bl *Block) GetHash() (hash crypto.Hash) { func (bl *Block) GetHash() (hash crypto.Hash) {
@ -222,8 +243,8 @@ func (bl *Block) Deserialize(buf []byte) (err error) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
logger.Warnf("Panic while deserialising block, block hex_dump below to make a testcase/debug\n")
logger.Warnf("%s", hex.EncodeToString(buf))
fmt.Printf("Panic while deserialising block, block hex_dump below to make a testcase/debug\n")
fmt.Printf("%s", hex.EncodeToString(buf))
err = fmt.Errorf("Invalid Block") err = fmt.Errorf("Invalid Block")
return return
} }
@ -235,7 +256,6 @@ func (bl *Block) Deserialize(buf []byte) (err error) {
} }
buf = buf[done:] buf = buf[done:]
bl.Major_Version = uint32(tmp) bl.Major_Version = uint32(tmp)
if uint64(bl.Major_Version) != tmp { if uint64(bl.Major_Version) != tmp {
@ -266,8 +286,6 @@ func (bl *Block) Deserialize(buf []byte) (err error) {
bl.Nonce = binary.LittleEndian.Uint32(buf) bl.Nonce = binary.LittleEndian.Uint32(buf)
buf = buf[4:] // nonce is always 4 bytes buf = buf[4:] // nonce is always 4 bytes
// read and parse transaction // read and parse transaction
err = bl.Miner_tx.DeserializeHeader(buf) err = bl.Miner_tx.DeserializeHeader(buf)
@ -275,9 +293,8 @@ func (bl *Block) Deserialize(buf []byte) (err error) {
return fmt.Errorf("Cannot parse miner TX %x", buf) return fmt.Errorf("Cannot parse miner TX %x", buf)
} }
// if tx was parse, make sure it's coin base // if tx was parse, make sure it's coin base
if len(bl.Miner_tx.Vin) != 1 || bl.Miner_tx.Vin[0].(Txin_gen).Height > config.MAX_CHAIN_HEIGHT {
if len(bl.Miner_tx.Vin) != 1 || bl.Miner_tx.Vin[0].(transaction.Txin_gen).Height > config.MAX_CHAIN_HEIGHT {
// serialize transaction again to get the tx size, so as parsing could continue // serialize transaction again to get the tx size, so as parsing could continue
return fmt.Errorf("Invalid Miner TX") return fmt.Errorf("Invalid Miner TX")
} }
@ -302,7 +319,7 @@ func (bl *Block) Deserialize(buf []byte) (err error) {
buf = buf[32:] buf = buf[32:]
bl.Tx_hashes = append(bl.Tx_hashes, h) bl.Tx_hashes = append(bl.Tx_hashes, h)
} }
//fmt.Printf("%d member in tx hashes \n",len(bl.Tx_hashes)) //fmt.Printf("%d member in tx hashes \n",len(bl.Tx_hashes))
@ -310,4 +327,3 @@ func (bl *Block) Deserialize(buf []byte) (err error) {
return return
} }

blockchain/block_test.go → block/block_test.go

@ -1,5 +1,20 @@
package blockchain
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package block
import "bytes" import "bytes"
import "testing" import "testing"

+ 20
- 2
blockchain/alt_blocks.go

@ -1,8 +1,26 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain package blockchain
import "fmt" import "fmt"
import "encoding/hex" import "encoding/hex"
import "github.com/deroproject/derosuite/block"
// this file only contains an altchain, 13 long // this file only contains an altchain, 13 long
// which can be used to test out consensus on live data in house // which can be used to test out consensus on live data in house
@ -72,7 +90,7 @@ func (chain *Blockchain) Inject_Alt_Chain() {
} }
func (chain *Blockchain) inject_block(x []byte) { func (chain *Blockchain) inject_block(x []byte) {
var bl Block
var bl block.Block
if len(x) < 20 { if len(x) < 20 {
fmt.Printf("block cannot be injected for sure\n") fmt.Printf("block cannot be injected for sure\n")
@ -85,5 +103,5 @@ func (chain *Blockchain) inject_block(x []byte) {
return return
} }
chain.Chain_Add(&bl)
//chain.Chain_Add(&bl)
} }

+ 124
- 0
blockchain/block_chain_input.go

@ -0,0 +1,124 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain
/*
import log "github.com/sirupsen/logrus"
import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/block"
import "github.com/deroproject/derosuite/transaction"
//import "github.com/deroproject/derosuite/blockchain/mempool"
*/
// DERO blockchain has been designed/developed as a state machine ( single-threaded)
// The state machine cannot change until there is external input
// the blockchain has 2 events as input
// 1) new block
// 2) new transaction
// So, the blockchain just waits for events from 2 sources
// 1) p2p layer ( network did a trasaction or found new block after mining)
// 2) user side ( user did a transaction or found new block after mining)
// the design has been simplified so as smart contracts can be integrated easily
// NOTE that adding a block is an atomic event in DERO blockchain
//
//
// This is the global event handler for block
// any block whether mined locally or via network must be dispatched using this channel
//var Incoming_Block_Channel = make(chan *block.Complete_Block, 512) // upto 500 blocks can be queued
//var Incoming_Transaction_Channel = make(chan *transaction.Transaction, 512) // upto 500 transactions can be queued
/*
// infinite looping function to process incoming block
// below event loops are never terminated, not even while exiting
// but we take the lock of chain, so as state/db cannot be changed
// also note that p2p layer is stopped earlier, so input cannot appear
func (chain *Blockchain) Handle_Block_Event_Loop(){
for{
select{
case <-chain.Exit_Event:
logger.Debugf("Exiting Block event loop")
return
default:
}
select{
case <-chain.Exit_Event:
logger.Debugf("Exiting Block event loop")
return
case complete_bl := <- Incoming_Block_Channel:
logger.Debugf("Incoming New Block")
func (){
var blid crypto.Hash
_ = blid
// defer func() { // safety so if anything wrong happens, verification fails
/// if r := recover(); r != nil {
// logger.WithFields( log.Fields{"blid": blid}).Warnf("Recovered while processing incoming block")
// }}()
blid = complete_bl.Bl.GetHash()
chain.add_Complete_Block(complete_bl)
}()
//default:
//case <- Exit_Event:
}
}
}
// infinite looping function to process incoming block
func (chain *Blockchain) Handle_Transaction_Event_Loop(){
for{
select {
case <-chain.Exit_Event:
logger.Debugf("Exiting Block event loop")
return
case tx := <- Incoming_Transaction_Channel:
logger.Debugf("Incoming New Transaction")
func() {
var txid crypto.Hash
defer func() { // safety so if anything wrong happens, verification fails
if r := recover(); r != nil {
logger.WithFields( log.Fields{"txid": txid}).Warnf("Recovered while Verifying transaction, failed verification")
//result = false
}}()
txid = tx.GetHash()
}()
// case <- Exit_Event:
}
}
}
*/

+ 569
- 136
blockchain/blockchain.go

@ -1,12 +1,34 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain package blockchain
// This file runs the core consensus protocol
// please think before randomly editing for after effects
// We must not call any packages that can call panic
// NO Panics or FATALs please
import "os"
//import "os"
import "fmt" import "fmt"
import "sort" import "sort"
import "sync" import "sync"
import "time"
import "bytes" import "bytes"
import "sync/atomic" import "sync/atomic"
import "runtime/debug"
import log "github.com/sirupsen/logrus" import log "github.com/sirupsen/logrus"
import "github.com/romana/rlog" import "github.com/romana/rlog"
@ -17,8 +39,11 @@ import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/storage" import "github.com/deroproject/derosuite/storage"
import "github.com/deroproject/derosuite/difficulty" import "github.com/deroproject/derosuite/difficulty"
import "github.com/deroproject/derosuite/crypto/ringct" import "github.com/deroproject/derosuite/crypto/ringct"
import "github.com/deroproject/derosuite/block"
import "github.com/deroproject/derosuite/transaction"
import "github.com/deroproject/derosuite/checkpoints"
import "github.com/deroproject/derosuite/blockchain/mempool"
import "github.com/deroproject/derosuite/blockchain/inputmaturity"
// all components requiring access to blockchain must use , this struct to communicate // all components requiring access to blockchain must use , this struct to communicate
// this structure must be update while mutex // this structure must be update while mutex
@ -28,13 +53,21 @@ type Blockchain struct {
height_seen uint64 // height seen on peers height_seen uint64 // height seen on peers
Top_ID crypto.Hash // id of the top block Top_ID crypto.Hash // id of the top block
Difficulty uint64 // current cumulative difficulty Difficulty uint64 // current cumulative difficulty
Mempool *Mempool
Mempool *mempool.Mempool
Exit_Event chan bool // blockchain is shutting down and we must quit ASAP
Top_Block_Median_Size uint64 // median block size of current top block
Top_Block_Base_Reward uint64 // top block base reward
checkpints_disabled bool // are checkpoints disabled
sync.RWMutex sync.RWMutex
} }
var logger *log.Entry var logger *log.Entry
//var Exit_Event = make(chan bool) // causes all threads to exit
// All blockchain activity is store in a single // All blockchain activity is store in a single
/* do initialisation , setup storage, put genesis block and chain in store /* do initialisation , setup storage, put genesis block and chain in store
@ -48,31 +81,66 @@ func Blockchain_Start(params map[string]interface{}) (*Blockchain, error) {
logger = globals.Logger.WithFields(log.Fields{"com": "BLKCHAIN"}) logger = globals.Logger.WithFields(log.Fields{"com": "BLKCHAIN"})
logger.Infof("Initialising blockchain") logger.Infof("Initialising blockchain")
init_checkpoints() // init some hard coded checkpoints
init_static_checkpoints() // init some hard coded checkpoints
chain.store = storage.Bolt_backend // setup backend chain.store = storage.Bolt_backend // setup backend
chain.store.Init(params) // init backend chain.store.Init(params) // init backend
chain.checkpints_disabled = params["--disable-checkpoints"].(bool)
chain.Exit_Event = make(chan bool) // init exit channel
// init mempool before chain starts
chain.Mempool, err = mempool.Init_Mempool(params)
// we need to check mainnet/testnet check whether the genesis block matches the testnet/mainet
// mean whether the user is trying to use mainnet db with testnet option or vice-versa
if chain.Block_Exists(config.Mainnet.Genesis_Block_Hash) || chain.Block_Exists(config.Testnet.Genesis_Block_Hash) {
if globals.IsMainnet() && !chain.Block_Exists(config.Mainnet.Genesis_Block_Hash) {
logger.Fatalf("Tryng to use a testnet database with mainnet, please add --testnet option")
}
if !globals.IsMainnet() && chain.Block_Exists(config.Testnet.Genesis_Block_Hash) {
logger.Fatalf("Tryng to use a mainnet database with testnet, please remove --testnet option")
}
}
// genesis block not in chain, add it to chain, together with its miner tx // genesis block not in chain, add it to chain, together with its miner tx
// make sure genesis is in the store // make sure genesis is in the store
if !chain.Block_Exists(globals.Config.Genesis_Block_Hash) { if !chain.Block_Exists(globals.Config.Genesis_Block_Hash) {
logger.Debugf("Genesis block not in store, add it now") logger.Debugf("Genesis block not in store, add it now")
var complete_block block.Complete_Block
bl := Generate_Genesis_Block() bl := Generate_Genesis_Block()
chain.Store_BL(&bl)
chain.Store_TOP_ID(globals.Config.Genesis_Block_Hash)
// store height mapping, genesis block is at id
chain.Store_BL_ID_at_Height(0, globals.Config.Genesis_Block_Hash)
complete_block.Bl = &bl
if !chain.Add_Complete_Block(&complete_block) {
logger.Fatalf("Failed to add genesis block, we can no longer continue")
}
} }
// load the chain from the disk // load the chain from the disk
chain.Initialise_Chain_From_DB() chain.Initialise_Chain_From_DB()
// init mempool
chain.Mempool, err = Init_Mempool(params)
if chain.checkpints_disabled {
logger.Infof("Internal Checkpoints are disabled")
} else {
logger.Debugf("Internal Checkpoints are enabled")
}
_ = err _ = err
atomic.AddUint32(&globals.Subsystem_Active, 1) // increment subsystem atomic.AddUint32(&globals.Subsystem_Active, 1) // increment subsystem
//go chain.Handle_Block_Event_Loop()
//go chain.Handle_Transaction_Event_Loop()
/*for i := uint64(0); i < 100;i++{
block_id,_ := chain.Load_BL_ID_at_Height(i)
chain.write_output_index(block_id)
}*/
// chain.Inject_Alt_Chain() // chain.Inject_Alt_Chain()
return &chain, nil return &chain, nil
@ -88,17 +156,22 @@ func (chain *Blockchain) Initialise_Chain_From_DB() {
chain.Top_ID = chain.Load_TOP_ID() chain.Top_ID = chain.Load_TOP_ID()
chain.Height = (chain.Load_Height_for_BL_ID(chain.Top_ID) + 1) chain.Height = (chain.Load_Height_for_BL_ID(chain.Top_ID) + 1)
chain.Difficulty = chain.Get_Difficulty()
chain.Top_Block_Median_Size = chain.Get_Median_BlockSize_At_Block(chain.Top_ID)
chain.Top_Block_Base_Reward = chain.Load_Block_Reward(chain.Top_ID)
logger.Infof("Chain Top Block %x Height %d", chain.Top_ID, chain.Height)
logger.Infof("Chain Top Block %s Height %d", chain.Top_ID, chain.Height)
} }
// before shutdown , make sure p2p is confirmed stopped // before shutdown , make sure p2p is confirmed stopped
func (chain *Blockchain) Shutdown() { func (chain *Blockchain) Shutdown() {
chain.Lock() // take the lock as chain is no longer in unsafe mode
close(chain.Exit_Event) // send signal to everyone we are shutting down
chain.Mempool.Shutdown() // shutdown mempool first chain.Mempool.Shutdown() // shutdown mempool first
chain.Lock() // take the lock as chain is no longer in unsafe mode
logger.Infof("Stopping Blockchain") logger.Infof("Stopping Blockchain")
chain.store.Shutdown() chain.store.Shutdown()
atomic.AddUint32(&globals.Subsystem_Active, ^uint32(0)) // this decrement 1 fom subsystem atomic.AddUint32(&globals.Subsystem_Active, ^uint32(0)) // this decrement 1 fom subsystem
@ -132,115 +205,300 @@ func (chain *Blockchain) Block_Exists(h crypto.Hash) bool {
return false return false
} }
/* this function will extend the chain and increase the height,
this function trigger checks for the block and transactions for validity, recursively
this is the only function which change chain height and top id
*/
// this is the only entrypoint for new txs in the chain
// add a transaction to MEMPOOL,
// verifying everything means everything possible
// TODO: currently we are not verifying fees, its on TODO list
// this only change mempool, no DB changes
func (chain *Blockchain) Add_TX_To_Pool(tx *transaction.Transaction) (result bool) {
// Coin base TX can not come through this path
if tx.IsCoinbase() {
logger.WithFields(log.Fields{"txid": tx.GetHash()}).Warnf("TX rejected coinbase tx cannot appear in mempool")
return false
}
// check whether enough fees is provided in the transaction
// calculate dynamic_fees_per_kb
dynamic_fees_per_kb := uint64(0)
previous_height := chain.Load_Height_for_BL_ID(chain.Get_Top_ID())
if previous_height >= 2 {
dynamic_fees_per_kb = chain.Get_Dynamic_Fee_Rate(previous_height)
}
func (chain *Blockchain) Chain_Add(bl *Block) (result bool) {
// check whether the fee provided is enoough
calculated_fee := chain.Calculate_TX_fee(dynamic_fees_per_kb, uint64(len(tx.Serialize())))
provided_fee := tx.RctSignature.Get_TX_Fee() // get fee from tx
if ((calculated_fee * 98) / 100) > provided_fee { // 2 % margin see blockchain.cpp L 2913
logger.WithFields(log.Fields{"txid": tx.GetHash()}).Warnf("TX rejected due to low fees provided fee %d calculated fee %d", provided_fee, calculated_fee)
return false
}
if chain.Verify_Transaction_NonCoinbase(tx) {
if chain.Mempool.Mempool_Add_TX(tx, 0) {
logger.Debugf("successfully added tx to pool")
return true
} else {
logger.Debugf("TX rejected by pool")
return false
}
}
logger.Warnf("Incoming TX could not be verified")
return false
}
// this is the only entrypoint for new / old blocks even for genesis block
// this will add the entire block atomically to the chain
// this is the only function which can add blocks to the chain
// this is exported, so ii can be fed new blocks by p2p layer
// genesis block is no different
// TODO: we should stop mining while adding the new block
func (chain *Blockchain) Add_Complete_Block(cbl *block.Complete_Block) (result bool) {
var block_hash crypto.Hash
chain.Lock() chain.Lock()
defer chain.Unlock() defer chain.Unlock()
defer func() {
result = false
// safety so if anything wrong happens, verification fails
if r := recover(); r != nil {
logger.Warnf("Recovered while adding new block, Stack trace below block_hash %s", block_hash)
logger.Warnf("Stack trace \n%s", debug.Stack())
result = false
}
block_hash := bl.GetHash()
// make sure that the block refers to some where in the chain
// and also make sure block is not the genesis block
if result == true { // block was successfully added, commit it atomically
chain.store.Commit()
chain.store.Sync() // sync the DB to disk after every execution of this function
} else {
chain.store.Rollback() // if block could not be added, rollback all changes to previous block
}
}()
if block_hash == globals.Config.Genesis_Block_Hash {
logger.Debugf("Genesis block already in chain skipping it")
return
}
bl := cbl.Bl // small pointer to block
// check if block already exist skip it
// first of all lets do some quick checks
// before doing extensive checks
result = false
block_hash = bl.GetHash()
block_logger := logger.WithFields(log.Fields{"blid": block_hash})
// check if block already exist skip it
if chain.Block_Exists(block_hash) { if chain.Block_Exists(block_hash) {
logger.Debugf("block already in chain skipping it %x", block_hash)
block_logger.Debugf("block already in chain skipping it ")
return return
} }
if chain.Height > 16996 {
// os.Exit(0)
// make sure prev_hash refers to some point in our our chain
// there is an edge case, where we know child but still donot know parent
// this might be some some corrupted miner or initial sync
if block_hash != globals.Config.Genesis_Block_Hash && !chain.Block_Exists(bl.Prev_Hash) {
// TODO we must queue this block for say 60 minutes, if parents donot appear it, discard it
block_logger.Warnf("Prev_Hash no where in the chain, skipping it till we get a parent ")
return
} }
if chain.Height > 17000 {
//os.Exit(0)
// make sure time is NOT too much into future
// if clock diff is more than 2 hrs, reject the block
if bl.Timestamp > (uint64(time.Now().Unix()) + config.CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT) {
block_logger.Warnf("Block timestamp is too much into future, make sure that system clock is correct")
return
} }
if chain.Height > 17010 {
// os.Exit(0)
// verify that the clock is not being run in reverse
median_timestamp := chain.Get_Median_Timestamp_At_Block(bl.Prev_Hash)
if bl.Timestamp < median_timestamp {
block_logger.Warnf("Block timestamp %d is less than median timestamp (%d) of %d blocks", bl.Timestamp, median_timestamp, config.BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW)
return
} }
if chain.Height > 16996000 {
os.Exit(0)
// check a small list 100 hashes whether they have been reached
if IsCheckPointKnown_Static(block_hash, chain.Load_Height_for_BL_ID(bl.Prev_Hash)+1) {
rlog.Tracef(1, "Static Checkpoint reached at height %d", chain.Load_Height_for_BL_ID(bl.Prev_Hash)+1)
} }
// make sure prev_hash refers to some point in our our chain
// there is an edge case, where we know child but still donot know parent
// this might be some some corrupted miner or initial sync
if !chain.Block_Exists(bl.Prev_Hash) {
// TODO we must queue this block for say 60 minutes, if parents donot appear it, discard it
logger.Warnf("Prev_Hash no where in the chain, skipping it till we get a parent %x", block_hash)
return
rlog.Tracef(1, "Checking Known checkpoint %s at height %d", block_hash, chain.Load_Height_for_BL_ID(bl.Prev_Hash)+1)
// disable security checks if checkpoint is already known
if chain.checkpints_disabled || !checkpoints.IsCheckPointKnown(block_hash, chain.Load_Height_for_BL_ID(bl.Prev_Hash)+1) {
rlog.Tracef(1, "Unknown checkpoint %s at height %d, verifying throughly", block_hash, chain.Load_Height_for_BL_ID(bl.Prev_Hash)+1)
// Verify Blocks Proof-Of-Work
PoW := bl.GetPoWHash()
current_difficulty := chain.Get_Difficulty_At_Block(bl.Prev_Hash)
}
if block_hash != globals.Config.Genesis_Block_Hash {
logger.Debugf("Difficulty at height %d is %d", chain.Load_Height_for_BL_ID(bl.Prev_Hash), current_difficulty)
}
// check if the PoW is satisfied
if !difficulty.CheckPowHash(PoW, current_difficulty) { // if invalid Pow, reject the bloc
block_logger.Warnf("Block has invalid PoW, rejecting it")
return false
}
// TODO we need to verify block size whether it crosses the limits
// we need to verify each and every tx contained in the block, sanity check everything
// first of all check, whether all the tx contained in the block, match their hashes
{
if len(bl.Tx_hashes) != len(cbl.Txs) {
block_logger.Warnf("Block says it has %d txs , however complete block contained %d txs", len(bl.Tx_hashes), len(cbl.Txs))
return false
}
// first check whether the complete block contains any diplicate hashes
tx_checklist := map[crypto.Hash]bool{}
for i := 0; i < len(bl.Tx_hashes); i++ {
tx_checklist[bl.Tx_hashes[i]] = true
}
if len(tx_checklist) != len(bl.Tx_hashes) { // block has duplicate tx, reject
block_logger.Warnf("Block has %d duplicate txs, reject it", len(bl.Tx_hashes)-len(tx_checklist))
}
// now lets loop through complete block, matching each tx
// detecting any duplicates using txid hash
for i := 0; i < len(cbl.Txs); i++ {
tx_hash := cbl.Txs[i].GetHash()
if _, ok := tx_checklist[tx_hash]; !ok {
// tx is NOT found in map, RED alert reject the block
block_logger.Warnf("Block says it has tx %s, but complete block does not have it", tx_hash)
return false
}
}
}
PoW := bl.GetPoWHash()
// another check, whether the tx contains any duplicate key images within the block
// block wide duplicate input detector
{
block_pool, _ := mempool.Init_Block_Mempool(nil)
for i := 0; i < len(cbl.Txs); i++ {
if !block_pool.Mempool_Add_TX(cbl.Txs[i], 0) { // block pool will reject any tx which are duplicates or double spend attacks
block_logger.Warnf("Double spend attack %s, rejecting ", cbl.Txs[i].GetHash())
return false
}
}
}
current_difficulty := chain.Get_Difficulty_At_Block(bl.Prev_Hash)
logger.Debugf("Difficulty at height %d is %d", chain.Load_Height_for_BL_ID(bl.Prev_Hash), current_difficulty)
// check if the PoW is satisfied
if !difficulty.CheckPowHash(PoW, current_difficulty) { // if invalid Pow, reject the bloc
logger.Warnf("Block %x has invalid PoW, ignoring it", block_hash)
return false
// now we need to verify each and every tx in detail
// verify coinbase tx
if chain.Get_Height() > 5 { // skip checks for first 5 blocks
if !chain.Verify_Transaction_Coinbase(cbl, &bl.Miner_tx) {
block_logger.Warnf("Miner tx failed verification rejecting ")
return false
}
}
/*
// verify all non coinbase tx, single threaded, we have a multithreaded version below
for i := 0 ; i < len(cbl.Txs); i++ {
if !chain.Verify_Transaction_NonCoinbase(cbl.Txs[i]){
logger.Warnf("Non Coinbase tx failed verification rejecting " )
return false
}
}
*/
fail_count := uint64(0)
wg := sync.WaitGroup{}
wg.Add(len(cbl.Txs)) // add total number of tx as work
for i := 0; i < len(cbl.Txs); i++ {
go func(j int) {
if !chain.Verify_Transaction_NonCoinbase(cbl.Txs[j]) { // transaction verification failed
atomic.AddUint64(&fail_count, 1) // increase fail count by 1
}
wg.Done()
}(i)
}
wg.Wait() // wait for verifications to finish
if fail_count > 0 { // check the result
block_logger.Warnf("Block verification failed rejecting ")
return false
}
} // checkpoint based validation completed here
// if checkpoint is found, we land here
// we are here means everything looks good, proceed and save to chain
// discard the transactions from mempool if they are present there
chain.Mempool.Monitor()
for i := 0; i < len(cbl.Txs); i++ {
txid := cbl.Txs[i].GetHash()
if chain.Mempool.Mempool_TX_Exist(txid) {
rlog.Tracef(1, "Deleting TX from pool txid=%s", txid)
chain.Mempool.Mempool_Delete_TX(txid)
}
}
// save all the txs
// and then save the block
{ // first lets save all the txs, together with their link to this block as height
height := uint64(0)
if block_hash != globals.Config.Genesis_Block_Hash {
// get height from parent block
height = chain.Load_Height_for_BL_ID(bl.Prev_Hash)
height++
}
for i := 0; i < len(cbl.Txs); i++ {
chain.Store_TX(cbl.Txs[i], height)
}
} }
// check we need to extend the chain or do a soft fork // check we need to extend the chain or do a soft fork
if bl.Prev_Hash == chain.Top_ID {
// this condition is automatically satisfied by the genesis block ( since golang gives everything a zero value)
if bl.Prev_Hash == chain.Top_ID /* lock_hash == globals.Config.Genesis_Block_Hash */ {
// we need to extend the chain // we need to extend the chain
//log.Debugf("Extendin chain using block %x", block_hash ) //log.Debugf("Extendin chain using block %x", block_hash )
chain.Store_BL(bl) chain.Store_BL(bl)
chain.Store_TOP_ID(block_hash) // make new block top block
chain.consume_keyimages(block_hash) // consume all keyimages as spent
chain.write_output_index(block_hash) // extract and store keys
chain.Store_TOP_ID(block_hash) // make new block top block
//chain.Add_Child(bl.Prev_Hash, block_hash) // add the new block as chil //chain.Add_Child(bl.Prev_Hash, block_hash) // add the new block as chil
chain.Store_Block_Child(bl.Prev_Hash, block_hash) chain.Store_Block_Child(bl.Prev_Hash, block_hash)
chain.Store_BL_ID_at_Height(chain.Height, block_hash)
chain.Store_BL_ID_at_Height(chain.Height, block_hash) // store height to block id mapping
// lower the window, where top_id and chain height are different // lower the window, where top_id and chain height are different
chain.Height = chain.Height + 1 // increment height chain.Height = chain.Height + 1 // increment height
chain.Top_ID = block_hash // set new top block id chain.Top_ID = block_hash // set new top block id
logger.Debugf("Chain extended using block %x new height %d", block_hash[:], chain.Height)
block_logger.Debugf("Chain extended new height %d", chain.Height)
// every 10 block print a line
// every 20 block print a line
if chain.Height%20 == 0 { if chain.Height%20 == 0 {
logger.Infof("Chain Height %d using block %x", chain.Height, block_hash[:])
block_logger.Infof("Chain Height %d", chain.Height)
} }
} else { // a soft fork is in progress } else { // a soft fork is in progress
logger.Debugf("Soft Fork is in progress block due to %x", block_hash)
block_logger.Debugf("Soft Fork is in progress")
chain.Chain_Add_And_Reorganise(bl) chain.Chain_Add_And_Reorganise(bl)
} }
// fmt.Printf("We should add the block to DB, reorganise if required\n")
return false
result = true
return // run any handlers necesary to atomically
} }
/* the block we have is NOT at the top, it either belongs to an altchain or is an alternative */ /* the block we have is NOT at the top, it either belongs to an altchain or is an alternative */
func (chain *Blockchain) Chain_Add_And_Reorganise(bl *Block) (result bool) {
func (chain *Blockchain) Chain_Add_And_Reorganise(bl *block.Block) (result bool) {
block_hash := bl.GetHash() block_hash := bl.GetHash()
// check whether the parent already has a child // check whether the parent already has a child
parent_has_child := chain.Does_Block_Have_Child(bl.Prev_Hash) parent_has_child := chain.Does_Block_Have_Child(bl.Prev_Hash)
// first lets add ourselves to the chain // first lets add ourselves to the chain
chain.Store_BL(bl) chain.Store_BL(bl)
chain.consume_keyimages(block_hash)
if !parent_has_child { if !parent_has_child {
chain.Store_Block_Child(bl.Prev_Hash, block_hash) chain.Store_Block_Child(bl.Prev_Hash, block_hash)
logger.Infof("Adding alternative block %x to alt chain top\n", block_hash)
logger.Infof("Adding alternative block %s to alt chain top", block_hash)
} else { } else {
logger.Infof("Adding alternative block %x\n", block_hash)
logger.Infof("Adding alternative block %s", block_hash)
// load existing children, there can be more than 1 in extremely rare case or unknown attacks // load existing children, there can be more than 1 in extremely rare case or unknown attacks
children_list := chain.Load_Block_Children(bl.Prev_Hash) children_list := chain.Load_Block_Children(bl.Prev_Hash)
@ -265,15 +523,15 @@ type chain_data struct {
foundat uint64 // when block was found foundat uint64 // when block was found
} }
// NOTE: below algorithm is the core and and is used to network consensus
// the best chain found using the following algorithm
// NOTE: below algorithm is the core and and is used to achieve network consensus
// the best chain is found using the following algorithm
// cryptonote protocol algo is below // cryptonote protocol algo is below
// compare cdiff, chain with higher diff wins, if diff is same, no reorg, this cause frequent splits // compare cdiff, chain with higher diff wins, if diff is same, no reorg, this cause frequent splits
// new algo is this // new algo is this
// compare cdiff, chain with higher diff wins, if diff is same, go below // compare cdiff, chain with higher diff wins, if diff is same, go below
// compare time stamp, block with lower timestamp wins (since it has probable spread more than other blocks) // compare time stamp, block with lower timestamp wins (since it has probable spread more than other blocks)
// if timestamps are same, block with lower block has (No PoW involved) wins
// if timestamps are same, block with lower block hash (No PoW involved) wins
// block hash cannot be same // block hash cannot be same
type bestChain []chain_data type bestChain []chain_data
@ -314,14 +572,14 @@ func (chain *Blockchain) reorganise(block_hash crypto.Hash) {
// check if the block mentioned has more than 1 child // check if the block mentioned has more than 1 child
block_hash, found := chain.find_parent_with_children(block_hash) block_hash, found := chain.find_parent_with_children(block_hash)
logger.Debugf("block with children (in reverse) %s found %d", block_hash, found)
if found { if found {
// reorganise chain at this block // reorganise chain at this block
children := chain.Load_Block_Children(block_hash) children := chain.Load_Block_Children(block_hash)
if len(children) < 2 { if len(children) < 2 {
panic(fmt.Sprintf("Children disappeared for block %x", block_hash))
panic(fmt.Sprintf("Children disappeared for block %s", block_hash))
} }
main_chain := chain.Load_Block_Child(block_hash) main_chain := chain.Load_Block_Child(block_hash)
_ = main_chain
// choose the best chain and make it parent // choose the best chain and make it parent
for i := range children { for i := range children {
@ -332,9 +590,9 @@ func (chain *Blockchain) reorganise(block_hash crypto.Hash) {
} }
sort.Sort(children_data) sort.Sort(children_data)
logger.Infof("Choosing best chain\n")
logger.Infof("Choosing best chain")
for i := range children { for i := range children {
fmt.Printf("%d %+v\n", i, children_data[i])
logger.Infof("%d %+v\n", i, children_data[i])
} }
best_chain := children_data[0].hash best_chain := children_data[0].hash
@ -350,12 +608,61 @@ func (chain *Blockchain) reorganise(block_hash crypto.Hash) {
// setup new height // setup new height
new_height := chain.Load_Height_for_BL_ID(chain.Get_Top_Block(best_chain)) + 1 new_height := chain.Load_Height_for_BL_ID(chain.Get_Top_Block(best_chain)) + 1
//also walk through all the new main chain till the top, setting output keys, first of all
chain.write_output_index(block_hash) // extract and store keys
loop_block_hash := block_hash
for {
chain.write_output_index(loop_block_hash) // extract and store keys
chain.consume_keyimages(loop_block_hash) // consume all keyimages
// fix up height to block id mapping, which is used to find orphans later on
height := chain.Load_Height_for_BL_ID(loop_block_hash)
chain.Store_BL_ID_at_Height(height, loop_block_hash)
// check if the block has child, if not , we are the top
if !chain.Does_Block_Have_Child(loop_block_hash) {
break
}
loop_block_hash = chain.Load_Block_Child(loop_block_hash) // continue searching the new top
}
// invalidate all transactionw contained within old main chain // invalidate all transactionw contained within old main chain
// validate all transactions in new main chain // validate all transactions in new main chain
logger.Debugf("Invalidating all transactions with old main chain") logger.Debugf("Invalidating all transactions with old main chain")
logger.Debugf("Validating all transactions with old alt chain") logger.Debugf("Validating all transactions with old alt chain")
// pushing alt_chain txs to mempool after verification
loop_block_hash = main_chain // main chain at this point is the old chain
for {
// load the block
bl, err := chain.Load_BL_FROM_ID(loop_block_hash)
if err != nil {
chain.revoke_keyimages(bl.GetHash()) // revoke all keyimages
for i := 0; i < len(bl.Tx_hashes); i++ {
tx, err := chain.Load_TX_FROM_ID(bl.Tx_hashes[i])
if err != nil {
if !chain.Verify_Transaction_NonCoinbase(tx) {
logger.Warnf("Non Coinbase tx failed verification rejecting ")
} else { // tx passed verification add to mempool
// TODO check whether the additiontion was successfull
chain.Mempool.Mempool_Add_TX(tx, 0)
}
}
}
} else {
logger.Debugf("error during chain reorganisation, failed to push alt chain TX to pool")
}
// check if the block has child, if not , we are the top
if !chain.Does_Block_Have_Child(loop_block_hash) {
break
}
loop_block_hash = chain.Load_Block_Child(loop_block_hash) // continue searching the new top
}
logger.Infof("Reorganise old height %d, new height %d", chain.Get_Height(), new_height) logger.Infof("Reorganise old height %d, new height %d", chain.Get_Height(), new_height)
chain.Top_ID = chain.Get_Top_Block(best_chain) chain.Top_ID = chain.Get_Top_Block(best_chain)
@ -399,53 +706,64 @@ func (chain *Blockchain) find_parent_with_children(block_hash crypto.Hash) (hash
} }
} }
// make sure the block is valid before we even attempt to add it
func (chain *Blockchain) Is_Block_Valid(height uint64, bl *Block) bool {
// Finds whether a block is orphan
// since we donot store any fields, we need to calculate/find the block as orphan
// using an algorithm
// find the block height and then relook up block using height
// if both are same, the block is good otherwise we treat it as orphan
func (chain *Blockchain) Is_Block_Orphan(hash crypto.Hash) bool {
height := chain.Load_Height_for_BL_ID(hash)
block_hash_at_height, _ := chain.Load_BL_ID_at_Height(height)
if hash == block_hash_at_height {
return false
}
return true return true
} }
/*
// Parent's list is appended to add child
func (chain *Blockchain) Add_Child( Parent_Hash, Child_Hash crypto.Hash ){
fmt.Printf("caller %s\n", CallerName())
// child list is only appended and never truncated
// fetch old list
children_list := chain.Load_Chain(Parent_Hash)
if len(children_list) % 32 != 0 {
log.Fatalf("Database corruption has occurred at this hash %x", Parent_Hash[:])
}
if len(children_list) == 0 {
chain.Store_Chain(Parent_Hash, Child_Hash[:])
log.Debugf("%x is a child of %x", Child_Hash, Parent_Hash)
}else{ // we need to sort the children based on Pow
panic("Chain need reorganisation, Sorting on PoW NOT implemented")
// this function will mark all the key images present in the block as requested
// this is done so as they cannot be respent
// mark is bool
func (chain *Blockchain) mark_keyimages(block_hash crypto.Hash, mark bool) bool {
bl, err := chain.Load_BL_FROM_ID(block_hash)
if err == nil {
for i := 0; i < len(bl.Tx_hashes); i++ {
tx, err := chain.Load_TX_FROM_ID(bl.Tx_hashes[i])
if err != nil {
logger.Debugf("TX loading error while marking keyimages as spent blid %s txid %s", block_hash, bl.Tx_hashes[i])
return false
} else {
// mark keyimage as spent
for i := 0; i < len(tx.Vin); i++ {
k_image := tx.Vin[i].(transaction.Txin_to_key).K_image
chain.Store_KeyImage(crypto.Hash(k_image), mark)
}
}
}
} else {
logger.Debugf("BL loading error while marking keyimages as spent blid %s err %s", block_hash, err)
return false
} }
return
return true
} }
*/
/* add a transaction to chain,, we are currently not verifying the TX,
its a BUG and disaster, implement it ASAP
*/
func (chain *Blockchain) Add_TX(tx *Transaction) {
chain.Store_TX(tx)
//this will mark all the keyimages present in this block as spent
//this is done so as an input cannot be spent twice
func (chain *Blockchain) consume_keyimages(block_hash crypto.Hash) bool {
return chain.mark_keyimages(block_hash, true)
}
//this will mark all the keyimages present in this block as unspent
//this is required during chain reorganisation
// when altchain becomes mainchain or viceversa,
// one of the chains needs to be markek unconsumed, so they can be consumed again
func (chain *Blockchain) revoke_keyimages(block_hash crypto.Hash) bool {
return chain.mark_keyimages(block_hash, false)
} }
/* this will only give you access to transactions which have been mined /* this will only give you access to transactions which have been mined
*/ */
func (chain *Blockchain) Get_TX(hash crypto.Hash) (*Transaction, error) {
func (chain *Blockchain) Get_TX(hash crypto.Hash) (*transaction.Transaction, error) {
tx, err := chain.Load_TX_FROM_ID(hash) tx, err := chain.Load_TX_FROM_ID(hash)
return tx, err return tx, err
@ -462,7 +780,7 @@ func (chain *Blockchain) Get_Difficulty_At_Height(Height uint64) uint64 {
block_id, err := chain.Load_BL_ID_at_Height(Height) block_id, err := chain.Load_BL_ID_at_Height(Height)
if err != nil { if err != nil {
logger.Warnf("No Block at Height %d , chain height %d\n", Height, chain.Get_Height())
logger.Warnf("No Block at Height %d , chain height %d", Height, chain.Get_Height())
panic("No Block at Height") panic("No Block at Height")
} }
@ -479,10 +797,10 @@ func (chain *Blockchain) Get_Difficulty_At_Block(block_id crypto.Hash) uint64 {
var zero_block crypto.Hash var zero_block crypto.Hash
current_block_id := block_id current_block_id := block_id
// traverse chain from the block referenced, to max 30 blocks ot till genesis block is researched
// traverse chain from the block referenced, to max 30 blocks ot till genesis block is reached
for i := 0; i < config.DIFFICULTY_BLOCKS_COUNT_V2; i++ { for i := 0; i < config.DIFFICULTY_BLOCKS_COUNT_V2; i++ {
if current_block_id == globals.Config.Genesis_Block_Hash || current_block_id == zero_block { if current_block_id == globals.Config.Genesis_Block_Hash || current_block_id == zero_block {
rlog.Tracef(2, "Reached genesis block for difficulty calculation %x", block_id[:])
rlog.Tracef(2, "Reached genesis block for difficulty calculation %s", block_id)
break // break we have reached genesis block break // break we have reached genesis block
} }
// read timestamp of block and cumulative difficulty at that block // read timestamp of block and cumulative difficulty at that block
@ -498,6 +816,52 @@ func (chain *Blockchain) Get_Difficulty_At_Block(block_id crypto.Hash) uint64 {
return difficulty.Next_Difficulty(timestamps, cumulative_difficulties, config.BLOCK_TIME) return difficulty.Next_Difficulty(timestamps, cumulative_difficulties, config.BLOCK_TIME)
} }
// get median time stamp at specific block_id, only condition is block must exist and must be connected
func (chain *Blockchain) Get_Median_Timestamp_At_Block(block_id crypto.Hash) uint64 {
var timestamps []uint64
var zero_block crypto.Hash
current_block_id := block_id
// traverse chain from the block referenced, to max 30 blocks ot till genesis block is researched
for i := 0; i < config.BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW; i++ {
if current_block_id == globals.Config.Genesis_Block_Hash || current_block_id == zero_block {
rlog.Tracef(4, "Reached genesis block for median calculation %s", block_id)
break // break we have reached genesis block
}
// read timestamp of block and cumulative difficulty at that block
timestamp := chain.Load_Block_Timestamp(current_block_id)
timestamps = append(timestamps, timestamp) // append timestamp
current_block_id = chain.Load_Block_Parent_ID(current_block_id)
}
return Median(timestamps)
}
// get median blocksize at specific block_id, only condition is block must exist and must be connected
func (chain *Blockchain) Get_Median_BlockSize_At_Block(block_id crypto.Hash) uint64 {
var block_sizes []uint64
var zero_block crypto.Hash
current_block_id := block_id
// traverse chain from the block referenced, to max 30 blocks ot till genesis block is researched
for i := uint64(0); i < config.CRYPTONOTE_REWARD_BLOCKS_WINDOW; i++ {
if current_block_id == globals.Config.Genesis_Block_Hash || current_block_id == zero_block {
rlog.Tracef(4, "Reached genesis block for median calculation %s", block_id)
break // break we have reached genesis block
}
// read timestamp of block and cumulative difficulty at that block
block_size := chain.Load_Block_Size(current_block_id)
block_sizes = append(block_sizes, block_size) // append size
current_block_id = chain.Load_Block_Parent_ID(current_block_id)
}
return Median(block_sizes)
}
// this function return the current top block, if we start at specific block // this function return the current top block, if we start at specific block
// this works for any blocks which were added // this works for any blocks which were added
func (chain *Blockchain) Get_Top_Block(block_id crypto.Hash) crypto.Hash { func (chain *Blockchain) Get_Top_Block(block_id crypto.Hash) crypto.Hash {
@ -508,86 +872,155 @@ func (chain *Blockchain) Get_Top_Block(block_id crypto.Hash) crypto.Hash {
} }
block_id = chain.Load_Block_Child(block_id) // continue searching the new top block_id = chain.Load_Block_Child(block_id) // continue searching the new top
} }
panic("We can never reach this point")
return block_id // we will never reach here
// panic("We can never reach this point")
// return block_id // we will never reach here
} }
// verifies whether we are lagging // verifies whether we are lagging
// return true if we need resync // return true if we need resync
// returns false if we are good
// returns false if we are good and resync is not required
func (chain *Blockchain) IsLagging(peer_cdifficulty, peer_height uint64, peer_top_id crypto.Hash) bool { func (chain *Blockchain) IsLagging(peer_cdifficulty, peer_height uint64, peer_top_id crypto.Hash) bool {
top_id := chain.Get_Top_ID() top_id := chain.Get_Top_ID()
cdifficulty := chain.Load_Block_Cumulative_Difficulty(top_id) cdifficulty := chain.Load_Block_Cumulative_Difficulty(top_id)
height := chain.Load_Height_for_BL_ID(top_id) + 1 height := chain.Load_Height_for_BL_ID(top_id) + 1
rlog.Tracef(3, "P_cdiff %d cdiff %d , P_BH %d BH %d, p_top %x top %x",
rlog.Tracef(3, "P_cdiff %d cdiff %d , P_BH %d BH %d, p_top %s top %s",
peer_cdifficulty, cdifficulty, peer_cdifficulty, cdifficulty,
peer_height, height, peer_height, height,
peer_top_id, top_id) peer_top_id, top_id)
if peer_cdifficulty > cdifficulty{
if peer_cdifficulty > cdifficulty {
return true // peer's cumulative difficulty is more than ours , active resync return true // peer's cumulative difficulty is more than ours , active resync
} }
if peer_cdifficulty == cdifficulty && peer_top_id != top_id { if peer_cdifficulty == cdifficulty && peer_top_id != top_id {
return true // cumulative difficulty is same but tops are different , active resync return true // cumulative difficulty is same but tops are different , active resync
} }
return false return false
} }
// This function will expand a transaction with all the missing info being reconstitued from the blockchain // This function will expand a transaction with all the missing info being reconstitued from the blockchain
// this also increases security since data is coming from the chain or being calculated // this also increases security since data is coming from the chain or being calculated
// basically this places data for ring signature verification // basically this places data for ring signature verification
// REMEMBER to expand key images from the blockchain // REMEMBER to expand key images from the blockchain
func (chain *Blockchain) Expand_Transaction_v2 (tx *Transaction){
// TODO we must enforce that the keyimages used are valid and specific outputs are unlocked
func (chain *Blockchain) Expand_Transaction_v2(tx *transaction.Transaction) (result bool) {
result = false
if tx.Version != 2 { if tx.Version != 2 {
panic("TX not version 2") panic("TX not version 2")
} }
//if rctsignature is null //if rctsignature is null
// fill up the message first
// fill up the message hash first
tx.RctSignature.Message = ringct.Key(tx.GetPrefixHash()) tx.RctSignature.Message = ringct.Key(tx.GetPrefixHash())
// fill up the key images
for i := 0; i < len(tx.Vin);i++{
tx.RctSignature.MlsagSigs[i].II[0]= ringct.Key(tx.Vin[i].(Txin_to_key).K_image)
// fill up the key images from the blockchain
for i := 0; i < len(tx.Vin); i++ {
tx.RctSignature.MlsagSigs[i].II = tx.RctSignature.MlsagSigs[i].II[:0] // zero it out
tx.RctSignature.MlsagSigs[i].II = make([]ringct.Key, 1, 1)
tx.RctSignature.MlsagSigs[i].II[0] = ringct.Key(tx.Vin[i].(transaction.Txin_to_key).K_image)
} }
// now we need to fill up the mixring ctkey // now we need to fill up the mixring ctkey
// one part is the destination address, second is the commitment mask from the outpk
// mixring is stored in different ways for rctfull and simple
}
switch tx.RctSignature.Get_Sig_Type() {
case ringct.RCTTypeFull:
// TODO, we need to make sure all ring are of same size
if len(tx.Vin) > 1 {
panic("unsipported rcctt full case please investigate")
}
// make a matrix of mixin x 1 elements
mixin := len(tx.Vin[0].(transaction.Txin_to_key).Key_offsets)
tx.RctSignature.MixRing = make([][]ringct.CtKey, mixin, mixin)
for n := 0; n < len(tx.Vin); n++ {
offset := uint64(0)
for m := 0; m < len(tx.Vin[n].(transaction.Txin_to_key).Key_offsets); m++ {
tx.RctSignature.MixRing[m] = make([]ringct.CtKey, len(tx.Vin), len(tx.Vin))
offset += tx.Vin[n].(transaction.Txin_to_key).Key_offsets[m]
// extract the keys from specific offset
offset_data := chain.load_output_index(offset)
// check maturity of inputs
if !inputmaturity.Is_Input_Mature(chain.Get_Height(), offset_data.Height, offset_data.Unlock_Height, 1) {
logger.Warnf("transaction using immature inputs from block %d chain height %d", offset_data.Height, chain.Get_Height())
return false
}
tx.RctSignature.MixRing[m][n].Destination = offset_data.InKey.Destination
tx.RctSignature.MixRing[m][n].Mask = offset_data.InKey.Mask
// fmt.Printf("%d %d dest %s\n",n,m, offset_data.InKey.Destination)
// fmt.Printf("%d %d mask %s\n",n,m, offset_data.InKey.Mask)
}
}
case ringct.RCTTypeSimple:
mixin := len(tx.Vin[0].(transaction.Txin_to_key).Key_offsets)
_ = mixin
tx.RctSignature.MixRing = make([][]ringct.CtKey, len(tx.Vin), len(tx.Vin))
for n := 0; n < len(tx.Vin); n++ {
tx.RctSignature.MixRing[n] = make([]ringct.CtKey, len(tx.Vin[n].(transaction.Txin_to_key).Key_offsets),
len(tx.Vin[n].(transaction.Txin_to_key).Key_offsets))
offset := uint64(0)
for m := 0; m < len(tx.Vin[n].(transaction.Txin_to_key).Key_offsets); m++ {
offset += tx.Vin[n].(transaction.Txin_to_key).Key_offsets[m]
// extract the keys from specific offset
offset_data := chain.load_output_index(offset)
// check maturity of inputs
if !inputmaturity.Is_Input_Mature(chain.Get_Height(), offset_data.Height, offset_data.Unlock_Height, 1) {
logger.Warnf("transaction using immature inputs from block %d chain height %d", offset_data.Height, chain.Get_Height())
return false
}
tx.RctSignature.MixRing[n][m].Destination = offset_data.InKey.Destination
tx.RctSignature.MixRing[n][m].Mask = offset_data.InKey.Mask
// fmt.Printf("%d %d dest %s\n",n,m, offset_data.InKey.Destination)
// fmt.Printf("%d %d mask %s\n",n,m, offset_data.InKey.Mask)
}
}
default:
logger.Warnf("unknown ringct transaction")
return false
}
return true
}
// this function count all the vouts of the block, // this function count all the vouts of the block,
// this function exists here because only the chain knws the tx // this function exists here because only the chain knws the tx
// //
func (chain *Blockchain) Block_Count_Vout(block_hash crypto.Hash) (count uint64){
func (chain *Blockchain) Block_Count_Vout(block_hash crypto.Hash) (count uint64) {
count = 1 // miner tx is always present count = 1 // miner tx is always present
bl, err := chain.Load_BL_FROM_ID(block_hash) bl, err := chain.Load_BL_FROM_ID(block_hash)
if err != nil { if err != nil {
panic(fmt.Errorf("Cannot load block for %x err %s", block_hash, err))
panic(fmt.Errorf("Cannot load block for %s err %s", block_hash, err))
} }
for i := 0 ; i < len(bl.Tx_hashes);i++{ // load all tx one by one
for i := 0; i < len(bl.Tx_hashes); i++ { // load all tx one by one
tx, err := chain.Load_TX_FROM_ID(bl.Tx_hashes[i]) tx, err := chain.Load_TX_FROM_ID(bl.Tx_hashes[i])
if err != nil{
panic(fmt.Errorf("Cannot load tx for %x err %s", bl.Tx_hashes[i], err))
if err != nil {
panic(fmt.Errorf("Cannot load tx for %s err %s", bl.Tx_hashes[i], err))
} }
// tx has been loaded, now lets get the vout // tx has been loaded, now lets get the vout
vout_count := uint64(len(tx.Vout))
count += vout_count
vout_count := uint64(len(tx.Vout))
count += vout_count
} }
return count return count
}
}

+ 60
- 0
blockchain/blockheader.go

@ -0,0 +1,60 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain
//import "fmt"
import "github.com/deroproject/derosuite/crypto"
// this is used to print blockheader for the rpc and the daemon
type BlockHeader_Print struct {
Depth uint64 `json:"depth"`
Difficulty uint64 `json:"difficulty"`
Hash string `json:"hash"`
Height uint64 `json:"height"`
Major_Version uint64 `json:"major_version"`
Minor_Version uint64 `json:"minor_version"`
Nonce uint64 `json:"nonce"`
Orphan_Status bool `json:"orphan_status"`
Reward uint64 `json:"reward"`
Prev_Hash string `json:"prev_hash"`
Timestamp uint64 `json:"timestamp"`
}
/* fill up the above structure from the blockchain */
func (chain *Blockchain) GetBlockHeader(hash crypto.Hash) (result BlockHeader_Print, err error) {
bl, err := chain.Load_BL_FROM_ID(hash)
if err != nil {
return
}
result.Height = chain.Load_Height_for_BL_ID(hash)
result.Depth = chain.Get_Height() - result.Height - 1
result.Difficulty = chain.Get_Difficulty_At_Block(hash)
result.Hash = hash.String()
result.Height = chain.Load_Height_for_BL_ID(hash)
result.Major_Version = uint64(bl.Major_Version)
result.Minor_Version = uint64(bl.Minor_Version)
result.Nonce = uint64(bl.Nonce)
result.Orphan_Status = chain.Is_Block_Orphan(hash)
result.Reward = chain.Load_Block_Reward(hash)
result.Prev_Hash = bl.Prev_Hash.String()
result.Timestamp = bl.Timestamp
return
}

+ 16
- 0
blockchain/caller.go

@ -1,3 +1,19 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain package blockchain
// this package identifies the 2nd level caller of this function // this package identifies the 2nd level caller of this function

+ 52
- 10
blockchain/checkpoints_static.go

@ -1,19 +1,35 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain package blockchain
import "fmt" import "fmt"
import "encoding/hex" import "encoding/hex"
import log "github.com/sirupsen/logrus"
//import log "github.com/sirupsen/logrus"
import "github.com/deroproject/derosuite/crypto" import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/globals" import "github.com/deroproject/derosuite/globals"
var mainnet_static_checkpoints = map[uint64]crypto.Hash{}
var testnet_static_checkpoints = map[uint64]crypto.Hash{}
var mainnet_static_checkpoints = map[crypto.Hash]uint64{}
var testnet_static_checkpoints = map[crypto.Hash]uint64{}
// initialize the checkpoints
func init_checkpoints() {
// initialize the checkpoints only few manually
// just in case we decide to skip adding blocklist in the future
func init_static_checkpoints() {
switch globals.Config.Name { switch globals.Config.Name {
case "mainnet": case "mainnet":
@ -21,9 +37,9 @@ func init_checkpoints() {
ADD_CHECKPOINT(mainnet_static_checkpoints, 10, "a8feb533ad2ad021f356b964957f4880445f89d6c6658a9407d63ce5144fe8ea") ADD_CHECKPOINT(mainnet_static_checkpoints, 10, "a8feb533ad2ad021f356b964957f4880445f89d6c6658a9407d63ce5144fe8ea")
ADD_CHECKPOINT(mainnet_static_checkpoints, 100, "462ef1347bd00511ad6e7be463cba4d44a69dbf8b7d1d478ff1fd68507dfc9e2") ADD_CHECKPOINT(mainnet_static_checkpoints, 100, "462ef1347bd00511ad6e7be463cba4d44a69dbf8b7d1d478ff1fd68507dfc9e2")
log.Debugf("Added %d static checkpoints to mainnnet\n", len(mainnet_static_checkpoints))
logger.Debugf("Added %d static checkpoints to mainnet", len(mainnet_static_checkpoints))
case "testnet": case "testnet":
logger.Debugf("Added %d static checkpoints to testnet", len(testnet_static_checkpoints))
default: default:
panic(fmt.Sprintf("Unknown Network \"%s\"", globals.Config.Name)) panic(fmt.Sprintf("Unknown Network \"%s\"", globals.Config.Name))
} }
@ -31,7 +47,7 @@ func init_checkpoints() {
} }
// add a checkpoint to specific network // add a checkpoint to specific network
func ADD_CHECKPOINT(x map[crypto.Hash]uint64, Height uint64, hash_hex string) {
func ADD_CHECKPOINT(x map[uint64]crypto.Hash, Height uint64, hash_hex string) {
var hash crypto.Hash var hash crypto.Hash
hash_raw, err := hex.DecodeString(hash_hex) hash_raw, err := hex.DecodeString(hash_hex)
@ -45,5 +61,31 @@ func ADD_CHECKPOINT(x map[crypto.Hash]uint64, Height uint64, hash_hex string) {
} }
copy(hash[:], hash_raw) copy(hash[:], hash_raw)
x[hash] = Height
x[Height] = hash
}
// verify whether the hash at the specific height matches
func IsCheckPointKnown_Static(actual_hash crypto.Hash, height uint64) (result bool) {
switch globals.Config.Name {
case "mainnet":
if expected_hash, ok := mainnet_static_checkpoints[height]; ok {
if actual_hash == expected_hash {
result = true
return
}
}
case "testnet":
if expected_hash, ok := testnet_static_checkpoints[height]; ok {
if actual_hash == expected_hash {
result = true
return
}
}
default:
panic(fmt.Sprintf("Unknown Network \"%s\"", globals.Config.Name))
}
return
} }

+ 23
- 0
blockchain/const.go

@ -0,0 +1,23 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain
import "github.com/deroproject/derosuite/crypto"
// this file contains all the constant
var ZERO_HASH crypto.Hash

+ 76
- 0
blockchain/create_miner_tx.go

@ -0,0 +1,76 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain
import "fmt"
import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/address"
import "github.com/deroproject/derosuite/crypto/ringct"
import "github.com/deroproject/derosuite/transaction"
// this function creates a miner tx, with specific blockreward
// TODO we should consider hardfork version while creating a miner tx
func Create_Miner_TX(hf_version, height, reward uint64, miner_address address.Address, reserve_size int) (tx transaction.Transaction, err error) {
// initialize extra map in empty tx
tx.Extra_map = map[transaction.EXTRA_TAG]interface{}{}
//TODO need to fix hard fork version checks
switch {
case hf_version <= 6:
tx.Version = 2
default:
err = fmt.Errorf("NO such hardfork version")
}
tx.Vin = append(tx.Vin, transaction.Txin_gen{Height: height}) // add input height
// now lets create encrypted keys, so as the miner_address can spend them
tx_secret_key, tx_public_key := crypto.NewKeyPair() // create new tx key pair
//tx_public_key is added to extra and serialized
tx.Extra_map[transaction.TX_PUBLIC_KEY] = *tx_public_key
derivation := crypto.KeyDerivation(&miner_address.ViewKey, tx_secret_key) // keyderivation using miner address view key
index_within_tx := uint64(0)
// this becomes the key within Vout
ehphermal_public_key := derivation.KeyDerivation_To_PublicKey(index_within_tx, miner_address.SpendKey)
// added the amount and key in vout
tx.Vout = append(tx.Vout, transaction.Tx_out{Amount: reward, Target: transaction.Txout_to_key{Key: ehphermal_public_key}})
// add reserve size if requested
if reserve_size != 0 {
if reserve_size <= 255 {
tx.Extra_map[transaction.TX_EXTRA_NONCE] = make([]byte, reserve_size, reserve_size)
} else {
// give a warning that nonce was requested but could not be created
}
}
tx.Extra = tx.Serialize_Extra() // serialize the extra
// add 0 byte ringct signature
var sig ringct.RctSig
tx.RctSignature = &sig
return
}

+ 135
- 0
blockchain/create_miner_tx_test.go

@ -0,0 +1,135 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain
//import "fmt"
import "testing"
import "github.com/deroproject/derosuite/walletapi"
import "github.com/deroproject/derosuite/crypto"
//import "github.com/deroproject/derosuite/address"
import "github.com/deroproject/derosuite/transaction"
// file to test whether the miner tx is created successfully and can be serialized/decoded successfully by the block miner
func Test_Create_Miner_TX(t *testing.T) {
for i := 0; i < 1; i++ {
hf_version := uint64(0)
height := uint64(i)
reward := uint64(i + 1)
account, _ := walletapi.Generate_Keys_From_Random()
miner_address := account.GetAddress()
miner_tx_original, err := Create_Miner_TX(hf_version, height, reward, miner_address, 0)
if err != nil {
t.Fatalf("error creating miner tx, err :%s", err)
}
miner_tx_original_serialized := miner_tx_original.Serialize()
var miner_tx_parsed transaction.Transaction
err = miner_tx_parsed.DeserializeHeader(miner_tx_original_serialized)
if err != nil {
t.Fatalf("error parsing created miner tx, err :%s", err)
}
miner_tx_parsed.Parse_Extra() // parse the extra
if miner_tx_parsed.Vin[0].(transaction.Txin_gen).Height != height {
t.Fatalf("miner tx height mismatch")
}
if miner_tx_parsed.Vout[0].Amount != reward {
t.Fatalf("miner tx reward mismatch")
}
// check whether we can decode it output
public_key := miner_tx_parsed.Extra_map[transaction.TX_PUBLIC_KEY].(crypto.Key)
vout_key := miner_tx_parsed.Vout[0].Target.(transaction.Txout_to_key).Key
index_within_tx := uint64(0)
if !account.Is_Output_Ours(public_key, index_within_tx, vout_key) {
t.Fatalf("miner tx cannot be decrypted by the wallet")
}
}
}
func Test_Create_Miner_TX_with_extra(t *testing.T) {
for i := 0; i < 1; i++ {
hf_version := uint64(0)
height := uint64(i)
reward := uint64(i + 1)
account, _ := walletapi.Generate_Keys_From_Random()
miner_address := account.GetAddress()
miner_tx_original, err := Create_Miner_TX(hf_version, height, reward, miner_address, 60)
if err != nil {
t.Fatalf("error creating miner tx, err :%s", err)
}
miner_tx_original_serialized := miner_tx_original.Serialize()
var miner_tx_parsed transaction.Transaction
err = miner_tx_parsed.DeserializeHeader(miner_tx_original_serialized)
if err != nil {
t.Fatalf("error parsing created miner tx, err :%s", err)
}
miner_tx_parsed.Parse_Extra() // parse the extra
if miner_tx_parsed.Vin[0].(transaction.Txin_gen).Height != height {
t.Fatalf("miner tx height mismatch")
}
if miner_tx_parsed.Vout[0].Amount != reward {
t.Fatalf("miner tx reward mismatch")
}
// check whether we can decode it output
public_key := miner_tx_parsed.Extra_map[transaction.TX_PUBLIC_KEY].(crypto.Key)
vout_key := miner_tx_parsed.Vout[0].Target.(transaction.Txout_to_key).Key
index_within_tx := uint64(0)
if !account.Is_Output_Ours(public_key, index_within_tx, vout_key) {
t.Fatalf("miner tx cannot be decrypted by the wallet")
}
extra_data := miner_tx_parsed.Extra_map[transaction.TX_EXTRA_NONCE].([]byte)
if len(extra_data) != 60 {
t.Fatalf("miner tx extra data mismatch")
}
}
}

+ 22
- 6
blockchain/genesis.go

@ -1,26 +1,42 @@
package blockchain
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain
import "encoding/hex" import "encoding/hex"
import "github.com/romana/rlog" import "github.com/romana/rlog"
import "github.com/deroproject/derosuite/address"
//import "github.com/deroproject/derosuite/address"
import "github.com/deroproject/derosuite/block"
import "github.com/deroproject/derosuite/globals" import "github.com/deroproject/derosuite/globals"
/*
func Create_Miner_Transaction(height uint64, median_size uint64, already_generated_coins uint64, func Create_Miner_Transaction(height uint64, median_size uint64, already_generated_coins uint64,
current_block_size uint64, fee uint64, current_block_size uint64, fee uint64,
miner_address address.Address, nonce []byte, miner_address address.Address, nonce []byte,
max_outs uint64, hard_fork uint64) (tx *Transaction, err error) {
max_outs uint64, hard_fork uint64) (tx *transaction.Transaction, err error) {
return nil, nil return nil, nil
} }
*/
// genesis transaction hash 5a18d9489bcd353aeaf4a19323d04e90353f98f0d7cc2a030cfd76e19495547d // genesis transaction hash 5a18d9489bcd353aeaf4a19323d04e90353f98f0d7cc2a030cfd76e19495547d
// genesis amount 35184372088831 // genesis amount 35184372088831
func Generate_Genesis_Block() (bl Block) {
func Generate_Genesis_Block() (bl block.Block) {
genesis_tx_blob, err := hex.DecodeString(globals.Config.Genesis_Tx) genesis_tx_blob, err := hex.DecodeString(globals.Config.Genesis_Tx)
if err != nil { if err != nil {

+ 16
- 0
blockchain/genesis_test.go

@ -1,3 +1,19 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain package blockchain
import "testing" import "testing"

+ 90
- 0
blockchain/inputmaturity/LICENSE

@ -0,0 +1,90 @@
RESEARCH LICENSE
Version 1.1.2
I. DEFINITIONS.
"Licensee " means You and any other party that has entered into and has in effect a version of this License.
“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees.
"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology.
"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage.
"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License.
"Technology Site" means the website designated by Licensor for accessing the Technology.
"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License.
II. PURPOSE.
Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology.
COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT <url>.
III. RESEARCH USE RIGHTS.
A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only:
1. reproduce, create Modifications of, and use the Technology alone, or with Modifications;
2. share source code of the Technology alone, or with Modifications, with other Licensees;
3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and
4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology.
B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights.
C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License.
D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution.
IV. INTELLECTUAL PROPERTY REQUIREMENTS
As a condition to Your License, You agree to comply with the following restrictions and responsibilities:
A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology.
B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License.
V. GENERAL TERMS.
A. Disclaimer Of Warranties.
TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE.
B. Infringement; Limitation Of Liability.
1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site.
2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY.
C. Termination.
1. You may terminate this License at any time by notifying Licensor in writing.
2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance.
3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination.
D. Miscellaneous.
1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor.
2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof.
3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate.
4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter.
5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications.
READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING.
BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS.
IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM.

+ 66
- 0
blockchain/inputmaturity/inputmaturity.go

@ -0,0 +1,66 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package inputmaturity
import "time"
import "github.com/deroproject/derosuite/config"
//this file implements the logic to detect whether an input is mature or still locked
//This function is crucial as any bugs can have catastrophic effects
//this function is used both by the core blockchain and wallet
//TODO we need to check the edge cases
func Is_Input_Mature(current_chain_height uint64, input_block_height uint64, locked_to_height uint64, sigtype uint64) bool {
// current_chain_height must be greater or equal to input height
if current_chain_height < input_block_height { // wrong cases reject
return false
}
// all miner txs end up here
if sigtype == 0 { // miner tx will also always unlock 60 blocks in future
if current_chain_height >= (input_block_height + config.MINER_TX_AMOUNT_UNLOCK) {
return true
}
return false
}
// 99.99 % normal tx cases come here
if locked_to_height == 0 { // input is not locked, so it must be unlocked in 10 blocks
if current_chain_height >= (input_block_height + config.NORMAL_TX_AMOUNT_UNLOCK) {
return true
}
return false
}
// input_block_height is no longer useful
// if we are here input was locked to specific height or time
if locked_to_height < config.CRYPTONOTE_MAX_BLOCK_NUMBER { // input was locked to specific block height
if current_chain_height >= locked_to_height {
return true
}
return false
}
// anything above LIMIT is time based lock
// input was locked to specific time in epoch
if locked_to_height < (uint64(time.Now().UTC().Unix())) {
return true
}
return false // reject time based locks if not mature
}

+ 144
- 0
blockchain/inputmaturity/inputmaturity_test.go

@ -0,0 +1,144 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package inputmaturity
import "testing"
import "github.com/deroproject/derosuite/config"
//this file implements the logic to detect whether an input is mature or still locked
//This function is crucial as any bugs can have catastrophic effects
//this function is used both by the core blockchain and wallet
//TODO we need to check the edge cases
func Test_Input_Maturity(t *testing.T) {
tests := []struct {
name string
current_chain_height uint64
input_block_height uint64
locked_to_height uint64
sigtype uint64
expected bool
}{
{
name: "simple test",
current_chain_height: 0,
input_block_height: 1,
locked_to_height: 0,
sigtype: 0,
expected: false,
},
// miner tx blocks mature in 60 blocks
{
name: "miner test 59",
current_chain_height: 59,
input_block_height: 0,
locked_to_height: 0,
sigtype: 0,
expected: false,
},
{
name: "miner test 60",
current_chain_height: 60,
input_block_height: 0,
locked_to_height: 0,
sigtype: 0,
expected: true,
},
{
name: "miner test 60", // genesis block reward should mature at block 61
current_chain_height: 61,
input_block_height: 0,
locked_to_height: 0,
sigtype: 0,
expected: true,
},
// normal tx output matures in 10 blocks
{
name: "normal test 9", // reward should mature at block 11
current_chain_height: 9,
input_block_height: 0,
locked_to_height: 0,
sigtype: 1,
expected: false,
},
{
name: "normal test 10", //reward should mature at block 10
current_chain_height: 10,
input_block_height: 0,
locked_to_height: 0,
sigtype: 1,
expected: true,
},
{
name: "normal test 11", // reward should mature at block 11
current_chain_height: 11,
input_block_height: 0,
locked_to_height: 0,
sigtype: 1,
expected: true,
},
// height based lock
{
name: "locked_to_height ", // reward should mature at specific block
current_chain_height: config.CRYPTONOTE_MAX_BLOCK_NUMBER - 1,
input_block_height: 0,
locked_to_height: config.CRYPTONOTE_MAX_BLOCK_NUMBER - 1,
sigtype: 1,
expected: true,
},
{
name: "locked_to_height false", // reward should mature at block 11
current_chain_height: config.CRYPTONOTE_MAX_BLOCK_NUMBER - 2,
input_block_height: 0,
locked_to_height: config.CRYPTONOTE_MAX_BLOCK_NUMBER - 1,
sigtype: 1,
expected: false,
},
// time based locked
{
name: "locked_to_time false",
current_chain_height: config.CRYPTONOTE_MAX_BLOCK_NUMBER,
input_block_height: 0,
locked_to_height: 15174219710,
sigtype: 1,
expected: false,
},
{
name: "locked_to_time true",
current_chain_height: config.CRYPTONOTE_MAX_BLOCK_NUMBER,
input_block_height: 0,
locked_to_height: 1517421971,
sigtype: 1,
expected: true,
},
}
for _, test := range tests {
actual := Is_Input_Mature(test.current_chain_height, test.input_block_height, test.locked_to_height, test.sigtype)
if actual != test.expected {
t.Fatalf("Input Maturity testing failed name %s actual %v expected %v", test.name, actual, test.expected)
}
}
}

+ 50
- 0
blockchain/median.go

@ -0,0 +1,50 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain
import "sort"
type uint64arr []uint64
func (a uint64arr) Len() int { return len(a) }
func (a uint64arr) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a uint64arr) Less(i, j int) bool { return a[i] < a[j] }
// Median gets the median number in a slice of uint64 numbers
// this function is used in so many checks that it should have unit tests for sure
// NOTE: it will the input array
func Median(inputs []uint64) (median uint64) {
// Start by sorting
sort.Sort(uint64arr(inputs))
// No math is needed if there are no numbers
// For even numbers we add the two middle numbers
// and divide by two using the mean function above
// For odd numbers we just use the middle number
l := len(inputs)
if l == 0 {
return 0
} else if l%2 == 0 {
median = (inputs[(l/2)-1] + inputs[(l/2)]) / 2
} else {
median = inputs[l/2]
}
return median
}

+ 66
- 0
blockchain/median_test.go

@ -0,0 +1,66 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain
import "testing"
// these tests have been taken from the test_math.h from epee tests
func Test_Median(t *testing.T) {
{ // test with 0 elements
var array []uint64
if Median(array) != 0 {
t.Errorf("Testing failed\n")
}
}
{ // test with 1 element
array := []uint64{1}
if Median(array) != 1 {
t.Errorf("Testing failed\n")
}
}
{ // test with 2 element
array := []uint64{1, 10}
if Median(array) != 5 {
t.Errorf("Testing failed\n")
}
}
{ // test with 3 element
array := []uint64{0, 9, 3}
if Median(array) != 3 {
t.Errorf("Testing failed\n")
}
}
{ // test with 4 element
array := []uint64{77, 9, 22, 60}
if Median(array) != 41 {
t.Errorf("Testing failed\n")
}
}
{ // test with 5 element
array := []uint64{77, 9, 22, 60, 11}
if Median(array) != 22 {
t.Errorf("Testing failed\n")
}
}
}

+ 0
- 97
blockchain/mempool.go

@ -1,97 +0,0 @@
package blockchain
import "sync"
import "time"
import "sync/atomic"
import log "github.com/sirupsen/logrus"
import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/crypto"
// at this point in time, this is an ultrafast written mempool,
// it will not scale for more than 10000 transactions but is good enough for now
// we can always come back and rewrite it
type Mempool struct {
txs map[crypto.Hash]mempool_object
// global variable , but don't see it utilisation here except fot tx verification
chain *Blockchain
sync.Mutex
}
type mempool_object struct {
Tx *Transaction
Added uint64
Reason int // why is the tx in the mempool
}
var loggerpool *log.Entry
func Init_Mempool(params map[string]interface{}) (*Mempool, error) {
var mempool Mempool
//mempool.chain = params["chain"].(*Blockchain)
loggerpool = globals.Logger.WithFields(log.Fields{"com": "POOL"}) // all components must use this logger
loggerpool.Infof("Mempool started")
atomic.AddUint32(&globals.Subsystem_Active, 1) // increment subsystem
//TODO load any trasactions saved at previous exit
return &mempool, nil
}
func (pool *Mempool) Shutdown() {
//TODO save mempool tx somewhere
loggerpool.Infof("Mempool stopped")
atomic.AddUint32(&globals.Subsystem_Active, ^uint32(0)) // this decrement 1 fom subsystem
}
func (pool *Mempool) Mempool_Add_TX(tx *Transaction, Reason int) {
pool.Lock()
defer pool.Unlock()
var object mempool_object
hash := crypto.Hash(tx.GetHash())
// check if tx already exists, skip it
if _, ok := pool.txs[hash]; ok {
loggerpool.Infof("Pool already contains %x, skipping \n", hash)
return
}
object.Tx = tx
object.Reason = Reason
object.Added = uint64(time.Now().Unix())
pool.txs[hash] = object
}
// delete specific tx from pool
func (pool *Mempool) Mempool_Delete_TX(crypto.Hash) {
}
// get specific tx from mem pool
func (pool *Mempool) Mempool_Get_TX(txid crypto.Hash) ([]byte, error) {
return nil, nil
}
// return list of all txs in pool
func (pool *Mempool) Mempool_List_TX() []crypto.Hash {
pool.Lock()
defer pool.Unlock()
var list []crypto.Hash
for k, _ := range pool.txs {
list = append(list, k)
}
return list
}

+ 90
- 0
blockchain/mempool/LICENSE

@ -0,0 +1,90 @@
RESEARCH LICENSE
Version 1.1.2
I. DEFINITIONS.
"Licensee " means You and any other party that has entered into and has in effect a version of this License.
“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees.
"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology.
"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage.
"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License.
"Technology Site" means the website designated by Licensor for accessing the Technology.
"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License.
II. PURPOSE.
Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology.
COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT <url>.
III. RESEARCH USE RIGHTS.
A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only:
1. reproduce, create Modifications of, and use the Technology alone, or with Modifications;
2. share source code of the Technology alone, or with Modifications, with other Licensees;
3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and
4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology.
B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights.
C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License.
D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution.
IV. INTELLECTUAL PROPERTY REQUIREMENTS
As a condition to Your License, You agree to comply with the following restrictions and responsibilities:
A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology.
B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License.
V. GENERAL TERMS.
A. Disclaimer Of Warranties.
TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE.
B. Infringement; Limitation Of Liability.
1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site.
2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY.
C. Termination.
1. You may terminate this License at any time by notifying Licensor in writing.
2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance.
3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination.
D. Miscellaneous.
1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor.
2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof.
3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate.
4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter.
5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications.
READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING.
BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS.
IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM.

+ 216
- 0
blockchain/mempool/mempool.go

@ -0,0 +1,216 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package mempool
import "sync"
import "time"
import "sync/atomic"
import log "github.com/sirupsen/logrus"
import "github.com/deroproject/derosuite/transaction"
import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/crypto"
// NOTE: do NOT consider this code as useless, as it is used to avooid double spending attacks within the block
// let me explain, since we are a state machine, we add block to our blockchain
// so, if a double spending attack comes, 2 transactions with same inputs, we reject one of them
// the algo is documented somewhere else which explains the entire process
// at this point in time, this is an ultrafast written mempool,
// it will not scale for more than 10000 transactions but is good enough for now
// we can always come back and rewrite it
// NOTE: the pool is not persistant , means closing the daemon will make the mempool empty next restart
// TODO: make the pool persistant
type Mempool struct {
txs map[crypto.Hash]mempool_object
key_images map[crypto.Hash]bool // contains key images of all txs
modified bool // used to monitor whethel mem pool contents have changed,
// global variable , but don't see it utilisation here except fot tx verification
//chain *Blockchain
sync.Mutex
}
type mempool_object struct {
Tx *transaction.Transaction
Added uint64 // time in epoch format
Reason int // why is the tx in the mempool
}
var loggerpool *log.Entry
func Init_Mempool(params map[string]interface{}) (*Mempool, error) {
var mempool Mempool
//mempool.chain = params["chain"].(*Blockchain)
loggerpool = globals.Logger.WithFields(log.Fields{"com": "POOL"}) // all components must use this logger
loggerpool.Infof("Mempool started")
atomic.AddUint32(&globals.Subsystem_Active, 1) // increment subsystem
// initialize maps
mempool.txs = map[crypto.Hash]mempool_object{}
mempool.key_images = map[crypto.Hash]bool{}
//TODO load any trasactions saved at previous exit
return &mempool, nil
}
// this is created per incoming block and then discarded
// This does not require shutting down and will be garbage collected automatically
func Init_Block_Mempool(params map[string]interface{}) (*Mempool, error) {
var mempool Mempool
// initialize maps
mempool.txs = map[crypto.Hash]mempool_object{}
mempool.key_images = map[crypto.Hash]bool{}
//TODO load any trasactions saved at previous exit
return &mempool, nil
}
func (pool *Mempool) Shutdown() {
//TODO save mempool tx somewhere
loggerpool.Infof("Mempool stopped")
atomic.AddUint32(&globals.Subsystem_Active, ^uint32(0)) // this decrement 1 fom subsystem
}
// start pool monitoring for changes for some specific time
// this is required so as we can add or discard transactions while selecting work for mining
func (pool *Mempool) Monitor() {
pool.Lock()
pool.modified = false
pool.Unlock()
}
// return whether pool contents have changed
func (pool *Mempool) HasChanged() (result bool) {
pool.Lock()
result = pool.modified
pool.Unlock()
return
}
// a tx should only be added to pool after verification is complete
func (pool *Mempool) Mempool_Add_TX(tx *transaction.Transaction, Reason int) (result bool) {
result = false
pool.Lock()
defer pool.Unlock()
var object mempool_object
tx_hash := crypto.Hash(tx.GetHash())
// check if tx already exists, skip it
if _, ok := pool.txs[tx_hash]; ok {
loggerpool.Infof("Pool already contains %s, skipping \n", tx_hash)
return false
}
// we should also extract all key images and add them to have multiple pending
for i := 0; i < len(tx.Vin); i++ {
if _, ok := pool.key_images[tx.Vin[i].(transaction.Txin_to_key).K_image]; ok {
loggerpool.WithFields(log.Fields{
"txid": tx_hash,
"kimage": tx.Vin[i].(transaction.Txin_to_key).K_image,
}).Warnf("TX using inputs which have already been used, Possible Double spend attack rejected")
return false
}
}
// add all the key images to check double spend attack within the pool
for i := 0; i < len(tx.Vin); i++ {
pool.key_images[tx.Vin[i].(transaction.Txin_to_key).K_image] = true // add element to map for next check
}
// we are here means we can add it to pool
object.Tx = tx
object.Reason = Reason
object.Added = uint64(time.Now().Unix())
pool.txs[tx_hash] = object
pool.modified = true // pool has been modified
return true
}
// check whether a tx exists in the pool
func (pool *Mempool) Mempool_TX_Exist(txid crypto.Hash) (result bool) {
pool.Lock()
defer pool.Unlock()
if _, ok := pool.txs[txid]; ok {
return true
}
return false
}
// delete specific tx from pool and return it
// if nil is returned Tx was not found in pool
func (pool *Mempool) Mempool_Delete_TX(txid crypto.Hash) (tx *transaction.Transaction) {
pool.Lock()
defer pool.Unlock()
// check if tx already exists, skip it
if _, ok := pool.txs[txid]; !ok {
loggerpool.Warnf("Pool does NOT contain %s, returning nil \n", txid)
return nil
}
// we reached here means, we have the tx remove it from our list, do maintainance cleapup and discard it
object := pool.txs[txid]
delete(pool.txs, txid)
// remove all the key images
for i := 0; i < len(object.Tx.Vin); i++ {
delete(pool.key_images, object.Tx.Vin[i].(transaction.Txin_to_key).K_image)
}
pool.modified = true // pool has been modified
return object.Tx // return the tx
}
// get specific tx from mem pool without removing it
func (pool *Mempool) Mempool_Get_TX(txid crypto.Hash) (tx *transaction.Transaction) {
pool.Lock()
defer pool.Unlock()
if _, ok := pool.txs[txid]; !ok {
//loggerpool.Warnf("Pool does NOT contain %s, returning nil \n", txid)
return nil
}
// we reached here means, we have the tx, return the pointer back
object := pool.txs[txid]
return object.Tx
}
// return list of all txs in pool
func (pool *Mempool) Mempool_List_TX() []crypto.Hash {
pool.Lock()
defer pool.Unlock()
var list []crypto.Hash
for k, _ := range pool.txs {
list = append(list, k)
}
return list
}

+ 132
- 0
blockchain/mempool/mempool_test.go
File diff suppressed because it is too large
View File


+ 308
- 28
blockchain/outputs_index.go

@ -1,37 +1,89 @@
package blockchain
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain
// NOTE: this is extremely critical code ( as a single error or typo here will lead to invalid transactions )
//
// thhis file implements code which controls output indexes // thhis file implements code which controls output indexes
// rewrites them during chain reorganisation // rewrites them during chain reorganisation
import "fmt" import "fmt"
import "encoding/binary"
//import "os"
//import "io/ioutil"
//import "sync"
//import "encoding/binary"
import "github.com/vmihailenco/msgpack"
import "github.com/deroproject/derosuite/config"
import "github.com/deroproject/derosuite/crypto" import "github.com/deroproject/derosuite/crypto"
//import "github.com/deroproject/derosuite/crypto/ringct"
import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/crypto/ringct"
import "github.com/deroproject/derosuite/transaction"
import "github.com/deroproject/derosuite/walletapi"
type Output_index struct {
Key crypto.Hash // stealth address key
Commitment crypto.Hash // commitment public key
Height uint64 // height to which this belongs
type Index_Data struct {
InKey ringct.CtKey
ECDHTuple ringct.ECdhTuple // encrypted Amounts
// Key crypto.Hash // stealth address key
// Commitment crypto.Hash // commitment public key
Height uint64 // height to which this belongs
Unlock_Height uint64 // height at which it will unlock
} }
func (o *Output_index) Serialize() (result []byte) {
result = append(o.Key[:], o.Commitment[:]...)
result = append(result, itob(o.Height)...)
/*
func (o *Index_Data) Serialize() (result []byte) {
result = append(o.InKey.Destination[:], o.InKey.Mask[:]...)
result = append(result, o.ECDHTuple.Mask[:]...)
result = append(result, o.ECDHTuple.Amount[:]...)
result = append(result, itob(o.Height)...)
return return
} }
func (o *Output_index) Deserialize(buf []byte) (err error) {
if len(buf) != ( 32 + 32 + 8){
func (o *Index_Data) Deserialize(buf []byte) (err error) {
if len(buf) != ( 32 + 32 + 32+ 32+8){
return fmt.Errorf("Output index needs to be 72 bytes in size but found to be %d bytes", len(buf)) return fmt.Errorf("Output index needs to be 72 bytes in size but found to be %d bytes", len(buf))
} }
copy(o.Key[:],buf[:32])
copy(o.Commitment[:],buf[32:64])
copy(o.InKey.Destination[:],buf[:32])
copy(o.InKey.Mask[:],buf[32:64])
copy(o.ECDHTuple.Mask[:],buf[64:96])
copy(o.ECDHTuple.Amount[:],buf[96:128])
o.Height = binary.BigEndian.Uint64(buf[64:]) o.Height = binary.BigEndian.Uint64(buf[64:])
return return
} }
*/
var account walletapi.Account
/*
func init() {
var err error
account , err = wallet.Generate_Account_From_Recovery_Words("PLACE RECOVERY SEED here to test tx evaluation from within daemon")
if err != nil {
fmt.Printf("err %s\n",err)
return
}
fmt.Printf("%+v\n", account)
}
*/
// this function writes or overwrites the data related to outputs // this function writes or overwrites the data related to outputs
// the following data is collected from each output // the following data is collected from each output
@ -40,17 +92,245 @@ func (o *Output_index) Deserialize(buf []byte) (err error) {
// 8 bytes blockheight to which this output belongs // 8 bytes blockheight to which this output belongs
// this function should always succeed or panic showing something is not correct // this function should always succeed or panic showing something is not correct
// NOTE: this function should only be called after all the tx and the block has been stored to DB // NOTE: this function should only be called after all the tx and the block has been stored to DB
func (chain *Blockchain)write_output_index(block_id crypto.Hash){
// load the block
bl, err := chain.Load_BL_FROM_ID(block_id)
if err != nil {
panic(fmt.Sprintf("No such block %x\n", block_id))
}
_ = bl
func (chain *Blockchain) write_output_index(block_id crypto.Hash) {
// load the block
bl, err := chain.Load_BL_FROM_ID(block_id)
if err != nil {
logger.Warnf("No such block %s for writing output index", block_id)
return
}
index_start := chain.Get_Block_Output_Index(block_id) // get index position
height := chain.Load_Height_for_BL_ID(block_id)
logger.Debugf("Writing Output Index for block %s height %d output index %d", block_id, height, index_start)
// ads miner tx separately as a special case
var o globals.TX_Output_Data
var d Index_Data
// extract key and commitment mask from for miner tx
d.InKey.Destination = ringct.Key(bl.Miner_tx.Vout[0].Target.(transaction.Txout_to_key).Key)
// mask can be calculated for miner tx on the wallet side as below
d.InKey.Mask = ringct.ZeroCommitment_From_Amount(bl.Miner_tx.Vout[0].Amount)
d.Height = height
d.Unlock_Height = height + config.MINER_TX_AMOUNT_UNLOCK
o.TXID = bl.Miner_tx.GetHash()
o.InKey.Destination = ringct.Key(bl.Miner_tx.Vout[0].Target.(transaction.Txout_to_key).Key)
o.InKey.Mask = ringct.ZeroCommitment_From_Amount(bl.Miner_tx.Vout[0].Amount)
o.Height = height
o.Unlock_Height = 0 // miner tx caannot be locked
o.Index_within_tx = 0
o.Index_Global = index_start
o.Amount = bl.Miner_tx.Vout[0].Amount
o.SigType = 0
o.Block_Time = bl.Timestamp
//ECDHTuple & sender pk is not available for miner tx
if bl.Miner_tx.Parse_Extra() {
o.Tx_Public_Key = bl.Miner_tx.Extra_map[transaction.TX_PUBLIC_KEY].(crypto.Key)
//o.Derivation_Public_Key_From_Vout = bl.Miner_tx.Vout[0].Target.(transaction.Txout_to_key).Key
/*
* PRE-WALLET code, can be used to track down bugs in wallet
if account.Is_Output_Ours(bl.Miner_tx.Extra_map[transaction.TX_PUBLIC_KEY].(crypto.Key),0, bl.Miner_tx.Vout[0].Target.(transaction.Txout_to_key).Key){
logger.Warnf("Miner Output is ours in tx %s height %d",bl.Miner_tx.GetHash(),height)
}
*/
}
serialized, err := msgpack.Marshal(&o)
if err != nil {
panic(err)
}
//fmt.Printf("index %d %x\n",index_start,d.InKey.Destination)
// store the index and relevant keys together in compact form
chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_OUTPUT_INDEX, GALAXY_OUTPUT_INDEX, itob(index_start), serialized)
index_start++
// now loops through all the transactions, and store there ouutputs also
for i := 0; i < len(bl.Tx_hashes); i++ { // load all tx one by one
tx, err := chain.Load_TX_FROM_ID(bl.Tx_hashes[i])
if err != nil {
panic(fmt.Errorf("Cannot load tx for %x err %s", bl.Tx_hashes[i], err))
}
//fmt.Printf("tx %s",bl.Tx_hashes[i])
index_within_tx := uint64(0)
o.TXID = bl.Tx_hashes[i]
o.Height = height
o.SigType = uint64(tx.RctSignature.Get_Sig_Type())
// TODO unlock specific outputs on specific height
o.Unlock_Height = height + config.NORMAL_TX_AMOUNT_UNLOCK
// build the key image list and pack it
for j := 0; j < len(tx.Vin); j++ {
k_image := ringct.Key(tx.Vin[j].(transaction.Txin_to_key).K_image)
o.Key_Images = append(o.Key_Images, crypto.Key(k_image))
}
extra_parsed := tx.Parse_Extra()
// tx has been loaded, now lets get the vout
for j := uint64(0); j < uint64(len(tx.Vout)); j++ {
//fmt.Printf("Processing vout %d\n", j)
d.InKey.Destination = ringct.Key(tx.Vout[j].Target.(transaction.Txout_to_key).Key)
d.InKey.Mask = ringct.Key(tx.RctSignature.OutPk[j].Mask)
o.InKey.Destination = ringct.Key(tx.Vout[j].Target.(transaction.Txout_to_key).Key)
o.InKey.Mask = ringct.Key(tx.RctSignature.OutPk[j].Mask)
o.ECDHTuple = tx.RctSignature.ECdhInfo[j]
o.Index_within_tx = index_within_tx
o.Index_Global = index_start
o.Amount = tx.Vout[j].Amount
o.Unlock_Height = 0
if j == 0 && tx.Unlock_Time != 0 { // only first output of a TX can be locked
o.Unlock_Height = tx.Unlock_Time
}
// include the key image list in the first output itself
// rest all the outputs donot contain the keyimage
if j != 0 && len(o.Key_Images) > 0 {
o.Key_Images = o.Key_Images[:0]
}
if extra_parsed {
o.Tx_Public_Key = tx.Extra_map[transaction.TX_PUBLIC_KEY].(crypto.Key)
/* during emergency, for debugging purpose only
NOTE: remove this before rekeasing code
if account.Is_Output_Ours(tx.Extra_map[transaction.TX_PUBLIC_KEY].(crypto.Key),index_within_tx, tx.Vout[j].Target.(transaction.Txout_to_key).Key){
logger.Warnf("MG/simple Output is ours in tx %s at index %d height %d global index %d",bl.Tx_hashes[i],index_within_tx,height, o.Index_Global)
account.Decode_RingCT_Output(tx.Extra_map[transaction.TX_PUBLIC_KEY].(crypto.Key),
j,
crypto.Key(tx.RctSignature.OutPk[j].Mask),
tx.RctSignature.ECdhInfo[j],
2)
}
*/
}
serialized, err := msgpack.Marshal(&o)
if err != nil {
panic(err)
}
chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_OUTPUT_INDEX, GALAXY_OUTPUT_INDEX, itob(index_start), serialized)
// fmt.Printf("index %d %x\n",index_start,d.InKey.Destination)
index_start++
index_within_tx++
}
}
}
// this will load the index data for specific index
// this should be done while holding the chain lock,
// since during reorganisation we might give out wrong keys,
// to avoid that pitfall take the chain lock
// NOTE: this function is now for internal use only by the blockchain itself
//
func (chain *Blockchain) load_output_index(index uint64) (idata globals.TX_Output_Data) {
// chain.Lock()
// defer chain.Unlock()
data_bytes, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_OUTPUT_INDEX, GALAXY_OUTPUT_INDEX, itob(index))
if err != nil {
logger.Warnf("err while loading output index data index = %d err %s", index, err)
return
}
err = msgpack.Unmarshal(data_bytes, &idata)
if err != nil {
logger.Warnf("err while unmarshallin output index data index = %d data_len %d err %s", index, len(data_bytes), err)
return
}
return
}
// this will read the output index data but will not deserialize it
// this is exposed for rpcserver giving access to wallet
func (chain *Blockchain) Read_output_index(index uint64) (data_bytes []byte, err error) {
chain.Lock()
defer chain.Unlock()
data_bytes, err = chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_OUTPUT_INDEX, GALAXY_OUTPUT_INDEX, itob(index))
if err != nil {
logger.Warnf("err while loading output index data index = %d err %s", index, err)
return
}
return data_bytes, err
}
// this function finds output index for the tx
// first find a block index , and get the start offset
// then loop the index till you find the key in the result
// if something is not right, we return 0
func (chain *Blockchain) Find_TX_Output_Index(tx_hash crypto.Hash) (offset uint64) {
Block_Height := chain.Load_TX_Height(tx_hash) // get height
block_id, err := chain.Load_BL_ID_at_Height(Block_Height)
if err != nil {
logger.Warnf("error while finding tx_output_index %s", tx_hash)
return 0
}
block_index_start := chain.Get_Block_Output_Index(block_id)
// output_max_count := chain.Block_Count_Vout(block_id) // this function will load/serdes all tx contained within block
/*for index_start:= block_index_start; index_start < (block_index_start+output_max_count); index_start++{
}
*/
bl, err := chain.Load_BL_FROM_ID(block_id)
if err != nil {
logger.Warnf("Cannot load block for %s err %s", block_id, err)
return
}
if tx_hash == bl.Miner_tx.GetHash() {
return block_index_start
}
offset = block_index_start + 1 // shift by 1
for i := 0; i < len(bl.Tx_hashes); i++ { // load all tx one by one
if bl.Tx_hashes[i] == tx_hash {
return offset
}
tx, err := chain.Load_TX_FROM_ID(bl.Tx_hashes[i])
if err != nil {
logger.Warnf("Cannot load tx for %s err %s", bl.Tx_hashes[i], err)
}
// tx has been loaded, now lets get the vout
vout_count := uint64(len(tx.Vout))
offset += vout_count
}
// we will reach here only if tx is linked to wrong block
// this may be possible during reorganisation
// return 0
logger.Warnf("Index Position must never reach here")
return 0
} }

+ 2
- 2
blockchain/readme.txt

@ -32,6 +32,6 @@ the psedo code is as follows
7) if yes,update main chain 7) if yes,update main chain
8) if not we have to do chain reorganisation at the top 8) if not we have to do chain reorganisation at the top
9) choose the block with higher poW as new top 9) choose the block with higher poW as new top
10) push alt chain txs to mem pool
10) push alt chain txs to mem pool after verification
11) if block is being added somewhere in the middle, find the chain with higher Pow as main chain 11) if block is being added somewhere in the middle, find the chain with higher Pow as main chain
12) push the orphan block txs to mempool
12) push the orphan block txs to mempool after verification

+ 16
- 1
blockchain/reorg_test.go

@ -1,5 +1,20 @@
package blockchain
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain
import "sort" import "sort"
import "testing" import "testing"

+ 90
- 0
blockchain/rpcserver/LICENSE

@ -0,0 +1,90 @@
RESEARCH LICENSE
Version 1.1.2
I. DEFINITIONS.
"Licensee " means You and any other party that has entered into and has in effect a version of this License.
“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees.
"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology.
"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage.
"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License.
"Technology Site" means the website designated by Licensor for accessing the Technology.
"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License.
II. PURPOSE.
Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology.
COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT <url>.
III. RESEARCH USE RIGHTS.
A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only:
1. reproduce, create Modifications of, and use the Technology alone, or with Modifications;
2. share source code of the Technology alone, or with Modifications, with other Licensees;
3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and
4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology.
B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights.
C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License.
D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution.
IV. INTELLECTUAL PROPERTY REQUIREMENTS
As a condition to Your License, You agree to comply with the following restrictions and responsibilities:
A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology.
B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License.
V. GENERAL TERMS.
A. Disclaimer Of Warranties.
TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE.
B. Infringement; Limitation Of Liability.
1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site.
2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY.
C. Termination.
1. You may terminate this License at any time by notifying Licensor in writing.
2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance.
3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination.
D. Miscellaneous.
1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor.
2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof.
3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate.
4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter.
5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications.
READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING.
BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS.
IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM.

+ 12
- 0
blockchain/rpcserver/dummy_test.go

@ -0,0 +1,12 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
package rpcserver
import "testing"
func Test_Part1(t *testing.T) {
}

+ 47
- 0
blockchain/rpcserver/echo.go

@ -0,0 +1,47 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
import "context"
//import "log"
//import "net/http"
import "github.com/intel-go/fastjson"
import "github.com/osamingo/jsonrpc"
type (
EchoHandler struct{}
EchoParams struct {
Name string `json:"name"`
}
EchoResult struct {
Message string `json:"message"`
}
)
func (h EchoHandler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
var p EchoParams
if err := jsonrpc.Unmarshal(params, &p); err != nil {
return nil, err
}
return EchoResult{
Message: "Hello, " + p.Name,
}, nil
}

+ 93
- 0
blockchain/rpcserver/getblock.go

@ -0,0 +1,93 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
// get block template handler not implemented
//import "fmt"
import "context"
import "encoding/hex"
import "encoding/json"
//import "log"
//import "net/http"
import "github.com/intel-go/fastjson"
import "github.com/osamingo/jsonrpc"
import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/blockchain"
type (
GetBlock_Handler struct{}
GetBlock_Params struct {
Hash string `json:"hash,omitempty"` // Monero Daemon breaks if both are provided
Height uint64 `json:"height,omitempty"` // Monero Daemon breaks if both are provided
} // no params
GetBlock_Result struct {
Blob string `json:"blob"`
Json string `json:"json"`
Block_Header blockchain.BlockHeader_Print `json:"block_header"`
Status string `json:"status"`
}
)
// TODO
func (h GetBlock_Handler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
var p GetBlock_Params
var hash crypto.Hash
var err error
if errp := jsonrpc.Unmarshal(params, &p); err != nil {
return nil, errp
}
if crypto.HashHexToHash(p.Hash) == hash { // user requested using height
if p.Height >= chain.Get_Height() {
return nil, jsonrpc.ErrInvalidParams()
}
hash, err = chain.Load_BL_ID_at_Height(p.Height)
if err != nil { // if err return err
logger.Warnf("User requested %d height block, chain height %d but err occured %s", p.Height, chain.Get_Height(), err)
return nil, jsonrpc.ErrInvalidParams()
}
} else {
hash = crypto.HashHexToHash(p.Hash)
}
block_header, err := chain.GetBlockHeader(hash)
if err != nil { // if err return err
return nil, jsonrpc.ErrInvalidParams()
}
bl, err := chain.Load_BL_FROM_ID(hash)
if err != nil { // if err return err
return nil, jsonrpc.ErrInvalidParams()
}
json_encoded_bytes, err := json.Marshal(bl)
if err != nil { // if err return err
return nil, jsonrpc.ErrInvalidParams()
}
return GetBlock_Result{ // return success
Block_Header: block_header,
Blob: hex.EncodeToString(bl.Serialize()),
Json: string(json_encoded_bytes),
Status: "OK",
}, nil
}

+ 58
- 0
blockchain/rpcserver/getblock_template.go

@ -0,0 +1,58 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
// get block template handler not implemented
//import "fmt"
import "context"
//import "log"
//import "net/http"
import "github.com/intel-go/fastjson"
import "github.com/osamingo/jsonrpc"
type (
GetBlockTemplate_Handler struct{}
GetBlockTemplate_Params struct {
Wallet_Address string `json:"wallet_address"`
Reserve_size uint64 `json:"reserve_size"`
}
GetBlockTemplate_Result struct {
Blocktemplate_blob string `json:"blocktemplate_blob"`
Difficulty uint64 `json:"difficulty"`
Height uint64 `json:"height"`
Prev_Hash string `json:"prev_hash"`
Reserved_Offset uint64 `json:"reserved_offset"`
Status string `json:"status"`
}
)
func (h GetBlockTemplate_Handler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
var p GetBlockTemplate_Params
if err := jsonrpc.Unmarshal(params, &p); err != nil {
return nil, err
}
// Wallet_Address needs to validated before
return GetBlockTemplate_Result{
Status: "NOT IMPLEMENTED",
}, nil
}

+ 43
- 0
blockchain/rpcserver/getblockcount.go

@ -0,0 +1,43 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
import "context"
//import "log"
//import "net/http"
import "github.com/intel-go/fastjson"
import "github.com/osamingo/jsonrpc"
type (
GetBlockCount_Handler struct{}
GetBlockCount_Params struct {
// NO params
}
GetBlockCount_Result struct {
Count uint64 `json:"count"`
Status string `json:"status"`
}
)
func (h GetBlockCount_Handler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
return GetBlockCount_Result{
Count: chain.Get_Height() - 1,
Status: "OK",
}, nil
}

+ 61
- 0
blockchain/rpcserver/getblockheaderbyhash.go

@ -0,0 +1,61 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
// get block template handler not implemented
//import "fmt"
import "context"
//import "log"
//import "net/http"
import "github.com/intel-go/fastjson"
import "github.com/osamingo/jsonrpc"
import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/blockchain"
type (
GetBlockHeaderByHash_Handler struct{}
GetBlockHeaderByHash_Params struct {
Hash string `json:"hash"`
} // no params
GetBlockHeaderByHash_Result struct {
Block_Header blockchain.BlockHeader_Print `json:"block_header"`
Status string `json:"status"`
}
)
func (h GetBlockHeaderByHash_Handler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
var p GetBlockHeaderByHash_Params
if err := jsonrpc.Unmarshal(params, &p); err != nil {
return nil, err
}
hash := crypto.HashHexToHash(p.Hash)
block_header, err := chain.GetBlockHeader(hash)
if err != nil { // if err return err
return nil, jsonrpc.ErrInvalidParams()
}
return GetBlockHeaderByHash_Result{ // return success
Block_Header: block_header,
Status: "OK",
}, nil
}

+ 72
- 0
blockchain/rpcserver/getblockheaderbyheight.go

@ -0,0 +1,72 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
// get block template handler not implemented
//import "fmt"
import "context"
//import "log"
//import "net/http"
import "github.com/intel-go/fastjson"
import "github.com/osamingo/jsonrpc"
//import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/blockchain"
type (
GetBlockHeaderByHeight_Handler struct{}
GetBlockHeaderByHeight_Params struct {
Height uint64 `json:"height"`
} // no params
GetBlockHeaderByHeight_Result struct {
Block_Header blockchain.BlockHeader_Print `json:"block_header"`
Status string `json:"status"`
}
)
func (h GetBlockHeaderByHeight_Handler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
var p GetBlockHeaderByHeight_Params
if err := jsonrpc.Unmarshal(params, &p); err != nil {
return nil, err
}
if p.Height >= chain.Get_Height() {
return nil, jsonrpc.ErrInvalidParams()
}
hash, err := chain.Load_BL_ID_at_Height(p.Height)
if err != nil { // if err return err
logger.Warnf("User requested %d height block, chain height %d but err occured %s", p.Height, chain.Get_Height(), err)
return nil, jsonrpc.ErrInvalidParams()
}
block_header, err := chain.GetBlockHeader(hash)
if err != nil { // if err return err
logger.Warnf("User requested %d height block, chain height %d but err occured %s", p.Height, chain.Get_Height(), err)
return nil, jsonrpc.ErrInvalidParams()
}
return GetBlockHeaderByHeight_Result{ // return success
Block_Header: block_header,
Status: "OK",
}, nil
}

+ 94
- 0
blockchain/rpcserver/getinfo.go

@ -0,0 +1,94 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
// get block template handler not implemented
//import "fmt"
import "context"
//import "log"
//import "net/http"
import "github.com/intel-go/fastjson"
import "github.com/osamingo/jsonrpc"
import "github.com/deroproject/derosuite/config"
import "github.com/deroproject/derosuite/globals"
/*
{
"id": "0",
"jsonrpc": "2.0",
"result": {
"alt_blocks_count": 5,
"difficulty": 972165250,
"grey_peerlist_size": 2280,
"height": 993145,
"incoming_connections_count": 0,
"outgoing_connections_count": 8,
"status": "OK",
"target": 60,
"target_height": 993137,
"testnet": false,
"top_block_hash": "",
"tx_count": 564287,
"tx_pool_size": 45,
"white_peerlist_size": 529
}
}*/
type (
GetInfo_Handler struct{}
GetInfo_Params struct{} // no params
GetInfo_Result struct {
Alt_Blocks_Count uint64 `json:"alt_blocks_count"`
Difficulty uint64 `json:"difficulty"`
Grey_PeerList_Size uint64 `json:"grey_peerlist_size"`
Height uint64 `json:"height"`
Incoming_connections_count uint64 `json:"incoming_connections_count"`
Outgoing_connections_count uint64 `json:"outgoing_connections_count"`
Target uint64 `json:"target"`
Target_Height uint64 `json:"target_height"`
Testnet bool `json:"testnet"`
Top_block_hash string `json:"top_block_hash"`
Tx_count uint64 `json:"tx_count"`
Tx_pool_size uint64 `json:"tx_pool_size"`
White_peerlist_size uint64 `json:"white_peerlist_size"`
Status string `json:"status"`
}
)
// TODO
func (h GetInfo_Handler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
var result GetInfo_Result
top_id := chain.Get_Top_ID()
result.Difficulty = chain.Get_Difficulty_At_Block(top_id)
result.Height = chain.Get_Height() - 1
result.Status = "OK"
result.Top_block_hash = top_id.String()
result.Target = config.BLOCK_TIME
result.Target_Height = chain.Get_Height()
result.Tx_pool_size = uint64(len(chain.Mempool.Mempool_List_TX()))
if globals.Config.Name != config.Mainnet.Name { // anything other than mainnet is testnet at this point in time
result.Testnet = true
}
return result, nil
}

+ 49
- 0
blockchain/rpcserver/getlastblockheader.go

@ -0,0 +1,49 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
// get block template handler not implemented
//import "fmt"
import "context"
//import "log"
//import "net/http"
import "github.com/intel-go/fastjson"
import "github.com/osamingo/jsonrpc"
import "github.com/deroproject/derosuite/blockchain"
type (
GetLastBlockHeader_Handler struct{}
GetLastBlockHeader_Params struct{} // no params
GetLastBlockHeader_Result struct {
Block_Header blockchain.BlockHeader_Print `json:"block_header"`
Status string `json:"status"`
}
)
func (h GetLastBlockHeader_Handler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
top_hash := chain.Get_Top_ID()
block_header, _ := chain.GetBlockHeader(top_hash)
return GetLastBlockHeader_Result{
Block_Header: block_header,
Status: "OK",
}, nil
}

+ 95
- 0
blockchain/rpcserver/getoutputs.bin.go

@ -0,0 +1,95 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
import "strconv"
import "net/http"
import "compress/gzip"
//import "github.com/pierrec/lz4"
// serve the outputs in streaming mode
// feeds any outputs requested by the server
func getoutputs(rw http.ResponseWriter, req *http.Request) {
var err error
start := uint64(0)
stop := uint64(0)
{ // parse start query parameter
keys, ok := req.URL.Query()["start"]
if !ok || len(keys) < 1 {
//log.Println("Url Param 'key' is missing")
//return
} else {
start_string := keys[0]
start, err = strconv.ParseUint(start_string, 10, 64)
if err != nil {
start = 0
}
}
}
{ // parse stop query parameter
keys, ok := req.URL.Query()["stop"]
if !ok || len(keys) < 1 {
} else {
stop_string := keys[0]
stop, err = strconv.ParseUint(stop_string, 10, 64)
if err != nil {
stop = 0
}
}
}
// do sanity check of stop first
top_id := chain.Get_Top_ID()
biggest_output_index := chain.Block_Count_Vout(top_id) + chain.Get_Block_Output_Index(top_id)
if stop == 0 || stop > biggest_output_index {
stop = biggest_output_index
}
// feed in atleast 1 index
if start >= stop {
start = stop - 1
}
/* lz4writer := lz4.NewWriter(rw)
lz4writer.HighCompression = true // enable extreme but slow compression
lz4writer.BlockMaxSize = 256*1024 // small block size to decrease memory consumption
*/
gzipwriter := gzip.NewWriter(rw)
defer gzipwriter.Close()
for i := start; i <= stop; i++ {
// load the bytes and send them
data, err := chain.Read_output_index(i)
if err != nil {
logger.Warnf("err while reading output err: %s\n", err)
break
}
//
//rw.Write(data)
// lz4writer.Write(data)
gzipwriter.Write(data)
}
//lz4writer.Flush() // flush any pending data
}

+ 125
- 0
blockchain/rpcserver/gettransactions.go

@ -0,0 +1,125 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
import "net/http"
import "encoding/hex"
import "encoding/json"
import "github.com/deroproject/derosuite/crypto"
// we definitely need to clear up the MESS that has been created by the MONERO project
// half of their APIs are json rpc and half are http
// for compatibility reasons, we are implementing theirs ( however we are also providin a json rpc implementation)
// we should DISCARD the http
// NOTE: we have currently not implemented the decode as json parameter
// it is however on the pending list
type (
GetTransaction_Handler struct{}
GetTransaction_Params struct {
Tx_Hashes []string `json:"txs_hashes"`
Decode uint64 `json:"decode_as_json,omitempty"` // Monero Daemon breaks if this sent
} // no params
GetTransaction_Result struct {
Txs_as_hex []string `json:"txs_as_hex"`
Txs_as_json []string `json:"txs_as_json"`
Txs []Tx_Related_Info `json:"txs"`
Status string `json:"status"`
}
Tx_Related_Info struct {
As_Hex string `json:"as_hex"`
As_Json string `json:"as_json"`
Block_Height int64 `json:"block_height"`
In_pool bool `json:"in_pool"`
Output_Indices []uint64 `json:"output_indices"`
Tx_hash string `json:"tx_hash"`
}
)
func gettransactions(rw http.ResponseWriter, req *http.Request) {
decoder := json.NewDecoder(req.Body)
var p GetTransaction_Params
err := decoder.Decode(&p)
if err != nil {
panic(err)
}
defer req.Body.Close()
result := gettransactions_fill(p)
//logger.Debugf("Request %+v", p)
encoder := json.NewEncoder(rw)
encoder.Encode(result)
}
// fill up the response
func gettransactions_fill(p GetTransaction_Params) (result GetTransaction_Result) {
for i := 0; i < len(p.Tx_Hashes); i++ {
hash := crypto.HashHexToHash(p.Tx_Hashes[i])
// check whether we can get the tx from the pool
{
tx := chain.Mempool.Mempool_Get_TX(hash)
if tx != nil { // found the tx in the mempool
result.Txs_as_hex = append(result.Txs_as_hex, hex.EncodeToString(tx.Serialize()))
var related Tx_Related_Info
related.Block_Height = -1 // not mined
related.In_pool = true
for i := 0; i < len(tx.Vout); i++ {
related.Output_Indices = append(related.Output_Indices, 0) // till the tx is mined we do not get indices
}
result.Txs = append(result.Txs, related)
continue // no more processing required
}
}
tx, err := chain.Load_TX_FROM_ID(hash)
if err == nil {
result.Txs_as_hex = append(result.Txs_as_hex, hex.EncodeToString(tx.Serialize()))
var related Tx_Related_Info
related.Block_Height = int64(chain.Load_TX_Height(hash))
index := chain.Find_TX_Output_Index(hash)
// logger.Infof("TX hash %s height %d",hash, related.Block_Height)
for i := 0; i < len(tx.Vout); i++ {
related.Output_Indices = append(related.Output_Indices, index+uint64(i))
}
result.Txs = append(result.Txs, related)
} else { // we could not fetch the tx, return an empty string
result.Txs_as_hex = append(result.Txs_as_hex, "")
result.Status = "TX NOT FOUND"
return
}
}
result.Status = "OK"
return
}

+ 51
- 0
blockchain/rpcserver/gettxpool.go

@ -0,0 +1,51 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
// get GetTxPool handler not implemented
import "fmt"
import "context"
//import "log"
//import "net/http"
import "github.com/intel-go/fastjson"
import "github.com/osamingo/jsonrpc"
type (
GetTxPool_Handler struct{}
GetTxPool_Params struct{} // no params
GetTxPool_Result struct {
Tx_list []string `json:"txs,omitempty"`
Status string `json:"status"`
}
)
// TODO
func (h GetTxPool_Handler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
var result GetTxPool_Result
result.Status = "OK"
pool_list := chain.Mempool.Mempool_List_TX()
for i := range pool_list {
result.Tx_list = append(result.Tx_list, fmt.Sprintf("%s", pool_list[i]))
}
return result, nil
}

+ 55
- 0
blockchain/rpcserver/on_getblockhash.go

@ -0,0 +1,55 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
import "fmt"
import "context"
//import "log"
//import "net/http"
import "github.com/intel-go/fastjson"
import "github.com/osamingo/jsonrpc"
type (
On_GetBlockHash_Handler struct{}
On_GetBlockHash_Params struct {
X [1]uint64
}
On_GetBlockHash_Result struct{}
)
func (h On_GetBlockHash_Handler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
var height [1]uint64
//var result On_GetBlockHash_Result
if err := jsonrpc.Unmarshal(params, &height); err != nil {
return nil, err
}
if height[0] < chain.Get_Height() {
hash, err := chain.Load_BL_ID_at_Height(height[0])
if err == nil {
result := fmt.Sprintf("%s", hash)
return result, nil
} else {
logger.Warnf("NOT possible, Could not find block at height %d Chain height %d\n", height[0], chain.Get_Height())
}
}
// if we reach here some error is here
return nil, jsonrpc.ErrInvalidParams()
}

+ 150
- 0
blockchain/rpcserver/rpcserver.go

@ -0,0 +1,150 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
import "io"
import "fmt"
import "time"
import "sync"
import "sync/atomic"
//import "context"
import "net/http"
//import "github.com/intel-go/fastjson"
import "github.com/osamingo/jsonrpc"
import log "github.com/sirupsen/logrus"
import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/blockchain"
/* this file implements the rpcserver api, so as wallet and block explorer tools can work without migration */
// all components requiring access to blockchain must use , this struct to communicate
// this structure must be update while mutex
type RPCServer struct {
Exit_Event chan bool // blockchain is shutting down and we must quit ASAP
sync.RWMutex
}
var Exit_In_Progress bool
var chain *blockchain.Blockchain
var logger *log.Entry
func RPCServer_Start(params map[string]interface{}) (*RPCServer, error) {
var err error
var r RPCServer
_ = err
r.Exit_Event = make(chan bool)
logger = globals.Logger.WithFields(log.Fields{"com": "RPC"}) // all components must use this logger
chain = params["chain"].(*blockchain.Blockchain)
// test whether chain is okay
if chain.Get_Height() == 0 {
return nil, fmt.Errorf("Chain DOES NOT have genesis block")
}
go r.Run()
logger.Infof("RPC server started")
atomic.AddUint32(&globals.Subsystem_Active, 1) // increment subsystem
return &r, nil
}
// shutdown the rpc server component
func (r *RPCServer) RPCServer_Stop() {
Exit_In_Progress = true
close(r.Exit_Event) // send signal to all connections to exit
// TODO we must wait for connections to kill themselves
time.Sleep(1 * time.Second)
logger.Infof("RPC Shutdown")
atomic.AddUint32(&globals.Subsystem_Active, ^uint32(0)) // this decrement 1 fom subsystem
}
func (r *RPCServer) Run() {
mr := jsonrpc.NewMethodRepository()
if err := mr.RegisterMethod("Main.Echo", EchoHandler{}, EchoParams{}, EchoResult{}); err != nil {
log.Fatalln(err)
}
// install getblockcount handler
if err := mr.RegisterMethod("getblockcount", GetBlockCount_Handler{}, GetBlockCount_Params{}, GetBlockCount_Result{}); err != nil {
log.Fatalln(err)
}
// install on_getblockhash
if err := mr.RegisterMethod("on_getblockhash", On_GetBlockHash_Handler{}, On_GetBlockHash_Params{}, On_GetBlockHash_Result{}); err != nil {
log.Fatalln(err)
}
// install getblocktemplate handler
if err := mr.RegisterMethod("getblocktemplate", GetBlockTemplate_Handler{}, GetBlockTemplate_Params{}, GetBlockTemplate_Result{}); err != nil {
log.Fatalln(err)
}
// submitblock handler
if err := mr.RegisterMethod("submitblock", SubmitBlock_Handler{}, SubmitBlock_Params{}, SubmitBlock_Result{}); err != nil {
log.Fatalln(err)
}
if err := mr.RegisterMethod("getlastblockheader", GetLastBlockHeader_Handler{}, GetLastBlockHeader_Params{}, GetLastBlockHeader_Result{}); err != nil {
log.Fatalln(err)
}
if err := mr.RegisterMethod("getblockheaderbyhash", GetBlockHeaderByHash_Handler{}, GetBlockHeaderByHash_Params{}, GetBlockHeaderByHash_Result{}); err != nil {
log.Fatalln(err)
}
if err := mr.RegisterMethod("getblockheaderbyheight", GetBlockHeaderByHeight_Handler{}, GetBlockHeaderByHeight_Params{}, GetBlockHeaderByHeight_Result{}); err != nil {
log.Fatalln(err)
}
if err := mr.RegisterMethod("getblock", GetBlock_Handler{}, GetBlock_Params{}, GetBlock_Result{}); err != nil {
log.Fatalln(err)
}
if err := mr.RegisterMethod("get_info", GetInfo_Handler{}, GetInfo_Params{}, GetInfo_Result{}); err != nil {
log.Fatalln(err)
}
if err := mr.RegisterMethod("gettxpool", GetTxPool_Handler{}, GetTxPool_Params{}, GetTxPool_Result{}); err != nil {
log.Fatalln(err)
}
http.HandleFunc("/", hello)
http.Handle("/json_rpc", mr)
// handle nasty http requests
http.HandleFunc("/getoutputs.bin", getoutputs) // stream any outputs to server, can make wallet work offline
http.HandleFunc("/gettransactions", gettransactions)
//http.HandleFunc("/json_rpc/debug", mr.ServeDebug)
if err := http.ListenAndServe("127.0.0.1:9999", http.DefaultServeMux); err != nil {
log.Fatalln(err)
}
}
func hello(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello world!")
}

+ 58
- 0
blockchain/rpcserver/submit.go

@ -0,0 +1,58 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package rpcserver
// get block template handler not implemented
//import "fmt"
import "context"
//import "log"
//import "net/http"
import "github.com/intel-go/fastjson"
import "github.com/osamingo/jsonrpc"
type (
SubmitBlock_Handler struct{}
SubmitBlock_Params struct {
Wallet_Address string `json:"wallet_address"`
Reserve_size uint64 `json:"reserve_size"`
}
SubmitBlock_Result struct {
Blocktemplate_blob string `json:"blocktemplate_blob"`
Difficulty uint64 `json:"difficulty"`
Height uint64 `json:"height"`
Prev_Hash string `json:"prev_hash"`
Reserved_Offset uint64 `json:"reserved_offset"`
Status string `json:"status"`
}
)
func (h SubmitBlock_Handler) ServeJSONRPC(c context.Context, params *fastjson.RawMessage) (interface{}, *jsonrpc.Error) {
var p GetBlockTemplate_Params
if err := jsonrpc.Unmarshal(params, &p); err != nil {
return nil, err
}
// Wallet_Address needs to validated before
return SubmitBlock_Result{
Status: "NOT IMPLEMENTED",
}, nil
}

+ 0
- 9
blockchain/signature.go

@ -1,9 +0,0 @@
package blockchain
// version 1 transaction support
const SIGNATURE_V1_LENGTH = 64
type Signature_v1 struct {
R [32]byte
C [32]byte
}

+ 175
- 63
blockchain/store.go

@ -1,3 +1,19 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain package blockchain
import "fmt" import "fmt"
@ -5,10 +21,10 @@ import "encoding/binary"
//import log "github.com/sirupsen/logrus" //import log "github.com/sirupsen/logrus"
import "github.com/deroproject/derosuite/block"
import "github.com/deroproject/derosuite/crypto" import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/globals" import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/transaction"
/* this file implements the only interface which translates comands to/from blockchain to storage layer * /* this file implements the only interface which translates comands to/from blockchain to storage layer *
* *
@ -50,16 +66,15 @@ var GALAXY_OUTPUT_INDEX = []byte("OUTPUT_INDEX") // incremental index over outp
// individual attributes becomes the planets // individual attributes becomes the planets
// individual attributes should be max 1 or 2 chars long, as they will be repeated millions of times and storing a static string millions of times shows foolishness // individual attributes should be max 1 or 2 chars long, as they will be repeated millions of times and storing a static string millions of times shows foolishness
var PLANET_BLOB = []byte("BLOB") //it shows serialised block
var PLANET_HEIGHT = []byte("HEIGHT") // contains height
var PLANET_PARENT = []byte("PARENT") // parent of block
var PLANET_BLOB = []byte("BLOB") //it shows serialised block
var PLANET_HEIGHT = []byte("HEIGHT") // contains height
var PLANET_PARENT = []byte("PARENT") // parent of block
var PLANET_SIZE = []byte("SIZE") // sum of block + all txs var PLANET_SIZE = []byte("SIZE") // sum of block + all txs
var PLANET_ALREADY_GENERATED_COINS = []byte("CCOINS") // all coins generated till this block var PLANET_ALREADY_GENERATED_COINS = []byte("CCOINS") // all coins generated till this block
var PLANET_OUTPUT_INDEX = []byte("OUTPUT_INDEX") // tx outputs indexing starts from here for this block
var PLANET_OUTPUT_INDEX = []byte("OUTPUT_INDEX") // tx outputs indexing starts from here for this block
var PLANET_CUMULATIVE_DIFFICULTY = []byte("CDIFFICULTY") var PLANET_CUMULATIVE_DIFFICULTY = []byte("CDIFFICULTY")
var PLANET_CHILD = []byte("CHILD") var PLANET_CHILD = []byte("CHILD")
//var PLANET_ORPHAN = []byte("ORPHAN")
var PLANET_BASEREWARD = []byte("BASEREWARD") // base reward of a block
var PLANET_TIMESTAMP = []byte("TIMESTAMP") var PLANET_TIMESTAMP = []byte("TIMESTAMP")
// this ill only be present if more tahn 1 child exists // this ill only be present if more tahn 1 child exists
@ -67,7 +82,7 @@ var PLANET_CHILDREN = []byte("CHILREN") // children list excludes the main child
// the TX has the following attributes // the TX has the following attributes
var PLANET_TX_BLOB = []byte("BLOB") // contains serialised TX , this attribute is also found in BLOCK where var PLANET_TX_BLOB = []byte("BLOB") // contains serialised TX , this attribute is also found in BLOCK where
var PLANET_TX_MINED_IN_BLOCK = []byte("MINERBLOCK") // which block mined this tx
var PLANET_TX_MINED_IN_BLOCK = []byte("MINERBLOCK") // which block mined this tx, height
var PLANET_TX_SIZE = []byte("SIZE") var PLANET_TX_SIZE = []byte("SIZE")
// the universe concept is there, as we bring in smart contracts, we will give each of them a universe to play within // the universe concept is there, as we bring in smart contracts, we will give each of them a universe to play within
@ -164,7 +179,7 @@ func (chain *Blockchain) Load_Block_Children(parent_id crypto.Hash) (children []
children_bytes, _ := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, parent_id[:], PLANET_CHILDREN) children_bytes, _ := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, parent_id[:], PLANET_CHILDREN)
if len(children_bytes)%32 != 0 { if len(children_bytes)%32 != 0 {
panic(fmt.Sprintf("parent does not have child hash in multiples of 32, block_hash %x", parent_id))
panic(fmt.Sprintf("parent does not have child hash in multiples of 32, block_hash %s", parent_id))
} }
for i := 0; i < len(children_bytes); i = i + 32 { for i := 0; i < len(children_bytes); i = i + 32 {
copy(child_hash[:], children_bytes[i:i+32]) copy(child_hash[:], children_bytes[i:i+32])
@ -175,13 +190,16 @@ func (chain *Blockchain) Load_Block_Children(parent_id crypto.Hash) (children []
// store a tx // store a tx
// this only occurs when a tx has been mined // this only occurs when a tx has been mined
func (chain *Blockchain) Store_TX(tx *Transaction) {
// stores a height to show at what height it has been mined
func (chain *Blockchain) Store_TX(tx *transaction.Transaction, Height uint64) {
hash := tx.GetHash() hash := tx.GetHash()
serialized := tx.Serialize() serialized := tx.Serialize()
err := chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, hash[:], PLANET_TX_BLOB, serialized) err := chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, hash[:], PLANET_TX_BLOB, serialized)
// store size of tx // store size of tx
chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, hash[:], PLANET_TX_SIZE, uint64(len(serialized))) chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, hash[:], PLANET_TX_SIZE, uint64(len(serialized)))
chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, hash[:], PLANET_TX_MINED_IN_BLOCK, Height)
_ = err _ = err
} }
@ -196,17 +214,26 @@ func (chain *Blockchain) Load_TX_Size(txhash crypto.Hash) uint64 {
size, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, txhash[:], PLANET_TX_SIZE) size, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, txhash[:], PLANET_TX_SIZE)
if err != nil { if err != nil {
logger.Warnf("Size not stored for tx %x", txhash)
logger.Warnf("Size not stored for tx %s", txhash)
} }
return size return size
} }
// load height at which a specific tx was mined
func (chain *Blockchain) Load_TX_Height(txhash crypto.Hash) uint64 {
height, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, txhash[:], PLANET_TX_MINED_IN_BLOCK)
if err != nil {
logger.Warnf("Error while querying height for tx %s\n", txhash)
}
return height
}
// BUG we should be able to delete any arbitrary key // BUG we should be able to delete any arbitrary key
// since a tx mined by one block, can be back in pool after chain reorganises // since a tx mined by one block, can be back in pool after chain reorganises
// TODO the miner tx should be extracted ands stored from somewhere else // TODO the miner tx should be extracted ands stored from somewhere else
// NOTE: before storing a block, its transactions must be stored // NOTE: before storing a block, its transactions must be stored
func (chain *Blockchain) Store_BL(bl *Block) {
func (chain *Blockchain) Store_BL(bl *block.Block) {
// store block height BHID automatically // store block height BHID automatically
@ -245,38 +272,52 @@ func (chain *Blockchain) Store_BL(bl *Block) {
total_difficulty := cumulative_difficulty + difficulty_of_current_block total_difficulty := cumulative_difficulty + difficulty_of_current_block
chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_CUMULATIVE_DIFFICULTY, total_difficulty) chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_CUMULATIVE_DIFFICULTY, total_difficulty)
// total size of block = size of block + size of all transactions in block ( excludind miner tx)
size_of_block := uint64(len(serialized_bytes))
// total size of block = size of miner_tx + size of all transactions in block ( excludind miner tx)
size_of_block := uint64(len(bl.Miner_tx.Serialize()))
for i := 0; i < len(bl.Tx_hashes); i++ { for i := 0; i < len(bl.Tx_hashes); i++ {
size_of_tx := chain.Load_TX_Size(bl.Tx_hashes[i]) size_of_tx := chain.Load_TX_Size(bl.Tx_hashes[i])
size_of_block += size_of_tx size_of_block += size_of_tx
} }
chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_SIZE, size_of_block) chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_SIZE, size_of_block)
// calculated position of vouts in global index
/* TODO below code has been disabled and should be enabled for extensive testing
index_pos := uint64(0)
if hash != globals.Config.Genesis_Block_Hash {
// load index pos from last block + add count of vouts from last block
index_pos = chain.Get_Block_Output_Index(bl.Prev_Hash)
vout_count_prev_block := chain.Block_Count_Vout(bl.Prev_Hash)
index_pos += vout_count_prev_block
}
chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_OUTPUT_INDEX, index_pos)
logger.Debugf("height %d output index %d\n",height, index_pos)
*/
// TODO calculate total coins emitted till this block
// calculated position of vouts in global indexs
index_pos := uint64(0)
if hash != globals.Config.Genesis_Block_Hash {
// load index pos from last block + add count of vouts from last block
index_pos = chain.Get_Block_Output_Index(bl.Prev_Hash)
vout_count_prev_block := chain.Block_Count_Vout(bl.Prev_Hash)
index_pos += vout_count_prev_block
}
chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_OUTPUT_INDEX, index_pos)
//logger.Debugf("height %d output index %d",height, index_pos)
total_fees := uint64(0)
for i := 0; i < len(bl.Tx_hashes); i++ {
tx, _ := chain.Load_TX_FROM_ID(bl.Tx_hashes[i])
total_fees += tx.RctSignature.Get_TX_Fee()
}
total_reward := bl.Miner_tx.Vout[0].Amount
base_reward := total_reward - total_fees
chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_BASEREWARD, base_reward)
already_generated_coins := uint64(0)
if hash != globals.Config.Genesis_Block_Hash { // genesis block has no parent
already_generated_coins = chain.Load_Already_Generated_Coins_for_BL_ID(bl.Prev_Hash)
} else {
base_reward = 1000000000000 // trigger the bug to fix coin calculation, see comments in emission
}
already_generated_coins += base_reward
chain.store.StoreUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_ALREADY_GENERATED_COINS, already_generated_coins)
// also extract and store the miner tx separetly, fr direct querying purpose // also extract and store the miner tx separetly, fr direct querying purpose
chain.Store_TX(&bl.Miner_tx)
chain.Store_TX(&bl.Miner_tx, height)
_ = err _ = err
} }
func (chain *Blockchain) Load_TX_FROM_ID(hash [32]byte) (*Transaction, error) {
var tx Transaction
func (chain *Blockchain) Load_TX_FROM_ID(hash [32]byte) (*transaction.Transaction, error) {
var tx transaction.Transaction
tx_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, hash[:], PLANET_TX_BLOB) tx_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_TRANSACTION, hash[:], PLANET_TX_BLOB)
if err != nil { if err != nil {
@ -287,19 +328,15 @@ func (chain *Blockchain) Load_TX_FROM_ID(hash [32]byte) (*Transaction, error) {
err = tx.DeserializeHeader(tx_data) err = tx.DeserializeHeader(tx_data)
if err != nil { if err != nil {
logger.Printf("fError deserialiing tx, block id %x len(data) %d data %x\n", hash[:], len(tx_data), tx_data)
logger.Printf("fError deserialiing tx, block id %s len(data) %d data %x\n", hash[:], len(tx_data), tx_data)
return nil, err return nil, err
} }
return &tx, nil return &tx, nil
} }
func (chain *Blockchain) Load_TX_FROM_OO(Offset uint64) {
}
func (chain *Blockchain) Load_BL_FROM_ID(hash [32]byte) (*Block, error) {
var bl Block
func (chain *Blockchain) Load_BL_FROM_ID(hash [32]byte) (*block.Block, error) {
var bl block.Block
block_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_BLOB) block_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_BLOB)
if err != nil { if err != nil {
@ -314,7 +351,7 @@ func (chain *Blockchain) Load_BL_FROM_ID(hash [32]byte) (*Block, error) {
err = bl.Deserialize(block_data) err = bl.Deserialize(block_data)
if err != nil { if err != nil {
logger.Warnf("fError deserialiing block, block id %x len(data) %d data %x\n", hash[:], len(block_data), block_data)
logger.Warnf("fError deserialiing block, block id %s len(data) %d data %x\n", hash[:], len(block_data), block_data)
return nil, err return nil, err
} }
return &bl, nil return &bl, nil
@ -348,10 +385,15 @@ func (chain *Blockchain) Store_BL_ID_at_Height(Height uint64, hash crypto.Hash)
} }
func (chain *Blockchain) Load_Height_for_BL_ID(hash crypto.Hash) (Height uint64) { func (chain *Blockchain) Load_Height_for_BL_ID(hash crypto.Hash) (Height uint64) {
if hash == ZERO_HASH { // handle special case for genesis
return 0
}
object_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_HEIGHT) object_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_HEIGHT)
if err != nil { if err != nil {
logger.Warnf("Error while querying height for block %x\n", hash)
logger.Warnf("Error while querying height for block %s\n", hash)
return return
} }
@ -372,10 +414,9 @@ func (chain *Blockchain) Load_Height_for_BL_ID(hash crypto.Hash) (Height uint64)
func (chain *Blockchain) Load_Block_Timestamp(hash crypto.Hash) uint64 { func (chain *Blockchain) Load_Block_Timestamp(hash crypto.Hash) uint64 {
timestamp, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_TIMESTAMP) timestamp, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_TIMESTAMP)
if err != nil { if err != nil {
logger.Fatalf("Error while querying timestamp for block %x\n", hash)
panic("Error while querying timestamp for block")
logger.Warnf("Error while querying timestamp for block %s\n", hash)
} }
return timestamp return timestamp
@ -385,20 +426,52 @@ func (chain *Blockchain) Load_Block_Cumulative_Difficulty(hash crypto.Hash) uint
cdifficulty, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_CUMULATIVE_DIFFICULTY) cdifficulty, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_CUMULATIVE_DIFFICULTY)
if err != nil { if err != nil {
logger.Panicf("Error while querying cumulative difficulty for block %x\n", hash)
logger.Panicf("Error while querying cumulative difficulty for block %s\n", hash)
} }
return cdifficulty return cdifficulty
} }
func (chain *Blockchain) Load_Block_Reward(hash crypto.Hash) uint64 {
timestamp, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_BASEREWARD)
if err != nil {
logger.Warnf("Error while querying base_reward for block %s\n", hash)
}
return timestamp
}
func (chain *Blockchain) Load_Already_Generated_Coins_for_BL_ID(hash crypto.Hash) uint64 {
if hash == ZERO_HASH {
return 0
}
timestamp, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_ALREADY_GENERATED_COINS)
if err != nil {
logger.Warnf("Error while querying alreadt generated coins for block %s\n", hash)
}
return timestamp
}
func (chain *Blockchain) Load_Block_Size(hash crypto.Hash) uint64 {
timestamp, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_SIZE)
if err != nil {
logger.Warnf("Error while querying size for block %s\n", hash)
}
return timestamp
}
func (chain *Blockchain) Load_Block_Parent_ID(hash crypto.Hash) crypto.Hash { func (chain *Blockchain) Load_Block_Parent_ID(hash crypto.Hash) crypto.Hash {
var parent_id crypto.Hash var parent_id crypto.Hash
object_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_PARENT) object_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, hash[:], PLANET_PARENT)
if err != nil || len(object_data) != 32 { if err != nil || len(object_data) != 32 {
logger.Panicf("Error while querying parent id for block %x\n", hash)
}
logger.Warnf("Error while querying parent id for block %s\n", hash)
}
copy(parent_id[:], object_data) copy(parent_id[:], object_data)
return parent_id return parent_id
@ -409,6 +482,7 @@ func (chain *Blockchain) Store_TOP_ID(hash crypto.Hash) {
chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, TOP_ID, TOP_ID, TOP_ID, hash[:]) chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, TOP_ID, TOP_ID, TOP_ID, hash[:])
} }
// crash if something is not correct
func (chain *Blockchain) Load_TOP_ID() (hash crypto.Hash) { func (chain *Blockchain) Load_TOP_ID() (hash crypto.Hash) {
object_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, TOP_ID, TOP_ID, TOP_ID) object_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, TOP_ID, TOP_ID, TOP_ID)
@ -434,22 +508,60 @@ func itob(v uint64) []byte {
return b return b
} }
// get the position from where indexing must start for this block // get the position from where indexing must start for this block
// indexing mean vout based index // indexing mean vout based index
// cryptonote works by giving each vout a unique index // cryptonote works by giving each vout a unique index
func (chain *Blockchain)Get_Block_Output_Index(block_id crypto.Hash) uint64 {
if block_id == globals.Config.Genesis_Block_Hash { // genesis block has no output index
return 0 ; // counting starts from zero
func (chain *Blockchain) Get_Block_Output_Index(block_id crypto.Hash) uint64 {
if block_id == globals.Config.Genesis_Block_Hash { // genesis block has no output index
return 0 // counting starts from zero
} }
index, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, block_id[:], PLANET_OUTPUT_INDEX)
if err != nil {
// TODO this panic must be enabled to catch some bugs
panic(fmt.Errorf("Cannot load output index for %x err %s", block_id, err))
return 0
}
return index
index, err := chain.store.LoadUint64(BLOCKCHAIN_UNIVERSE, GALAXY_BLOCK, block_id[:], PLANET_OUTPUT_INDEX)
if err != nil {
// TODO this panic must be enabled to catch some bugs
logger.Warnf("Cannot load output index for %s err %s", block_id, err)
return 0
}
return index
}
// store key image to its own galaxy
// a keyimage stored with value 1 == it has been consumed
// a keyimage stored with value 0 == it has not been consumed
// a key image not found in store == it has NOT been consumed
func (chain *Blockchain) Store_KeyImage(hash crypto.Hash, mark bool) {
store_value := byte(0)
if mark {
store_value = byte(1)
}
chain.store.StoreObject(BLOCKCHAIN_UNIVERSE, GALAXY_KEYIMAGE, GALAXY_KEYIMAGE, hash[:], []byte{store_value})
}
// read a key image, whether it's stored with value 1
// a keyimage stored with value 1 == it has been consumed
// a keyimage stored with value 0 == it has not been consumed
// a key image not found in store == it has NOT been consumed
func (chain *Blockchain) Read_KeyImage_Status(hash crypto.Hash) bool {
object_data, err := chain.store.LoadObject(BLOCKCHAIN_UNIVERSE, GALAXY_KEYIMAGE, GALAXY_KEYIMAGE, hash[:])
if err != nil {
return false
}
if len(object_data) == 0 {
return false
}
if len(object_data) != 1 {
panic(fmt.Errorf("probably Database corruption, Wrong data stored in keyimage, expected size 1, actual size %d", len(object_data)))
}
if object_data[0] == 1 {
return true
}
// anything other than value 1 is considered wrong keyimage
return false
} }

+ 0
- 83
blockchain/transaction_ringct_test.go
File diff suppressed because it is too large
View File


+ 299
- 0
blockchain/transaction_verify.go

@ -0,0 +1,299 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain
//import "fmt"
//import "time"
/*import "bytes"
import "encoding/binary"
import "github.com/romana/rlog"
*/
//import "github.com/romana/rlog"
import "runtime/debug"
import log "github.com/sirupsen/logrus"
import "github.com/deroproject/derosuite/block"
import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/crypto/ringct"
import "github.com/deroproject/derosuite/transaction"
import "github.com/deroproject/derosuite/emission"
/* This function verifies tx fully, means all checks,
* if the transaction has passed the check it can be added to mempool, relayed or added to blockchain
* the transaction has already been deserialized thats it
* */
func (chain *Blockchain) Verify_Transaction(tx *transaction.Transaction) (result bool) {
return false
}
/* Coinbase transactions need to verify the amount of coins
* */
func (chain *Blockchain) Verify_Transaction_Coinbase(cbl *block.Complete_Block, minertx *transaction.Transaction) (result bool) {
if !minertx.IsCoinbase() { // transaction is not coinbase, return failed
return false
}
// coinbase transactions only have 1 vin, 1 vout
if len(minertx.Vin) != 1 {
return false
}
if len(minertx.Vout) != 1 {
return false
}
// check whether the height mentioned in tx.Vin is equal to block height
// this does NOT hold for genesis block so test it differently
expected_height := chain.Load_Height_for_BL_ID(cbl.Bl.Prev_Hash)
expected_height++
if cbl.Bl.GetHash() == globals.Config.Genesis_Block_Hash {
expected_height = 0
}
if minertx.Vin[0].(transaction.Txin_gen).Height != expected_height {
logger.Warnf(" Rejected Height %d should be %d", minertx.Vin[0].(transaction.Txin_gen).Height, chain.Load_Height_for_BL_ID(cbl.Bl.Prev_Hash))
return false
}
// verify coins amount ( minied amount ) + the fees colllected which is sum of all tx included in this block
// and whether it has been calculated correctly
total_fees := uint64(0)
for i := 0; i < len(cbl.Txs); i++ {
total_fees += cbl.Txs[i].RctSignature.Get_TX_Fee()
}
total_reward := minertx.Vout[0].Amount
base_reward := total_reward - total_fees
// size of block = size of miner_tx + size of all non coinbase tx
sizeofblock := uint64(0)
sizeofblock += uint64(len(cbl.Bl.Miner_tx.Serialize()))
// logger.Infof("size of block %d sizeof miner tx %d", sizeofblock, len(cbl.Bl.Miner_tx.Serialize()))
for i := 0; i < len(cbl.Txs); i++ {
sizeofblock += uint64(len(cbl.Txs[i].Serialize()))
// logger.Infof("size of tx i %d tx size %d total size %d", i, uint64(len(cbl.Txs[i].Serialize())) ,sizeofblock)
}
median_block_size := chain.Get_Median_BlockSize_At_Block(cbl.Bl.Prev_Hash)
already_generated_coins := chain.Load_Already_Generated_Coins_for_BL_ID(cbl.Bl.Prev_Hash)
base_reward_calculated := emission.GetBlockReward(median_block_size, sizeofblock, already_generated_coins, 6, 0)
if base_reward != base_reward_calculated {
logger.Warnf("Base reward %d should be %d", base_reward, base_reward_calculated)
logger.Warnf("median_block_size %d block_size %d already already_generated_coins %d", median_block_size, sizeofblock,
already_generated_coins)
return false
}
/*
for i := sizeofblock-4000; i < (sizeofblock+4000);i++{
// now we need to verify whether base reward is okay
//base_reward_calculated := emission.GetBlockReward(median_block_size,sizeofblock,already_generated_coins,6,0)
base_reward_calculated := emission.GetBlockReward(median_block_size,i,already_generated_coins,6,0)
if base_reward == base_reward_calculated {
logger.Warnf("Base reward %d should be %d size %d", base_reward, base_reward_calculated,i)
}
}
*/
return true
}
// all non miner tx must be non-coinbase tx
// each check is placed in a separate block of code, to avoid ambigous code or faulty checks
// all check are placed and not within individual functions ( so as we cannot skip a check )
func (chain *Blockchain) Verify_Transaction_NonCoinbase(tx *transaction.Transaction) (result bool) {
result = false
var tx_hash crypto.Hash
defer func() { // safety so if anything wrong happens, verification fails
if r := recover(); r != nil {
logger.WithFields(log.Fields{"txid": tx_hash}).Warnf("Recovered while Verifying transaction, failed verification, Stack trace below")
logger.Warnf("Stack trace \n%s", debug.Stack())
result = false
}
}()
tx_hash = tx.GetHash()
if tx.Version != 2 {
return false
}
// make sure atleast 1 vin and 1 vout are there
if len(tx.Vin) < 1 || len(tx.Vout) < 1 {
logger.WithFields(log.Fields{"txid": tx_hash}).Warnf("Incoming TX does NOT have atleast 1 vin and 1 vout")
return false
}
// this means some other checks have failed somewhere else
if tx.IsCoinbase() { // transaction coinbase must never come here
logger.WithFields(log.Fields{"txid": tx_hash}).Warnf("Coinbase tx in non coinbase path, Please investigate")
return false
}
// Vin can be only specific type rest all make the fail case
for i := 0; i < len(tx.Vin); i++ {
switch tx.Vin[i].(type) {
case transaction.Txin_gen:
return false // this is for coinbase so fail it
case transaction.Txin_to_key: // pass
default:
return false
}
}
// Vout can be only specific type rest all make th fail case
for i := 0; i < len(tx.Vout); i++ {
switch tx.Vout[i].Target.(type) {
case transaction.Txout_to_key: // pass
default:
return false
}
}
// Vout should have amount 0
for i := 0; i < len(tx.Vout); i++ {
if tx.Vout[i].Amount != 0 {
logger.WithFields(log.Fields{"txid": tx_hash, "Amount": tx.Vout[i].Amount}).Warnf("Amount must be zero in ringCT world")
return false
}
}
// just some extra logs for testing purposes
if len(tx.Vin) >= 3 {
logger.WithFields(log.Fields{"txid": tx_hash}).Warnf("tx has more than 3 inputs")
}
if len(tx.Vout) >= 3 {
logger.WithFields(log.Fields{"txid": tx_hash}).Warnf("tx has more than 3 outputs")
}
// check the mixin , it should be atleast 4 and should be same through out the tx ( all other inputs)
// someone did send a mixin of 3 in 12006 block height
mixin := len(tx.Vin[0].(transaction.Txin_to_key).Key_offsets)
if mixin < 3 {
logger.WithFields(log.Fields{"txid": tx_hash, "Mixin": mixin}).Warnf("Mixin must be atleast 3 in ringCT world")
return false
}
for i := 0; i < len(tx.Vin); i++ {
if mixin != len(tx.Vin[i].(transaction.Txin_to_key).Key_offsets) {
logger.WithFields(log.Fields{"txid": tx_hash, "Mixin": mixin}).Warnf("Mixin must be same for entire TX in ringCT world")
return false
}
}
// duplicate ringmembers are not allowed, check them here
// just in case protect ourselves as much as we can
for i := 0; i < len(tx.Vin); i++ {
ring_members := map[uint64]bool{} // create a separate map for each input
ring_member := uint64(0)
for j := 0; j < len(tx.Vin[i].(transaction.Txin_to_key).Key_offsets); j++ {
ring_member += tx.Vin[i].(transaction.Txin_to_key).Key_offsets[j]
if _, ok := ring_members[ring_member]; ok {
logger.WithFields(log.Fields{"txid": tx_hash, "input_index": i}).Warnf("Duplicate ring member within the TX")
return false
}
ring_members[ring_member] = true // add member to ring member
}
}
// check whether the key image is duplicate within the inputs
// NOTE: a block wide key_image duplication is done during block testing but we are still keeping it
{
kimages := map[crypto.Hash]bool{}
for i := 0; i < len(tx.Vin); i++ {
if _, ok := kimages[tx.Vin[i].(transaction.Txin_to_key).K_image]; ok {
logger.WithFields(log.Fields{
"txid": tx_hash,
"kimage": tx.Vin[i].(transaction.Txin_to_key).K_image,
}).Warnf("TX using duplicate inputs within the TX")
return false
}
kimages[tx.Vin[i].(transaction.Txin_to_key).K_image] = true // add element to map for next check
}
}
// check whether the key image is low order attack, if yes reject it right now
for i := 0; i < len(tx.Vin); i++ {
k_image := ringct.Key(tx.Vin[i].(transaction.Txin_to_key).K_image)
curve_order := ringct.CurveOrder()
mult_result := ringct.ScalarMultKey(&k_image, &curve_order)
if *mult_result != ringct.Identity {
logger.WithFields(log.Fields{
"txid": tx_hash,
"kimage": tx.Vin[i].(transaction.Txin_to_key).K_image,
"curve_order": curve_order,
"mult_result": *mult_result,
"identity": ringct.Identity,
}).Warnf("TX contains a low order key image attack, but we are already safeguarded")
return false
}
}
// a similiar block level check is done for double spending attacks within the block itself
// check whether the key image is already used or spent earlier ( in blockchain )
for i := 0; i < len(tx.Vin); i++ {
k_image := ringct.Key(tx.Vin[i].(transaction.Txin_to_key).K_image)
if chain.Read_KeyImage_Status(crypto.Hash(k_image)) {
logger.WithFields(log.Fields{
"txid": tx_hash,
"kimage": k_image,
}).Warnf("Key image is already spent, attempt to double spend ")
return false
}
}
// check whether the TX contains a signature or NOT
switch tx.RctSignature.Get_Sig_Type() {
case ringct.RCTTypeSimple, ringct.RCTTypeFull: // default case, pass through
default:
logger.WithFields(log.Fields{"txid": tx_hash}).Warnf("TX does NOT contain a ringct signature. It is NOT possible")
return false
}
// expand the signature first
// whether the inputs are mature and can be used at time is verified while expanding the inputs
if !chain.Expand_Transaction_v2(tx) {
logger.WithFields(log.Fields{"txid": tx_hash}).Warnf("TX inputs could not be expanded or inputs are NOT mature")
return false
}
// check the ring signature
if !tx.RctSignature.Verify() {
logger.WithFields(log.Fields{"txid": tx_hash}).Warnf("TX RCT Signature failed")
return false
}
logger.WithFields(log.Fields{"txid": tx_hash}).Debugf("TX successfully verified")
return true
}

+ 96
- 0
blockchain/tx_fees.go

@ -0,0 +1,96 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package blockchain
import "math/big"
import "github.com/deroproject/derosuite/config"
// this file implements the logic to calculate fees dynamicallly
// get mininum size of block
func Get_Block_Minimum_Size(version uint64) uint64 {
return config.CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE
}
// get maximum size of TX
func Get_Transaction_Maximum_Size() uint64 {
return config.CRYPTONOTE_MAX_TX_SIZE
}
// get per KB fees which is dependent of block reward and median_block_size
//
func (chain *Blockchain) Get_Dynamic_per_kb_fee(block_reward, median_block_size, version uint64) uint64 {
fee_per_kb_base := config.DYNAMIC_FEE_PER_KB_BASE_FEE_V5
min_block_size := Get_Block_Minimum_Size(version)
if median_block_size < min_block_size {
median_block_size = min_block_size
}
var unscaled_fee_per_kb big.Int
unscaled_fee_per_kb.SetUint64((fee_per_kb_base * min_block_size) / median_block_size)
unscaled_fee_per_kb.Mul(&unscaled_fee_per_kb, big.NewInt(int64(block_reward))) // block reward is always positive
unscaled_fee_per_kb.Div(&unscaled_fee_per_kb, big.NewInt(int64(config.DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD)))
if !unscaled_fee_per_kb.IsUint64() {
panic("Get_Dynamic_per_kb_fee has issues, Need to fix it urgently\n")
}
lo := unscaled_fee_per_kb.Uint64()
// we need to quantise it 8 decimal // make 4 lower digits 0
mask := uint64(10000)
qlo := (lo + mask - 1) / mask * mask
//logger.Infof("dynamic fee lo= %d qlo=%d", lo, qlo)
return qlo
}
// this will give the dynamic fee at any specfic height
func (chain *Blockchain) Get_Dynamic_Fee_Rate(height uint64) uint64 {
var base_reward, median_block_size uint64
// sanitize height
if height >= chain.Get_Height() {
height = chain.Load_Height_for_BL_ID(chain.Get_Top_ID())
}
block_id_at_height, _ := chain.Load_BL_ID_at_Height(height)
median_block_size = chain.Get_Median_BlockSize_At_Block(block_id_at_height)
base_reward = chain.Load_Block_Reward(block_id_at_height)
return chain.Get_Dynamic_per_kb_fee(base_reward, median_block_size, 0)
}
// get the tx fee
// this function assumes that dynamic fees has been calculated as per requirement
// for every part of 1KB multiply by dynamic_fee_per_kb
// the dynamic fee should be calculated on the basis of the current top
func (chain *Blockchain) Calculate_TX_fee(dynamic_fee_per_kb uint64, tx_size uint64) uint64 {
size_in_kb := tx_size / 1024
if (tx_size % 1024) != 0 { // for any part there of, use a full KB fee
size_in_kb += 1
}
needed_fee := size_in_kb * dynamic_fee_per_kb
return needed_fee
}

+ 13
- 61
build_all.sh

@ -1,9 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
package=$1
package="github.com/deroproject/derosuite/cmd/derod"
package_split=(${package//\// })
package_name=${package_split[-1]}
CURDIR=`/bin/pwd` CURDIR=`/bin/pwd`
@ -11,63 +7,19 @@ BASEDIR=$(dirname $0)
ABSPATH=$(readlink -f $0) ABSPATH=$(readlink -f $0)
ABSDIR=$(dirname $ABSPATH) ABSDIR=$(dirname $ABSPATH)
cd $ABSDIR/../../../../
GOPATH=`pwd`
cd $CURDIR
bash $ABSDIR/build_package.sh "github.com/deroproject/derosuite/cmd/derod"
bash $ABSDIR/build_package.sh "github.com/deroproject/derosuite/cmd/explorer"
bash $ABSDIR/build_package.sh "github.com/deroproject/derosuite/cmd/dero-wallet-cli"
cd "${ABSDIR}/build"
PLATFORMS="darwin/amd64" # amd64 only as of go1.5
PLATFORMS="$PLATFORMS windows/amd64 windows/386" # arm compilation not available for Windows
PLATFORMS="$PLATFORMS linux/amd64 linux/386"
#PLATFORMS="$PLATFORMS linux/ppc64le" is it common enough ??
#PLATFORMS="$PLATFORMS linux/mips64le" # experimental in go1.6 is it common enough ??
PLATFORMS="$PLATFORMS freebsd/amd64 freebsd/386"
PLATFORMS="$PLATFORMS netbsd/amd64" # amd64 only as of go1.6
PLATFORMS="$PLATFORMS openbsd/amd64" # amd64 only as of go1.6
PLATFORMS="$PLATFORMS dragonfly/amd64" # amd64 only as of go1.5
#PLATFORMS="$PLATFORMS plan9/amd64 plan9/386" # as of go1.4, is it common enough ??
PLATFORMS="$PLATFORMS solaris/amd64" # as of go1.3
#windows users require zip files
zip -r windows-amd64.zip windows_amd64
zip -r windows-x86.zip windows_386
#all other platforms are okay with tar.gz
find . -mindepth 1 -type d -not -name '*windows*' -exec tar --owner=dummy --group=dummy -cvzf {}.tar.gz {} \;
PLATFORMS_ARM="linux freebsd netbsd"
type setopt >/dev/null 2>&1
SCRIPT_NAME=`basename "$0"`
FAILURES=""
CURRENT_DIRECTORY=${PWD##*/}
OUTPUT="$package_name" # if no src file given, use current dir name
OUTPUT_DIR="$ABSDIR/build/"
for PLATFORM in $PLATFORMS; do
GOOS=${PLATFORM%/*}
GOARCH=${PLATFORM#*/}
BIN_FILENAME="${OUTPUT}-${GOOS}-${GOARCH}"
if [[ "${GOOS}" == "windows" ]]; then BIN_FILENAME="${BIN_FILENAME}.exe"; fi
CMD="GOOS=${GOOS} GOARCH=${GOARCH} go build -o $OUTPUT_DIR/${BIN_FILENAME} $package"
echo "${CMD}"
eval $CMD || FAILURES="${FAILURES} ${PLATFORM}"
done
# ARM64 builds only for linux
if [[ $PLATFORMS_ARM == *"linux"* ]]; then
CMD="GOOS=linux GOARCH=arm64 go build -o $OUTPUT_DIR/${OUTPUT}-linux-arm64 $package"
echo "${CMD}"
eval $CMD || FAILURES="${FAILURES} ${PLATFORM}"
fi
for GOOS in $PLATFORMS_ARM; do
GOARCH="arm"
# build for each ARM version
for GOARM in 7 6 5; do
BIN_FILENAME="${OUTPUT}-${GOOS}-${GOARCH}${GOARM}"
CMD="GOARM=${GOARM} GOOS=${GOOS} GOARCH=${GOARCH} go build -o $OUTPUT_DIR/${BIN_FILENAME} $package"
echo "${CMD}"
eval "${CMD}" || FAILURES="${FAILURES} ${GOOS}/${GOARCH}${GOARM}"
done
done
# eval errors
if [[ "${FAILURES}" != "" ]]; then
echo ""
echo "${SCRIPT_NAME} failed on: ${FAILURES}"
exit 1
fi
cd $CURDIR

+ 78
- 0
build_package.sh

@ -0,0 +1,78 @@
#!/usr/bin/env bash
package=$1
package_split=(${package//\// })
package_name=${package_split[-1]}
CURDIR=`/bin/pwd`
BASEDIR=$(dirname $0)
ABSPATH=$(readlink -f $0)
ABSDIR=$(dirname $ABSPATH)
PLATFORMS="darwin/amd64" # amd64 only as of go1.5
PLATFORMS="$PLATFORMS windows/amd64 windows/386" # arm compilation not available for Windows
PLATFORMS="$PLATFORMS linux/amd64 linux/386"
#PLATFORMS="$PLATFORMS linux/ppc64le" is it common enough ??
#PLATFORMS="$PLATFORMS linux/mips64le" # experimental in go1.6 is it common enough ??
PLATFORMS="$PLATFORMS freebsd/amd64 freebsd/386"
PLATFORMS="$PLATFORMS netbsd/amd64" # amd64 only as of go1.6
PLATFORMS="$PLATFORMS openbsd/amd64" # amd64 only as of go1.6
PLATFORMS="$PLATFORMS dragonfly/amd64" # amd64 only as of go1.5
#PLATFORMS="$PLATFORMS plan9/amd64 plan9/386" # as of go1.4, is it common enough ??
PLATFORMS="$PLATFORMS solaris/amd64" # as of go1.3
PLATFORMS_ARM="linux freebsd netbsd"
type setopt >/dev/null 2>&1
SCRIPT_NAME=`basename "$0"`
FAILURES=""
CURRENT_DIRECTORY=${PWD##*/}
OUTPUT="$package_name" # if no src file given, use current dir name
for PLATFORM in $PLATFORMS; do
GOOS=${PLATFORM%/*}
GOARCH=${PLATFORM#*/}
OUTPUT_DIR="${ABSDIR}/build/dero_${GOOS}_${GOARCH}"
BIN_FILENAME="${OUTPUT}-${GOOS}-${GOARCH}"
echo mkdir -p $OUTPUT_DIR
if [[ "${GOOS}" == "windows" ]]; then BIN_FILENAME="${BIN_FILENAME}.exe"; fi
CMD="GOOS=${GOOS} GOARCH=${GOARCH} go build -o $OUTPUT_DIR/${BIN_FILENAME} $package"
echo "${CMD}"
eval $CMD || FAILURES="${FAILURES} ${PLATFORM}"
done
# ARM64 builds only for linux
if [[ $PLATFORMS_ARM == *"linux"* ]]; then
GOOS="linux"
GOARCH="arm64"
OUTPUT_DIR="${ABSDIR}/build/dero_${GOOS}_${GOARCH}"
CMD="GOOS=linux GOARCH=arm64 go build -o $OUTPUT_DIR/${OUTPUT}-linux-arm64 $package"
echo "${CMD}"
eval $CMD || FAILURES="${FAILURES} ${PLATFORM}"
fi
for GOOS in $PLATFORMS_ARM; do
GOARCH="arm"
# build for each ARM version
for GOARM in 7 6 5; do
OUTPUT_DIR="${ABSDIR}/build/dero_${GOOS}_${GOARCH}${GOARM}"
BIN_FILENAME="${OUTPUT}-${GOOS}-${GOARCH}${GOARM}"
CMD="GOARM=${GOARM} GOOS=${GOOS} GOARCH=${GOARCH} go build -o $OUTPUT_DIR/${BIN_FILENAME} $package"
echo "${CMD}"
eval "${CMD}" || FAILURES="${FAILURES} ${GOOS}/${GOARCH}${GOARM}"
done
done
# eval errors
if [[ "${FAILURES}" != "" ]]; then
echo ""
echo "${SCRIPT_NAME} failed on: ${FAILURES}"
exit 1
fi

+ 106
- 0
checkpoints/checkpoints.go

@ -0,0 +1,106 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package checkpoints
// generate main net checkpoints automatically from file mainnet_checkpoints.dat
//go:generate sh -c "echo // Code generated by go generate DO NOT EDIT. > mainnet_checkpoints.go"
//go:generate sh -c "echo // This file contains all the mainnet checkpoints > mainnet_checkpoints.go"
//go:generate sh -c "echo // please read checkpoints.go comments > mainnet_checkpoints.go"
//go:generate sh -c "echo package checkpoints >> mainnet_checkpoints.go"
//go:generate sh -c "echo >> mainnet_checkpoints.go"
//go:generate sh -c "echo var mainnet_checkpoints = []byte{ >> mainnet_checkpoints.go"
//go:generate sh -c "xxd -i < mainnet_checkpoints.dat >> mainnet_checkpoints.go"
//go:generate sh -c "truncate -s-1 mainnet_checkpoints.go"
//go:generate sh -c "echo ,} >> mainnet_checkpoints.go"
//go:generate sh -c "echo // Code generated by go generate DO NOT EDIT. > testnet_checkpoints.go"
//go:generate sh -c "echo // This file contains all the testnet checkpoints > testnet_checkpoints.go"
//go:generate sh -c "echo // please read checkpoints.go comments > testnet_checkpoints.go"
//go:generate sh -c "echo package checkpoints >> testnet_checkpoints.go"
//go:generate sh -c "echo >> testnet_checkpoints.go"
// generate blank file if no checkpoints
//go:generate sh -c "if [ ! -s testnet_checkpoints.dat ]; then echo var testnet_checkpoints = []byte{} >> testnet_checkpoints.go; fi;"
//go:generate sh -c " if [ -s testnet_checkpoints.dat ]; then echo var testnet_checkpoints = []byte{ >> testnet_checkpoints.go; fi"
//go:generate sh -c "if [ -s testnet_checkpoints.dat ]; then xxd -i < testnet_checkpoints.dat >> testnet_checkpoints.go;fi"
//go:generate sh -c "if [ -s testnet_checkpoints.dat ]; then truncate -s-1 testnet_checkpoints.go; fi"
//go:generate sh -c "if [ -s testnet_checkpoints.dat ]; then echo ,} >> testnet_checkpoints.go;fi "
import "fmt"
import "github.com/romana/rlog"
import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/globals"
// this file handles and maintains checkpoints which are used by blockchain to skip some checks on known parts of the chain
// the skipping of the checks can be disabled by command line arguments
var mainnet_checkpoints_height uint64 = uint64(len(mainnet_checkpoints) / 32) // each checkpoint is 32 bytes in size
var testnet_checkpoints_height uint64 = uint64(len(testnet_checkpoints) / 32) // each checkpoint is 32 bytes in size
func init() {
rlog.Tracef(1, "Loaded %d checkpoints for mainnet hardcoded", mainnet_checkpoints_height)
rlog.Tracef(1, "Loaded %d checkpoints for testnet hardcoded", testnet_checkpoints_height)
}
// gives length of currently available checkpoints
func Length() uint64 {
switch globals.Config.Name {
case "mainnet":
return mainnet_checkpoints_height
case "testnet":
return testnet_checkpoints_height
default:
return 0
}
// we can never reach here
//return 0
}
// tell whether a checkpoint is known in the current selected network
func IsCheckPointKnown(hash crypto.Hash, height uint64) (result bool) {
var known_hash crypto.Hash
switch globals.Config.Name {
case "mainnet":
if height < mainnet_checkpoints_height {
copy(known_hash[:], mainnet_checkpoints[32*height:])
if known_hash == hash {
result = true
return
}
}
case "testnet":
if height < testnet_checkpoints_height {
copy(known_hash[:], testnet_checkpoints[32*height:])
if known_hash == hash {
result = true
return
}
}
default:
panic(fmt.Sprintf("Unknown Network \"%s\"", globals.Config.Name))
}
return
}

+ 13
- 0
checkpoints/dummy_test.go

@ -0,0 +1,13 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
package checkpoints
import "testing"
// Needs to expand test to cover failure conditions
func Test_Part1(t *testing.T) {
}

BIN
checkpoints/mainnet_checkpoints.dat


+ 84756
- 0
checkpoints/mainnet_checkpoints.go
File diff suppressed because it is too large
View File


+ 0
- 0
checkpoints/testnet_checkpoints.dat


+ 4
- 0
checkpoints/testnet_checkpoints.go

@ -0,0 +1,4 @@
// please read checkpoints.go comments
package checkpoints
var testnet_checkpoints = []byte{}

+ 90
- 0
cmd/dero-wallet-cli/LICENSE

@ -0,0 +1,90 @@
RESEARCH LICENSE
Version 1.1.2
I. DEFINITIONS.
"Licensee " means You and any other party that has entered into and has in effect a version of this License.
“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees.
"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology.
"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage.
"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License.
"Technology Site" means the website designated by Licensor for accessing the Technology.
"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License.
II. PURPOSE.
Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology.
COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT <url>.
III. RESEARCH USE RIGHTS.
A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only:
1. reproduce, create Modifications of, and use the Technology alone, or with Modifications;
2. share source code of the Technology alone, or with Modifications, with other Licensees;
3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and
4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology.
B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights.
C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License.
D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution.
IV. INTELLECTUAL PROPERTY REQUIREMENTS
As a condition to Your License, You agree to comply with the following restrictions and responsibilities:
A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology.
B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License.
V. GENERAL TERMS.
A. Disclaimer Of Warranties.
TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE.
B. Infringement; Limitation Of Liability.
1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site.
2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY.
C. Termination.
1. You may terminate this License at any time by notifying Licensor in writing.
2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance.
3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination.
D. Miscellaneous.
1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor.
2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof.
3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate.
4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter.
5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications.
READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING.
BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS.
IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM.

+ 167
- 0
cmd/dero-wallet-cli/daemon_communication.go

@ -0,0 +1,167 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package main
/* this file handles communication with the daemon
* this includes receiving output information
* *
*/
import "io"
import "fmt"
import "net"
import "time"
import "sync"
import "net/http"
import "compress/gzip"
//import "github.com/romana/rlog"
//import "github.com/pierrec/lz4"
import "github.com/ybbus/jsonrpc"
import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/blockchain/rpcserver"
var Wallet_Height uint64 // height of wallet
var Daemon_Height uint64 // height of daemon
var Connected bool = true
var rpcClient *jsonrpc.RPCClient
var netClient *http.Client
var endpoint string
var output_lock sync.Mutex
// this is as simple as it gets
// single threaded communication to get the daemon status and height
func Run_Communication_Engine() {
// check if user specified daemon address explicitly
if globals.Arguments["--daemon-address"] != nil {
daemon_address := globals.Arguments["--daemon-address"].(string)
remote_end, err := net.ResolveTCPAddr("tcp", daemon_address)
if err != nil {
globals.Logger.Warnf("Daemon address \"%s\" is invalid. parse err %s", daemon_address, err)
} else {
fmt.Printf("%+v\n", remote_end.IP)
if remote_end.IP == nil || remote_end.IP.IsUnspecified() { // user never provided an ipaddress, use loopback
globals.Logger.Debugf("Setting loopback ip on daemon endpoint")
remote_end.IP = net.IPv4(127, 0, 0, 1)
}
endpoint = remote_end.String()
}
}
// if user provided endpoint has error, use default
if endpoint == "" {
endpoint = "127.0.0.1:9999"
if !globals.IsMainnet() {
endpoint = "127.0.0.1:28091"
}
}
globals.Logger.Debugf("Daemon endpoint %s", endpoint)
// TODO enable socks support here
var netTransport = &http.Transport{
Dial: (&net.Dialer{
Timeout: 5 * time.Second, // 5 second timeout
}).Dial,
TLSHandshakeTimeout: 5 * time.Second,
}
netClient = &http.Client{
Timeout: time.Second * 10,
Transport: netTransport,
}
// create client
rpcClient = jsonrpc.NewRPCClient("http://" + endpoint + "/json_rpc")
for {
time.Sleep(1 * time.Second) // ping server every second
// execute rpc to service
response, err := rpcClient.Call("get_info")
// notify user of any state change
// if daemon connection breaks or comes live again
if err == nil {
if !Connected {
globals.Logger.Infof("Connection to RPC server successful")
Connected = true
}
} else {
if Connected {
globals.Logger.Warnf("Connection to RPC server Failed err %s", err)
Connected = false
}
continue // try next time
}
var info rpcserver.GetInfo_Result
err = response.GetObject(&info)
if err != nil {
globals.Logger.Warnf("Daemon getinfo RPC parsing error err: %s\n", err)
continue
}
// detect whether both are in different modes
// daemon is in testnet and wallet in mainnet or
// daemon
if info.Testnet != !globals.IsMainnet() {
globals.Logger.Warnf("Mainnet/TestNet is different between wallet/daemon.Please run daemon/wallet without --testnet")
}
Daemon_Height = info.Height
}
}
// get the outputs from the daemon, requesting specfic outputs
// the range can be anything
// if stop is zero,
// the daemon will flush out everything it has ASAP
// the stream can be saved and used later on
func Get_Outputs(start uint64, stop uint64) {
output_lock.Lock()
defer output_lock.Unlock()
if Connected { // only execute query if we are connected
response, err := http.Get(fmt.Sprintf("http://%s/getoutputs.bin?start=%d", endpoint, start))
if err != nil {
globals.Logger.Warnf("Error while requesting outputs from daemon err %s", err)
// os.Exit(1)
} else {
defer response.Body.Close()
// lz4reader := lz4.NewReader(response.Body)
// io.Copy(pipe_writer, lz4reader)
gzipreader, err := gzip.NewReader(response.Body)
if err != nil {
globals.Logger.Warnf("Error while decompressing output from daemon err: %s ", err)
return
}
defer gzipreader.Close()
io.Copy(pipe_writer, gzipreader)
}
// contents, err := ioutil.ReadAll(response.Body)
}
}

+ 13
- 0
cmd/dero-wallet-cli/dummy_test.go

@ -0,0 +1,13 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
package main
import "testing"
// Needs to expand test to cover failure conditions
func Test_Part1(t *testing.T) {
}

+ 107
- 0
cmd/dero-wallet-cli/easymenu_post_open.go

@ -0,0 +1,107 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package main
import "io"
import "fmt"
import "strings"
import "github.com/chzyer/readline"
import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/walletapi"
// handle menu if a wallet is currently opened
func display_easymenu_post_open_command(l *readline.Instance) {
w := l.Stderr()
io.WriteString(w, "Menu:\n")
io.WriteString(w, "\t\033[1m1\033[0m\tDisplay account Address \n")
if !account.ViewOnly { // hide some commands, if view only wallet
io.WriteString(w, "\t\033[1m2\033[0m\tDisplay Seed "+color_red+"(Please save seed otherwise your wallet is LOST)\n\033[0m")
}
io.WriteString(w, "\t\033[1m3\033[0m\tDisplay Keys (hex)\n")
io.WriteString(w, "\t\033[1m4\033[0m\tDisplay Watch-able View only wallet key ( cannot spend any funds from this wallet) (hex)\n")
if !account.ViewOnly { // hide some commands, if view only wallet
io.WriteString(w, "\t\033[1m5\033[0m\tTransfer ( send DERO) To Another Wallet\n")
io.WriteString(w, "\t\033[1m6\033[0m\tTransfer ( send DERO) To Exchange (payment id mandatory\n")
io.WriteString(w, "\t\033[1m7\033[0m\tCreate Transaction in offline mode\n")
}
io.WriteString(w, "\t\033[1m8\033[0m\tClose Wallet\n")
io.WriteString(w, "\n\t\033[1m9\033[0m\tExit menu and start prompt\n")
io.WriteString(w, "\t\033[1m0\033[0m\tExit Wallet\n")
}
// this handles all the commands if wallet in menu mode and a wallet is opened
func handle_easymenu_post_open_command(l *readline.Instance, line string) {
var err error
_ = err
line = strings.TrimSpace(line)
line_parts := strings.Fields(line)
if len(line_parts) < 1 { // if no command return
return
}
command := ""
if len(line_parts) >= 1 {
command = strings.ToLower(line_parts[0])
}
switch command {
case "1":
if account_valid {
fmt.Fprintf(l.Stderr(), "%s\n", account.GetAddress())
}
case "2": // give user his seed
if !account.ViewOnly {
display_seed(l)
}
case "3": // give user his keys in hex form
display_spend_key(l)
display_view_key(l)
case "4": // display user keys to create view only wallet
display_viewwallet_key(l)
case "5", "6", "7":
if !account.ViewOnly {
globals.Logger.Warnf("This command is NOT yet implemented")
}
case "8": // close and discard user key
account_valid = false
account = &walletapi.Account{} // overwrite previous instance
address = "" // empty the address
Wallet_Height = 0
case "9": // enable prompt mode
menu_mode = false
globals.Logger.Infof("Prompt mode enabled")
case "0", "bye", "exit", "quit":
globals.Exit_In_Progress = true
default: // just loop
}
}

+ 132
- 0
cmd/dero-wallet-cli/easymenu_pre_open.go

@ -0,0 +1,132 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package main
import "io"
import "strings"
import "github.com/chzyer/readline"
import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/walletapi"
// display menu before a wallet is opened
func display_easymenu_pre_open_command(l *readline.Instance) {
w := l.Stderr()
io.WriteString(w, "Menu:\n")
io.WriteString(w, "\t\033[1m1\033[0m\tCreate New Wallet\n")
io.WriteString(w, "\t\033[1m2\033[0m\tRecover Wallet using recovery seed (25 words)\n")
io.WriteString(w, "\t\033[1m3\033[0m\tRecover Wallet using recovery key (64 char private spend key hex)\n")
io.WriteString(w, "\t\033[1m4\033[0m\tCreate Watch-able Wallet (view only) using wallet view key\n")
io.WriteString(w, "\n\t\033[1m9\033[0m\tExit menu and start prompt\n")
io.WriteString(w, "\t\033[1m0\033[0m\tExit Wallet\n")
}
// handle all commands
func handle_easymenu_pre_open_command(l *readline.Instance, line string) {
var err error
line = strings.TrimSpace(line)
line_parts := strings.Fields(line)
if len(line_parts) < 1 { // if no command return
return
}
command := ""
if len(line_parts) >= 1 {
command = strings.ToLower(line_parts[0])
}
account_state := account_valid
switch command {
case "1": // create a new random account
if account_valid {
globals.Logger.Warnf("Account already exists. Cannot create new account")
break
}
account = Create_New_Account(l)
account_valid = true
globals.Logger.Debugf("Seed Language %s", account.SeedLanguage)
address = account.GetAddress().String()
display_seed(l)
if offline_mode {
go trigger_offline_data_scan()
}
case "2": // create wallet from recovery seed
if account_valid {
globals.Logger.Warnf("Account already exists. Cannot recover account")
break
}
seed := read_line_with_prompt(l, "Enter your seed (25 words) : ")
account, err = walletapi.Generate_Account_From_Recovery_Words(seed)
if err != nil {
globals.Logger.Warnf("Error while recovering seed err %s\n", err)
break
}
account_valid = true
globals.Logger.Debugf("Seed Language %s", account.SeedLanguage)
globals.Logger.Infof("Successfully recovered wallet from seed")
address = account.GetAddress().String()
if offline_mode {
go trigger_offline_data_scan()
}
case "3": // create wallet from hex seed
account = Create_New_Account_from_seed(l)
if account_valid {
globals.Logger.Infof("Successfully recovered wallet from hex seed")
display_seed(l)
address = account.GetAddress().String()
if offline_mode {
go trigger_offline_data_scan()
}
}
case "4": // create new view only wallet // TODO user providing wrong key is not being validated, do it ASAP
account = Create_New_Account_from_viewable_key(l)
if account_valid {
globals.Logger.Infof("Successfully created view only wallet from viewable keys")
address = account.GetAddress().String()
account_valid = true
if offline_mode {
go trigger_offline_data_scan()
}
}
case "9":
menu_mode = false
globals.Logger.Infof("Prompt mode enabled")
case "0", "bye", "exit", "quit":
globals.Exit_In_Progress = true
default: // just loop
}
_ = account_state
// NOTE: if we are in online mode, it is handled automatically
// user opened or created a new account
// rescan blockchain in offline mode
//if account_state == false && account_valid && offline_mode {
// go trigger_offline_data_scan()
//}
}

BIN
cmd/dero-wallet-cli/getoutputs.bin


+ 502
- 0
cmd/dero-wallet-cli/main.go

@ -0,0 +1,502 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package main
/// this file implements the wallet and rpc wallet
import "io"
import "os"
import "fmt"
import "time"
import "sync"
import "strings"
import "strconv"
import "runtime"
//import "io/ioutil"
//import "bufio"
//import "bytes"
//import "net/http"
import "encoding/hex"
import "github.com/romana/rlog"
import "github.com/chzyer/readline"
import "github.com/docopt/docopt-go"
import log "github.com/sirupsen/logrus"
import "github.com/vmihailenco/msgpack"
//import "github.com/deroproject/derosuite/address"
import "github.com/deroproject/derosuite/walletapi"
import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/walletapi/mnemonics"
var command_line string = `dero-wallet-cli
DERO : A secure, private blockchain with smart-contracts
Usage:
derod [--help] [--version] [--offline] [--offline_datafile=<file>] [--testnet] [--prompt] [--debug] [--daemon-address=<host:port>] [--restore-deterministic-wallet] [--electrum-seed=<recovery-seed>] [--socks-proxy=<socks_ip:port>]
derod -h | --help
derod --version
Options:
-h --help Show this screen.
--version Show version.
--offline Run the wallet in completely offline mode
--offline_datafile=<file> Use the data in offline mode default ("getoutputs.bin") in current dir
--prompt Disable menu and display prompt
--testnet Run in testnet mode.
--debug Debug mode enabled, print log messages
--restore-deterministic-wallet Restore wallet from previously saved recovery seed
--electrum-seed=<recovery-seed> Seed to use while restoring wallet
--password Password to unlock the wallet
--socks-proxy=<socks_ip:port> Use a proxy to connect to Daemon.
--daemon-address=<host:port> Use daemon instance at <host>:<port>
`
var menu_mode bool = true // default display menu mode
var account_valid bool = false // if an account has been opened, do not allow to create new account in this session
var offline_mode bool // whether we are in offline mode
var sync_in_progress int // whether sync is in progress with daemon
var account *walletapi.Account = &walletapi.Account{} // all account data is available here
var address string
var sync_time time.Time // used to suitable update prompt
var default_offline_datafile string = "getoutputs.bin"
// these pipes are used to feed in transaction data to recover valid amounts
var pipe_reader *io.PipeReader // any output will be read from this end point
var pipe_writer *io.PipeWriter // any data from daemon or file needs to written here
var color_black = "\033[30m"
var color_red = "\033[31m"
var color_green = "\033[32m"
var color_yellow = "\033[33m"
var color_blue = "\033[34m"
var color_magenta = "\033[35m"
var color_cyan = "\033[36m"
var color_white = "\033[37m"
var prompt_mutex sync.Mutex // prompt lock
var prompt string = "\033[92mDERO Wallet:\033[32m>>>\033[0m "
func main() {
var err error
globals.Arguments, err = docopt.Parse(command_line, nil, true, "DERO daemon : work in progress", false)
if err != nil {
log.Fatalf("Error while parsing options err: %s\n", err)
}
// We need to initialize readline first, so it changes stderr to ansi processor on windows
l, err := readline.NewEx(&readline.Config{
//Prompt: "\033[92mDERO:\033[32m»\033[0m",
Prompt: prompt,
HistoryFile: "", // wallet never saves any history file anywhere, to prevent any leakage
AutoComplete: completer,
InterruptPrompt: "^C",
EOFPrompt: "exit",
HistorySearchFold: true,
FuncFilterInputRune: filterInput,
})
if err != nil {
panic(err)
}
defer l.Close()
// parse arguments and setup testnet mainnet
globals.Initialize() // setup network and proxy
globals.Logger.Infof("") // a dummy write is required to fully activate logrus
// all screen output must go through the readline
globals.Logger.Out = l.Stdout()
globals.Logger.Debugf("Arguments %+v", globals.Arguments)
globals.Logger.Infof("DERO Wallet : This version is under heavy development, use it for testing/evaluations purpose only")
globals.Logger.Infof("Copyright 2017-2018 DERO Project. All rights reserved.")
globals.Logger.Infof("OS:%s ARCH:%s GOMAXPROCS:%d", runtime.GOOS, runtime.GOARCH, runtime.GOMAXPROCS(0))
globals.Logger.Infof("Wallet in %s mode", globals.Config.Name)
// disable menu mode if requested
if globals.Arguments["--prompt"].(bool) {
menu_mode = false
}
// lets handle the arguments one by one
if globals.Arguments["--restore-deterministic-wallet"].(bool) {
// user wants to recover wallet, check whether seed is provided on command line, if not prompt now
seed := ""
if globals.Arguments["--electrum-seed"] != nil {
seed = globals.Arguments["--electrum-seed"].(string)
} else { // prompt user for seed
seed = read_line_with_prompt(l, "Enter your seed (25 words) : ")
}
account, err = walletapi.Generate_Account_From_Recovery_Words(seed)
if err != nil {
globals.Logger.Warnf("Error while recovering seed err %s\n", err)
return
}
account_valid = true
globals.Logger.Debugf("Seed Language %s", account.SeedLanguage)
globals.Logger.Infof("Successfully recovered wallet from seed")
address = account.GetAddress().String()
}
// check if offline mode requested
if globals.Arguments["--offline"].(bool) == true {
offline_mode = true
} else { // we are not in offline mode, start communications with the daemon
go Run_Communication_Engine()
}
pipe_reader, pipe_writer = io.Pipe() // create pipes
setPasswordCfg := l.GenPasswordConfig()
setPasswordCfg.SetListener(func(line []rune, pos int, key rune) (newLine []rune, newPos int, ok bool) {
l.SetPrompt(fmt.Sprintf("Enter password(%v): ", len(line)))
l.Refresh()
return nil, 0, false
})
l.Refresh() // refresh the prompt
// reader ready to parse any data from the file
go blockchain_data_consumer()
// update prompt when required
go update_prompt(l)
// if wallet has been opened in offline mode by commands supplied at command prompt
// trigger the offline scan
if account_valid {
go trigger_offline_data_scan()
}
// start infinite loop processing user commands
for {
if globals.Exit_In_Progress { // exit if requested so
break
}
if menu_mode { // display menu if requested
if account_valid { // account is opened, display post menu
display_easymenu_post_open_command(l)
} else { // account has not been opened display pre open menu
display_easymenu_pre_open_command(l)
}
}
line, err := l.Readline()
if err == readline.ErrInterrupt {
if len(line) == 0 {
globals.Logger.Infof("Ctrl-C received, Exit in progress\n")
globals.Exit_In_Progress = true
break
} else {
continue
}
} else if err == io.EOF {
break
}
// pass command to suitable handler
if menu_mode {
if account_valid {
handle_easymenu_post_open_command(l, line)
} else {
handle_easymenu_pre_open_command(l, line)
}
} else {
handle_prompt_command(l, line)
}
}
globals.Exit_In_Progress = true
}
// this functions reads all data transferred from daemon or from offline file
// and plays it here
// finds which transactions belong to current account
// and adds them to account for reconciliation
func blockchain_data_consumer() {
var err error
for {
rlog.Tracef(1, "Discarding old pipe_reader,writer, creating new")
// close already created pipes, discarding there data
pipe_reader.Close()
pipe_writer.Close()
pipe_reader, pipe_writer = io.Pipe() // create pipes
decoder := msgpack.NewDecoder(pipe_reader)
for {
var output globals.TX_Output_Data
err = decoder.Decode(&output)
if err == io.EOF { // reached eof
break
}
if err != nil {
fmt.Printf("err while decoding msgpack stream err %s\n", err)
break
}
if globals.Exit_In_Progress {
return
}
sync_time = time.Now()
if account.Index_Global < output.Index_Global { // process tx if it has not been processed earlier
Wallet_Height = output.Height
account.Height = output.Height
if account.Is_Output_Ours(output.Tx_Public_Key, output.Index_within_tx, crypto.Key(output.InKey.Destination)) {
amount, _, result := account.Decode_RingCT_Output(output.Tx_Public_Key,
output.Index_within_tx,
crypto.Key(output.InKey.Mask),
output.ECDHTuple,
output.SigType)
if result == false {
globals.Logger.Warnf("Internal error occurred, amount cannot be spent")
}
globals.Logger.Infof(color_green+"Height %d transaction %s received %s DERO"+color_white, output.Height, output.TXID, globals.FormatMoney(amount))
// add tx to wallet
account.Add_Transaction_Record_Funds(&output)
}
// check this keyimage represents our funds
// if yes we have consumed that specific funds, mark them as such
amount_spent := uint64(0)
for i := range output.Key_Images {
amount_per_keyimage, result := account.Is_Our_Fund_Consumed(output.Key_Images[i])
if result {
amount_spent += amount_per_keyimage
account.Consume_Transaction_Record_Funds(&output, output.Key_Images[i]) // decrease fund from our wallet
}
}
if amount_spent > 0 {
globals.Logger.Infof(color_magenta+"Height %d transaction %s Spent %s DERO"+color_white, output.Height, output.TXID, globals.FormatMoney(amount_spent))
}
account.Index_Global = output.Index_Global
}
}
}
}
// update prompt as and when necessary
// TODO: make this code simple, with clear direction
func update_prompt(l *readline.Instance) {
last_wallet_height := uint64(0)
last_daemon_height := uint64(0)
for {
time.Sleep(30 * time.Millisecond) // give user a smooth running number
if globals.Exit_In_Progress {
return
}
prompt_mutex.Lock() // do not update if we can not lock the mutex
// show first 8 bytes of address
address_trim := ""
if len(address) > 8 {
address_trim = address[0:8]
} else {
address_trim = "DERO Wallet"
}
if len(address) == 0 {
last_wallet_height = 0
Wallet_Height = 0
}
if !account_valid {
l.SetPrompt(fmt.Sprintf("\033[1m\033[32m%s \033[0m"+color_green+"0/%d \033[32m>>>\033[0m ", address_trim, Daemon_Height))
prompt_mutex.Unlock()
continue
}
// only update prompt if needed, trigger resync if required
if last_wallet_height != Wallet_Height || last_daemon_height != Daemon_Height {
// choose color based on urgency
color := "\033[32m" // default is green color
if Wallet_Height < Daemon_Height {
color = "\033[33m" // make prompt yellow
}
balance_string := ""
if account_valid {
balance_unlocked, locked_balance := account.Get_Balance()
balance_string = fmt.Sprintf(color_green+"%s "+color_white+"| "+color_yellow+"%s", globals.FormatMoney(balance_unlocked), globals.FormatMoney(locked_balance))
}
l.SetPrompt(fmt.Sprintf("\033[1m\033[32m%s \033[0m"+color+"%d/%d %s\033[32m>>>\033[0m ", address_trim, Wallet_Height, Daemon_Height, balance_string))
l.Refresh()
last_wallet_height = Wallet_Height
last_daemon_height = Daemon_Height
}
if time.Since(sync_time) > (2*time.Second) && Wallet_Height < Daemon_Height {
if !offline_mode { // if offline mode, never connect anywhere
go Get_Outputs(account.Index_Global, 0) // start sync
}
sync_time = time.Now()
}
prompt_mutex.Unlock()
}
}
// create a new wallet from scratch from random numbers
func Create_New_Account(l *readline.Instance) *walletapi.Account {
account, _ := walletapi.Generate_Keys_From_Random()
account.SeedLanguage = choose_seed_language(l)
// a new account has been created, append the seed to user home directory
//usr, err := user.Current()
/*if err != nil {
globals.Logger.Warnf("Cannot get current username to save recovery key and password")
}else{ // we have a user, get his home dir
}*/
return account
}
// create a new wallet from hex seed provided
func Create_New_Account_from_seed(l *readline.Instance) *walletapi.Account {
var account *walletapi.Account
var seedkey crypto.Key
seed := read_line_with_prompt(l, "Please enter your seed ( hex 64 chars): ")
seed = strings.TrimSpace(seed) // trim any extra space
seed_raw, err := hex.DecodeString(seed) // hex decode
if len(seed) != 64 || err != nil { //sanity check
globals.Logger.Warnf("Seed must be 64 chars hexadecimal chars")
return account
}
copy(seedkey[:], seed_raw[:32]) // copy bytes to seed
account, _ = walletapi.Generate_Account_From_Seed(seedkey) // create a new account
account.SeedLanguage = choose_seed_language(l) // ask user his seed preference and set it
account_valid = true
return account
}
// create a new wallet from viewable seed provided
// viewable seed consists of public spend key and private view key
func Create_New_Account_from_viewable_key(l *readline.Instance) *walletapi.Account {
var seedkey crypto.Key
var privateview crypto.Key
var account *walletapi.Account
seed := read_line_with_prompt(l, "Please enter your View Only Key ( hex 128 chars): ")
seed = strings.TrimSpace(seed) // trim any extra space
seed_raw, err := hex.DecodeString(seed)
if len(seed) != 128 || err != nil {
globals.Logger.Warnf("View Only key must be 128 chars hexadecimal chars")
return account
}
copy(seedkey[:], seed_raw[:32])
copy(privateview[:], seed_raw[32:64])
account, _ = walletapi.Generate_Account_View_Only(seedkey, privateview)
account_valid = true
return account
}
// helper function to let user to choose a seed in specific lanaguage
func choose_seed_language(l *readline.Instance) string {
languages := mnemonics.Language_List()
fmt.Printf("Language list for seeds, please enter a number (default English)\n")
for i := range languages {
fmt.Fprintf(l.Stderr(), "\033[1m%2d:\033[0m %s\n", i, languages[i])
}
language_number := read_line_with_prompt(l, "Please enter a choice: ")
choice := 0 // 0 for english
if s, err := strconv.Atoi(language_number); err == nil {
choice = s
}
for i := range languages { // if user gave any wrong or ot of range choice, choose english
if choice == i {
return languages[choice]
}
}
// if no match , return Englisg
return "English"
}
// read a line from the prompt
func read_line_with_prompt(l *readline.Instance, prompt_temporary string) string {
prompt_mutex.Lock()
defer prompt_mutex.Unlock()
l.SetPrompt(prompt_temporary)
line, err := l.Readline()
if err == readline.ErrInterrupt {
if len(line) == 0 {
globals.Logger.Infof("Ctrl-C received, Exiting\n")
os.Exit(0)
}
} else if err == io.EOF {
os.Exit(0)
}
l.SetPrompt(prompt)
return line
}
// filter out specfic inputs from input processing
// currently we only skip CtrlZ background key
func filterInput(r rune) (rune, bool) {
switch r {
// block CtrlZ feature
case readline.CharCtrlZ:
return r, false
}
return r, true
}

+ 207
- 0
cmd/dero-wallet-cli/prompt.go

@ -0,0 +1,207 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package main
import "os"
import "io"
import "fmt"
import "bufio"
import "strings"
import "strconv"
import "compress/gzip"
import "github.com/chzyer/readline"
import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/walletapi"
// handle all commands while in prompt mode
func handle_prompt_command(l *readline.Instance, line string) {
var err error
line = strings.TrimSpace(line)
line_parts := strings.Fields(line)
if len(line_parts) < 1 { // if no command return
return
}
_ = err
command := ""
if len(line_parts) >= 1 {
command = strings.ToLower(line_parts[0])
}
switch command {
case "help":
usage(l.Stderr())
case "address": // give user his account address
if account_valid {
fmt.Fprintf(l.Stderr(), "%s\n", account.GetAddress())
}
case "rescan_bc": // rescan from 0
fallthrough
case "rescan_spent": // rescan from 0
if offline_mode {
go trigger_offline_data_scan()
} else {
globals.Logger.Warnf("This command is NOT yet implemented")
}
case "seed": // give user his seed
display_seed(l)
case "spendkey": // give user his spend key
display_spend_key(l)
case "viewkey": // give user his viewkey
display_view_key(l)
case "walletviewkey":
display_viewwallet_key(l)
case "set": // set different settings
case "close": // close the account
account_valid = false
tmp := &walletapi.Account{}
address = ""
account = tmp // overwrite previous instance
case "menu": // enable menu mode
menu_mode = true
globals.Logger.Infof("Menu mode enabled")
case "bye", "exit", "quit":
globals.Exit_In_Progress = true
case "": // blank enter key just loop
default:
fmt.Fprintf(l.Stderr(), "you said: %s", strconv.Quote(line))
}
}
// if we are in offline, scan default or user provided file
// this function will replay the blockchain data in offline mode
func trigger_offline_data_scan() {
filename := default_offline_datafile
if globals.Arguments["--offline_datafile"] != nil {
filename = globals.Arguments["--offline_datafile"].(string)
}
f, err := os.Open(filename)
if err != nil {
globals.Logger.Warnf("Cannot read offline data file=\"%s\" err: %s ", filename, err)
return
}
w := bufio.NewReader(f)
gzipreader, err := gzip.NewReader(w)
if err != nil {
globals.Logger.Warnf("Error while decompressing offline data file=\"%s\" err: %s ", filename, err)
return
}
defer gzipreader.Close()
io.Copy(pipe_writer, gzipreader)
}
// this completer is used to complete the commands at the prompt
// BUG, this needs to be disabled in menu mode
var completer = readline.NewPrefixCompleter(
readline.PcItem("help"),
readline.PcItem("address"),
readline.PcItem("rescan_bc"),
readline.PcItem("rescan_spent"),
readline.PcItem("print_height"),
readline.PcItem("seed"),
readline.PcItem("menu"),
readline.PcItem("set",
readline.PcItem("priority",
readline.PcItem("lowest x1"),
readline.PcItem("low x4"),
readline.PcItem("normal x8"),
readline.PcItem("high x13"),
readline.PcItem("veryhigh x20"),
),
readline.PcItem("default-ring-size"),
readline.PcItem("store-tx-info"),
readline.PcItem("ask-password"),
),
readline.PcItem("spendkey"),
readline.PcItem("viewkey"),
readline.PcItem("walletviewkey"),
readline.PcItem("bye"),
readline.PcItem("exit"),
readline.PcItem("quit"),
)
// help command screen
func usage(w io.Writer) {
io.WriteString(w, "commands:\n")
io.WriteString(w, "\t\033[1mhelp\033[0m\t\tthis help\n")
io.WriteString(w, "\t\033[1maddress\033[0m\t\tDisplay user address\n")
io.WriteString(w, "\t\033[1mmenu\033[0m\t\tEnable menu mode\n")
io.WriteString(w, "\t\033[1mrescan_bc\033[0m\tRescan blockchain again from 0 height\n")
io.WriteString(w, "\t\033[1mprint_block\033[0m\tPrint block, print_block <block_hash> or <block_height>\n")
io.WriteString(w, "\t\033[1mseed\033[0m\tDisplay seed\n")
io.WriteString(w, "\t\033[1mset\033[0m\tSet various settings\n")
io.WriteString(w, "\t\033[1mstatus\033[0m\t\tShow genereal information\n")
io.WriteString(w, "\t\033[1mspendkey\033[0m\tView secret key\n")
io.WriteString(w, "\t\033[1mviewkey\033[0m\tView view key\n")
io.WriteString(w, "\t\033[1mwalletviewkey\033[0m\tWallet view key, used to create watchable view only wallet\n")
io.WriteString(w, "\t\033[1mbye\033[0m\t\tQuit wallet\n")
io.WriteString(w, "\t\033[1mexit\033[0m\t\tQuit wallet\n")
io.WriteString(w, "\t\033[1mquit\033[0m\t\tQuit wallet\n")
}
// display seed to the user in his preferred language
func display_seed(l *readline.Instance) {
if account_valid {
seed := account.GetSeed()
fmt.Fprintf(l.Stderr(), color_green+"PLEASE NOTE: the following 25 words can be used to recover access to your wallet. Please write them down and store them somewhere safe and secure. Please do not store them in your email or on file storage services outside of your immediate control."+color_white+"\n")
fmt.Fprintf(os.Stderr, color_red+"%s"+color_white+"\n", seed)
}
}
// display spend key
// viewable wallet do not have spend secret key
// TODO wee need to give user a warning if we are printing secret
func display_spend_key(l *readline.Instance) {
if account_valid {
if !account.ViewOnly {
fmt.Fprintf(os.Stderr, "spend key secret : "+color_red+"%s"+color_white+"\n", account.Keys.Spendkey_Secret)
}
fmt.Fprintf(os.Stderr, "spend key public : %s\n", account.Keys.Spendkey_Public)
}
}
//display view key
func display_view_key(l *readline.Instance) {
if account_valid {
fmt.Fprintf(os.Stderr, "view key secret : "+color_yellow+"%s"+color_white+"\n", account.Keys.Viewkey_Secret)
fmt.Fprintf(os.Stderr, "view key public : %s\n", account.Keys.Viewkey_Public)
}
}
// display wallet view only Keys
// this will create a watchable view only mode
func display_viewwallet_key(l *readline.Instance) {
if account_valid {
io.WriteString(l.Stderr(), fmt.Sprintf("This Key can used to create a watch only wallet. This wallet can only see incoming funds but cannot spend them.\nThe key is below.\n%s\n\n", account.GetViewWalletKey()))
}
}

+ 90
- 0
cmd/derod/LICENSE

@ -0,0 +1,90 @@
RESEARCH LICENSE
Version 1.1.2
I. DEFINITIONS.
"Licensee " means You and any other party that has entered into and has in effect a version of this License.
“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees.
"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology.
"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage.
"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License.
"Technology Site" means the website designated by Licensor for accessing the Technology.
"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License.
II. PURPOSE.
Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology.
COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT <url>.
III. RESEARCH USE RIGHTS.
A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only:
1. reproduce, create Modifications of, and use the Technology alone, or with Modifications;
2. share source code of the Technology alone, or with Modifications, with other Licensees;
3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and
4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology.
B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights.
C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License.
D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution.
IV. INTELLECTUAL PROPERTY REQUIREMENTS
As a condition to Your License, You agree to comply with the following restrictions and responsibilities:
A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology.
B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License.
V. GENERAL TERMS.
A. Disclaimer Of Warranties.
TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE.
B. Infringement; Limitation Of Liability.
1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site.
2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY.
C. Termination.
1. You may terminate this License at any time by notifying Licensor in writing.
2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance.
3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination.
D. Miscellaneous.
1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor.
2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof.
3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate.
4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter.
5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications.
READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING.
BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS.
IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM.

+ 6
- 2
cmd/derod/dummy_test.go

@ -1,8 +1,12 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
package main package main
import "testing" import "testing"
func Test_Part1(t *testing.T) {
func Test_Part1(t *testing.T){
} }

+ 101
- 27
cmd/derod/main.go

@ -1,3 +1,19 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package main package main
import "io" import "io"
@ -5,8 +21,10 @@ import "os"
import "time" import "time"
import "fmt" import "fmt"
import "bytes" import "bytes"
import "bufio"
import "strings" import "strings"
import "strconv" import "strconv"
import "runtime"
import "encoding/hex" import "encoding/hex"
import "encoding/json" import "encoding/json"
import "path/filepath" import "path/filepath"
@ -18,15 +36,19 @@ import log "github.com/sirupsen/logrus"
import "github.com/deroproject/derosuite/p2p" import "github.com/deroproject/derosuite/p2p"
import "github.com/deroproject/derosuite/globals" import "github.com/deroproject/derosuite/globals"
import "github.com/deroproject/derosuite/blockchain" import "github.com/deroproject/derosuite/blockchain"
import "github.com/deroproject/derosuite/crypto"
//import "github.com/deroproject/derosuite/checkpoints"
import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/crypto/ringct"
import "github.com/deroproject/derosuite/blockchain/rpcserver"
//import "github.com/deroproject/derosuite/address"
var command_line string = `derod var command_line string = `derod
DERO : A secure, private blockchain with smart-contracts DERO : A secure, private blockchain with smart-contracts
Usage: Usage:
derod [--help] [--version] [--testnet] [--debug] [--socks-proxy=<socks_ip:port>] [--p2p-bind-port=<18090>] [--add-exclusive-node=<ip:port>]...
derod [--help] [--version] [--testnet] [--debug] [--disable-checkpoints] [--socks-proxy=<socks_ip:port>] [--p2p-bind-port=<18090>] [--add-exclusive-node=<ip:port>]...
derod -h | --help derod -h | --help
derod --version derod --version
@ -35,6 +57,7 @@ Options:
--version Show version. --version Show version.
--testnet Run in testnet mode. --testnet Run in testnet mode.
--debug Debug mode enabled, print log messages --debug Debug mode enabled, print log messages
--disable-checkpoints Disable checkpoints, work in truly async, slow mode 1 block at a time
--socks-proxy=<socks_ip:port> Use a proxy to connect to network. --socks-proxy=<socks_ip:port> Use a proxy to connect to network.
--p2p-bind-port=<18090> p2p server listens on this port. --p2p-bind-port=<18090> p2p server listens on this port.
--add-exclusive-node=<ip:port> Connect to this peer only (disabled for this version)` --add-exclusive-node=<ip:port> Connect to this peer only (disabled for this version)`
@ -76,18 +99,27 @@ func main() {
globals.Logger.Debugf("Arguments %+v", globals.Arguments) globals.Logger.Debugf("Arguments %+v", globals.Arguments)
globals.Logger.Infof("DERO daemon : This version is under heavy development, use it for testing/evaluations purpose only") globals.Logger.Infof("DERO daemon : This version is under heavy development, use it for testing/evaluations purpose only")
globals.Logger.Infof("Copyright 2017-2018 DERO Project. All rights reserved.")
globals.Logger.Infof("OS:%s ARCH:%s GOMAXPROCS:%d", runtime.GOOS, runtime.GOARCH, runtime.GOMAXPROCS(0))
globals.Logger.Infof("Daemon in %s mode", globals.Config.Name) globals.Logger.Infof("Daemon in %s mode", globals.Config.Name)
chain, _ := blockchain.Blockchain_Start(nil)
params := map[string]interface{}{} params := map[string]interface{}{}
params["--disable-checkpoints"] = globals.Arguments["--disable-checkpoints"].(bool)
chain, _ := blockchain.Blockchain_Start(params)
params["chain"] = chain params["chain"] = chain
p2p.P2P_Init(params) p2p.P2P_Init(params)
rpc, _ := rpcserver.RPCServer_Start(params)
// This tiny goroutine continuously updates status as required // This tiny goroutine continuously updates status as required
go func() { go func() {
last_our_height := uint64(0) last_our_height := uint64(0)
last_best_height := uint64(0) last_best_height := uint64(0)
last_peer_count := uint64(0) last_peer_count := uint64(0)
last_mempool_tx_count := 0
for { for {
if globals.Exit_In_Progress { if globals.Exit_In_Progress {
return return
@ -95,9 +127,10 @@ func main() {
our_height := chain.Get_Height() our_height := chain.Get_Height()
best_height := p2p.Best_Peer_Height() best_height := p2p.Best_Peer_Height()
peer_count := p2p.Peer_Count() peer_count := p2p.Peer_Count()
mempool_tx_count := len(chain.Mempool.Mempool_List_TX())
// only update prompt if needed // only update prompt if needed
if last_our_height != our_height || last_best_height != best_height || last_peer_count != peer_count {
if last_our_height != our_height || last_best_height != best_height || last_peer_count != peer_count || last_mempool_tx_count != mempool_tx_count {
// choose color based on urgency // choose color based on urgency
color := "\033[32m" // default is green color color := "\033[32m" // default is green color
if our_height < best_height { if our_height < best_height {
@ -112,11 +145,12 @@ func main() {
} else if peer_count <= 8 { } else if peer_count <= 8 {
pcolor = "\033[33m" // make prompt yellow pcolor = "\033[33m" // make prompt yellow
} }
l.SetPrompt(fmt.Sprintf("\033[1m\033[32mDERO: \033[0m"+color+"%d/%d "+pcolor+"P %d\033[32m>>>\033[0m ", our_height, best_height, peer_count))
l.SetPrompt(fmt.Sprintf("\033[1m\033[32mDERO: \033[0m"+color+"%d/%d "+pcolor+"P %d TXp %d\033[32m>>>\033[0m ", our_height, best_height, peer_count, mempool_tx_count))
l.Refresh() l.Refresh()
last_our_height = our_height last_our_height = our_height
last_best_height = best_height last_best_height = best_height
last_peer_count = peer_count last_peer_count = peer_count
last_mempool_tx_count = mempool_tx_count
} }
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
} }
@ -134,7 +168,6 @@ func main() {
line, err := l.Readline() line, err := l.Readline()
if err == readline.ErrInterrupt { if err == readline.ErrInterrupt {
if len(line) == 0 { if len(line) == 0 {
fmt.Print("Ctrl-C received, Exit in progress\n") fmt.Print("Ctrl-C received, Exit in progress\n")
globals.Exit_In_Progress = true globals.Exit_In_Progress = true
break break
@ -255,7 +288,7 @@ func main() {
fmt.Printf("height: %10d, timestamp: %10d, difficulty: %12d\n", i, timestamp, diff) fmt.Printf("height: %10d, timestamp: %10d, difficulty: %12d\n", i, timestamp, diff)
fmt.Printf("Block Id: %x , prev block id:%x\n", current_block_id, parent_block_id)
fmt.Printf("Block Id: %s , prev block id:%s\n", current_block_id, parent_block_id)
fmt.Printf("\n") fmt.Printf("\n")
} }
@ -271,11 +304,11 @@ func main() {
} }
var hash crypto.Hash var hash crypto.Hash
copy(hash[:32], []byte(txid)) copy(hash[:32], []byte(txid))
fmt.Printf("block id: %x\n", hash[:])
fmt.Printf("block id: %s\n", hash[:])
bl, err := chain.Load_BL_FROM_ID(hash) bl, err := chain.Load_BL_FROM_ID(hash)
if err == nil { if err == nil {
fmt.Printf("Block : %x\n", bl.Serialize())
fmt.Printf("Block : %s\n", bl.Serialize())
} else { } else {
fmt.Printf("Err %s\n", err) fmt.Printf("Err %s\n", err)
} }
@ -286,8 +319,8 @@ func main() {
if err == nil { if err == nil {
bl, err := chain.Load_BL_FROM_ID(hash) bl, err := chain.Load_BL_FROM_ID(hash)
if err == nil { if err == nil {
fmt.Printf("block id: %x\n", hash[:])
fmt.Printf("Block : %x\n", bl.Serialize())
fmt.Printf("block id: %s\n", hash[:])
fmt.Printf("Block : %s\n", bl.Serialize())
json_bytes, err := json.Marshal(bl) json_bytes, err := json.Marshal(bl)
@ -323,6 +356,10 @@ func main() {
_ = err _ = err
fmt.Printf("%s\n", string(json_bytes)) fmt.Printf("%s\n", string(json_bytes))
tx.RctSignature.Message = ringct.Key(tx.GetPrefixHash())
ringct.Get_pre_mlsag_hash(tx.RctSignature)
chain.Expand_Transaction_v2(tx)
} else { } else {
fmt.Printf("Err %s\n", err) fmt.Printf("Err %s\n", err)
} }
@ -330,13 +367,13 @@ func main() {
fmt.Printf("print_tx needs a single transaction id as arugument\n") fmt.Printf("print_tx needs a single transaction id as arugument\n")
} }
case strings.ToLower(line) == "diff": case strings.ToLower(line) == "diff":
fmt.Printf("Network %s BH %d, Diff %d, NW Hashrate %0.03f MH/sec TH %x\n", globals.Config.Name, chain.Get_Height(), chain.Get_Difficulty(), float64(chain.Get_Network_HashRate())/1000000.0, chain.Get_Top_ID())
fmt.Printf("Network %s BH %d, Diff %d, NW Hashrate %0.03f MH/sec TH %s\n", globals.Config.Name, chain.Get_Height(), chain.Get_Difficulty(), float64(chain.Get_Network_HashRate())/1000000.0, chain.Get_Top_ID())
case strings.ToLower(line) == "status": case strings.ToLower(line) == "status":
// fmt.Printf("chain diff %d\n",chain.Get_Difficulty_At_Block(chain.Top_ID)) // fmt.Printf("chain diff %d\n",chain.Get_Difficulty_At_Block(chain.Top_ID))
//fmt.Printf("chain nw rate %d\n", chain.Get_Network_HashRate()) //fmt.Printf("chain nw rate %d\n", chain.Get_Network_HashRate())
inc, out := p2p.Peer_Direction_Count()
fmt.Printf("Network %s Height %d NW Hashrate %0.03f MH/sec TH %x Peers %d INC, %d OUT\n", globals.Config.Name, chain.Get_Height(), float64(chain.Get_Network_HashRate())/1000000.0, chain.Get_Top_ID(), inc,out )
inc, out := p2p.Peer_Direction_Count()
fmt.Printf("Network %s Height %d NW Hashrate %0.03f MH/sec TH %s Peers %d inc, %d out MEMPOOL size %d\n", globals.Config.Name, chain.Get_Height(), float64(chain.Get_Network_HashRate())/1000000.0, chain.Get_Top_ID(), inc, out, len(chain.Mempool.Mempool_List_TX()))
case strings.ToLower(line) == "sync_info": case strings.ToLower(line) == "sync_info":
p2p.Connection_Print() p2p.Connection_Print()
case strings.ToLower(line) == "bye": case strings.ToLower(line) == "bye":
@ -345,6 +382,41 @@ func main() {
fallthrough fallthrough
case strings.ToLower(line) == "quit": case strings.ToLower(line) == "quit":
goto exit goto exit
case strings.ToLower(line) == "checkpoints": // save all knowns block id
var block_id crypto.Hash
name := "mainnet_checkpoints.dat"
if !globals.IsMainnet() {
name = "testnet_checkpoints.dat"
}
filename := filepath.Join(os.TempDir(), name)
// create output filen
f, err := os.Create(filename)
if err != nil {
globals.Logger.Warnf("error creating new file %s", err)
continue
}
w := bufio.NewWriter(f)
chain.Lock() // we do not want any reorgs during this op
height := chain.Get_Height()
for i := uint64(0); i < height; i++ {
block_id, err = chain.Load_BL_ID_at_Height(i)
if err != nil {
break
}
w.Write(block_id[:])
}
if err != nil {
globals.Logger.Warnf("error writing checkpoints err: %s", err)
} else {
globals.Logger.Infof("Successfully wrote %d checkpoints to file %s", height, filename)
}
w.Flush() // flush everything
f.Close()
chain.Unlock()
case line == "sleep": case line == "sleep":
log.Println("sleep 4 second") log.Println("sleep 4 second")
time.Sleep(4 * time.Second) time.Sleep(4 * time.Second)
@ -358,6 +430,8 @@ exit:
globals.Logger.Infof("Exit in Progress, Please wait") globals.Logger.Infof("Exit in Progress, Please wait")
time.Sleep(100 * time.Millisecond) // give prompt update time to finish time.Sleep(100 * time.Millisecond) // give prompt update time to finish
rpc.RPCServer_Stop()
p2p.P2P_Shutdown() // shutdown p2p subsystem p2p.P2P_Shutdown() // shutdown p2p subsystem
chain.Shutdown() // shutdown chain subsysem chain.Shutdown() // shutdown chain subsysem
@ -376,18 +450,18 @@ func prettyprint_json(b []byte) []byte {
func usage(w io.Writer) { func usage(w io.Writer) {
io.WriteString(w, "commands:\n") io.WriteString(w, "commands:\n")
//io.WriteString(w, completer.Tree(" ")) //io.WriteString(w, completer.Tree(" "))
io.WriteString(w,"\t\033[1mhelp\033[0m\t\tthis help\n")
io.WriteString(w,"\t\033[1mdiff\033[0m\t\tShow difficulty\n")
io.WriteString(w,"\t\033[1mprint_bc\033[0m\tPrint blockchain info in a given blocks range, print_bc <begin_height> <end_height>\n")
io.WriteString(w,"\t\033[1mprint_block\033[0m\tPrint block, print_block <block_hash> or <block_height>\n")
io.WriteString(w,"\t\033[1mprint_height\033[0m\tPrint local blockchain height\n")
io.WriteString(w,"\t\033[1mprint_tx\033[0m\tPrint transaction, print_tx <transaction_hash>\n")
io.WriteString(w,"\t\033[1mstatus\033[0m\t\tShow genereal information\n")
io.WriteString(w,"\t\033[1msync_info\033[0m\tPrint information about connected peers and their state\n")
io.WriteString(w,"\t\033[1mbye\033[0m\t\tQuit the daemon\n")
io.WriteString(w,"\t\033[1mexit\033[0m\t\tQuit the daemon\n")
io.WriteString(w,"\t\033[1mquit\033[0m\t\tQuit the daemon\n")
io.WriteString(w, "\t\033[1mhelp\033[0m\t\tthis help\n")
io.WriteString(w, "\t\033[1mdiff\033[0m\t\tShow difficulty\n")
io.WriteString(w, "\t\033[1mprint_bc\033[0m\tPrint blockchain info in a given blocks range, print_bc <begin_height> <end_height>\n")
io.WriteString(w, "\t\033[1mprint_block\033[0m\tPrint block, print_block <block_hash> or <block_height>\n")
io.WriteString(w, "\t\033[1mprint_height\033[0m\tPrint local blockchain height\n")
io.WriteString(w, "\t\033[1mprint_tx\033[0m\tPrint transaction, print_tx <transaction_hash>\n")
io.WriteString(w, "\t\033[1mstatus\033[0m\t\tShow genereal information\n")
io.WriteString(w, "\t\033[1msync_info\033[0m\tPrint information about connected peers and their state\n")
io.WriteString(w, "\t\033[1mbye\033[0m\t\tQuit the daemon\n")
io.WriteString(w, "\t\033[1mexit\033[0m\t\tQuit the daemon\n")
io.WriteString(w, "\t\033[1mquit\033[0m\t\tQuit the daemon\n")
} }
var completer = readline.NewPrefixCompleter( var completer = readline.NewPrefixCompleter(
@ -421,7 +495,7 @@ var completer = readline.NewPrefixCompleter(
readline.PcItem("print_block"), readline.PcItem("print_block"),
readline.PcItem("print_height"), readline.PcItem("print_height"),
readline.PcItem("print_tx"), readline.PcItem("print_tx"),
readline.PcItem("status"),
readline.PcItem("status"),
readline.PcItem("sync_info"), readline.PcItem("sync_info"),
readline.PcItem("bye"), readline.PcItem("bye"),
readline.PcItem("exit"), readline.PcItem("exit"),

+ 90
- 0
cmd/explorer/LICENSE

@ -0,0 +1,90 @@
RESEARCH LICENSE
Version 1.1.2
I. DEFINITIONS.
"Licensee " means You and any other party that has entered into and has in effect a version of this License.
“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees.
"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology.
"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage.
"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License.
"Technology Site" means the website designated by Licensor for accessing the Technology.
"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License.
II. PURPOSE.
Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology.
COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT <url>.
III. RESEARCH USE RIGHTS.
A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only:
1. reproduce, create Modifications of, and use the Technology alone, or with Modifications;
2. share source code of the Technology alone, or with Modifications, with other Licensees;
3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and
4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology.
B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights.
C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License.
D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution.
IV. INTELLECTUAL PROPERTY REQUIREMENTS
As a condition to Your License, You agree to comply with the following restrictions and responsibilities:
A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology.
B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License.
V. GENERAL TERMS.
A. Disclaimer Of Warranties.
TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE.
B. Infringement; Limitation Of Liability.
1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site.
2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY.
C. Termination.
1. You may terminate this License at any time by notifying Licensor in writing.
2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance.
3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination.
D. Miscellaneous.
1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor.
2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof.
3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate.
4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter.
5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications.
READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING.
BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS.
IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM.

+ 12
- 0
cmd/explorer/dummy_test.go

@ -0,0 +1,12 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
package main
import "testing"
func Test_Part1(t *testing.T) {
}

+ 673
- 0
cmd/explorer/explorer.go

@ -0,0 +1,673 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package main
// this file implements the explorer for DERO blockchain
// this needs only RPC access
// NOTE: Only use data exported from within the RPC interface, do direct use of exported variables fom packages
// NOTE: we can use structs defined within the RPCserver package
// This is being developed to track down and confirm some bugs
// NOTE: This is NO longer entirely compliant with the xyz RPC interface ( the pool part is not compliant), currently and can be used as it for their chain,
// atleast for the last 1 year
// TODO: error handling is non-existant ( as this was built up in hrs ). Add proper error handling
//
import "time"
import "fmt"
import "net"
import "bytes"
import "strings"
import "encoding/hex"
import "net/http"
import "html/template"
import "encoding/json"
import "io/ioutil"
import "github.com/docopt/docopt-go"
import log "github.com/sirupsen/logrus"
import "github.com/ybbus/jsonrpc"
import "github.com/deroproject/derosuite/block"
import "github.com/deroproject/derosuite/crypto"
import "github.com/deroproject/derosuite/transaction"
import "github.com/deroproject/derosuite/blockchain/rpcserver"
var command_line string = `dero_explorer
DERO Explorer: A secure, private blockchain with smart-contracts
Usage:
dero_explorer [--help] [--version] [--debug] [--rpc-server-address=<127.0.0.1:18091>] [--http-address=<0.0.0.0:8080>]
dero_explorer -h | --help
dero_explorer --version
Options:
-h --help Show this screen.
--version Show version.
--debug Debug mode enabled, print log messages
--rpc-server-address=<127.0.0.1:18091> connect to this daemon port as client
--http-address=<0.0.0.0:8080> explorer listens on this port to serve user requests`
var rpcClient *jsonrpc.RPCClient
var netClient *http.Client
var endpoint string
var replacer = strings.NewReplacer("h", ":", "m", ":", "s", "")
func main() {
var err error
var arguments map[string]interface{}
arguments, err = docopt.Parse(command_line, nil, true, "DERO Explorer : work in progress", false)
if err != nil {
log.Fatalf("Error while parsing options err: %s\n", err)
}
if arguments["--debug"].(bool) == true {
log.SetLevel(log.DebugLevel)
}
log.Debugf("Arguments %+v", arguments)
log.Infof("DERO Exporer : This is under heavy development, use it for testing/evaluations purpose only")
log.Infof("Copyright 2017-2018 DERO Project. All rights reserved.")
endpoint = "127.0.0.1:9999"
if arguments["--rpc-server-address"] != nil {
endpoint = arguments["--rpc-server-address"].(string)
}
log.Infof("using RPC endpoint %s", endpoint)
listen_address := "0.0.0.0:8080"
if arguments["--http-address"] != nil {
listen_address = arguments["--http-address"].(string)
}
log.Infof("Will listen on %s", listen_address)
// create client
rpcClient = jsonrpc.NewRPCClient("http://" + endpoint + "/json_rpc")
var netTransport = &http.Transport{
Dial: (&net.Dialer{
Timeout: 5 * time.Second,
}).Dial,
TLSHandshakeTimeout: 5 * time.Second,
}
netClient = &http.Client{
Timeout: time.Second * 10,
Transport: netTransport,
}
// execute rpc to service
response, err := rpcClient.Call("get_info")
if err == nil {
log.Infof("Connection to RPC server successful")
} else {
log.Fatalf("Connection to RPC server Failed err %s", err)
}
var info rpcserver.GetInfo_Result
err = response.GetObject(&info)
fmt.Printf("%+v err %s\n", info, err)
http.HandleFunc("/search", search_handler)
http.HandleFunc("/page/", page_handler)
http.HandleFunc("/block/", block_handler)
http.HandleFunc("/txpool/", txpool_handler)
http.HandleFunc("/tx/", tx_handler)
http.HandleFunc("/", root_handler)
fmt.Printf("Listening for requests\n")
err = http.ListenAndServe(listen_address, nil)
log.Warnf("Listening to port %s err : %s", listen_address, err)
}
// all the tx info which ever needs to be printed
type txinfo struct {
Height string // height at which tx was mined
Depth uint64
Timestamp uint64 // timestamp
Age string // time diff from current time
Block_time string // UTC time from block header
Epoch uint64 // Epoch time
In_Pool bool // whether tx was in pool
Hash string // hash for hash
PrefixHash string // prefix hash
Version int // version of tx
Size string // size of tx in KB
Sizeuint64 uint64 // size of tx in bytes
Fee string // fee in TX
Feeuint64 uint64 // fee in atomic units
In int // inputs counts
Out int // outputs counts
Amount string
CoinBase bool // is tx coin base
Extra string // extra within tx
Keyimages []string // key images within tx
OutAddress []string // contains output secret key
OutOffset []uint64 // contains index offsets
Type string // ringct or ruffct ( bulletproof)
Ring_size int
}
// any information for block which needs to be printed
type block_info struct {
Major_Version uint64
Minor_Version uint64
Height uint64
Depth uint64
Timestamp uint64
Hash string
Prev_Hash string
Nonce uint64
Fees string
Reward string
Size string
Age string // time diff from current time
Block_time string // UTC time from block header
Epoch uint64 // Epoch time
Outputs string
Mtx txinfo
Txs []txinfo
Orphan_Status bool
Tx_Count int
}
// load and setup block_info from rpc
// if hash is less than 64 bytes then it is considered a height parameter
func load_block_from_rpc(info *block_info, block_hash string, recursive bool) (err error) {
var bl block.Block
var bresult rpcserver.GetBlock_Result
var block_height int
var block_bin []byte
if len(block_hash) != 64 { // parameter is a height
fmt.Sscanf(block_hash, "%d", &block_height)
// user requested block height
log.Debugf("User requested block at height %d user input %s", block_height, block_hash)
response, err := rpcClient.CallNamed("getblock", map[string]interface{}{"height": uint64(block_height)})
if err != nil {
return err
}
err = response.GetObject(&bresult)
if err != nil {
return err
}
} else { // parameter is the hex blob
log.Debugf("User requested block %s", block_hash)
response, err := rpcClient.CallNamed("getblock", map[string]interface{}{"hash": block_hash})
if err != nil {
log.Warnf("err %s ", err)
return err
}
if response.Error != nil {
log.Warnf("err %s ", response.Error)
return fmt.Errorf("No Such block or other Error")
}
err = response.GetObject(&bresult)
if err != nil {
return err
}
}
// fmt.Printf("block %d %+v\n",i, bresult)
info.Height = bresult.Block_Header.Height
info.Depth = bresult.Block_Header.Depth
duration_second := (uint64(time.Now().UTC().Unix()) - bresult.Block_Header.Timestamp)
info.Age = replacer.Replace((time.Duration(duration_second) * time.Second).String())
info.Block_time = time.Unix(int64(bresult.Block_Header.Timestamp), 0).Format("2006-01-02 15:04:05")
info.Epoch = bresult.Block_Header.Timestamp
info.Outputs = fmt.Sprintf("%.03f", float32(bresult.Block_Header.Reward)/1000000000000.0)
info.Size = "N/A"
info.Hash = bresult.Block_Header.Hash
info.Prev_Hash = bresult.Block_Header.Prev_Hash
info.Orphan_Status = bresult.Block_Header.Orphan_Status
info.Nonce = bresult.Block_Header.Nonce
info.Major_Version = bresult.Block_Header.Major_Version
info.Minor_Version = bresult.Block_Header.Minor_Version
info.Reward = fmt.Sprintf("%.03f", float32(bresult.Block_Header.Reward)/1000000000000.0)
block_bin, _ = hex.DecodeString(bresult.Blob)
bl.Deserialize(block_bin)
if recursive {
// fill in miner tx info
err = load_tx_from_rpc(&info.Mtx, bl.Miner_tx.GetHash().String()) //TODO handle error
info.Tx_Count = len(bl.Tx_hashes)
fees := uint64(0)
size := uint64(0)
// if we have any other tx load them also
for i := 0; i < len(bl.Tx_hashes); i++ {
var tx txinfo
err = load_tx_from_rpc(&tx, bl.Tx_hashes[i].String()) //TODO handle error
info.Txs = append(info.Txs, tx)
fees += tx.Feeuint64
size += tx.Sizeuint64
}
info.Fees = fmt.Sprintf("%.03f", float32(fees)/1000000000000.0)
info.Size = fmt.Sprintf("%.03f", float32(size)/1024)
}
return
}
// this will fill up the info struct from the tx
func load_tx_info_from_tx(info *txinfo, tx *transaction.Transaction) (err error) {
info.Hash = tx.GetHash().String()
info.PrefixHash = tx.GetPrefixHash().String()
info.Size = fmt.Sprintf("%.03f", float32(len(tx.Serialize()))/1024)
info.Sizeuint64 = uint64(len(tx.Serialize()))
info.Version = int(tx.Version)
info.Extra = fmt.Sprintf("%x", tx.Extra)
info.In = len(tx.Vin)
info.Out = len(tx.Vout)
if !tx.IsCoinbase() {
info.Fee = fmt.Sprintf("%.012f", float64(tx.RctSignature.Get_TX_Fee())/1000000000000)
info.Feeuint64 = tx.RctSignature.Get_TX_Fee()
info.Amount = "?"
info.Ring_size = len(tx.Vin[0].(transaction.Txin_to_key).Key_offsets)
for i := 0; i < len(tx.Vin); i++ {
info.Keyimages = append(info.Keyimages, fmt.Sprintf("%s ring members %+v", tx.Vin[i].(transaction.Txin_to_key).K_image, tx.Vin[i].(transaction.Txin_to_key).Key_offsets))
}
} else {
info.CoinBase = true
info.In = 0
info.Amount = fmt.Sprintf("%.012f", float64(tx.Vout[0].Amount)/1000000000000)
}
for i := 0; i < len(tx.Vout); i++ {
info.OutAddress = append(info.OutAddress, tx.Vout[i].Target.(transaction.Txout_to_key).Key.String())
}
// if outputs cannot be located, do not panic
// this will be the case for pool transactions
if len(info.OutAddress) != len(info.OutOffset) {
info.OutOffset = make([]uint64, len(info.OutAddress), len(info.OutAddress))
}
switch tx.RctSignature.Get_Sig_Type() {
case 0:
info.Type = "RingCT/0"
case 1:
info.Type = "RingCT/1 MG"
case 2:
info.Type = "RingCT/2 Simple"
}
if !info.In_Pool { // find the age of block and other meta
var blinfo block_info
err := load_block_from_rpc(&blinfo, fmt.Sprintf("%s", info.Height), false) // we only need block data and not data of txs
if err != nil {
return err
}
// fmt.Printf("Blinfo %+v height %d", blinfo, info.Height);
info.Age = blinfo.Age
info.Block_time = blinfo.Block_time
info.Epoch = blinfo.Epoch
info.Timestamp = blinfo.Epoch
info.Depth = blinfo.Depth
}
return nil
}
// load and setup txinfo from rpc
func load_tx_from_rpc(info *txinfo, txhash string) (err error) {
var tx_params rpcserver.GetTransaction_Params
var tx_result rpcserver.GetTransaction_Result
//fmt.Printf("Requesting tx data %s", txhash);
tx_params.Tx_Hashes = append(tx_params.Tx_Hashes, txhash)
request_bytes, err := json.Marshal(&tx_params)
response, err := http.Post("http://"+endpoint+"/gettransactions", "application/json", bytes.NewBuffer(request_bytes))
if err != nil {
//fmt.Printf("err while requesting tx err %s",err);
return
}
buf, err := ioutil.ReadAll(response.Body)
if err != nil {
// fmt.Printf("err while reading reponse body err %s",err);
return
}
err = json.Unmarshal(buf, &tx_result)
if err != nil {
return
}
// fmt.Printf("TX response %+v", tx_result)
if tx_result.Status != "OK" {
return fmt.Errorf("No Such TX RPC error status %s", tx_result.Status)
}
var tx transaction.Transaction
if len(tx_result.Txs_as_hex[0]) < 50 {
return
}
tx_bin, _ := hex.DecodeString(tx_result.Txs_as_hex[0])
tx.DeserializeHeader(tx_bin)
// fill as much info required from headers
if tx_result.Txs[0].In_pool {
info.In_Pool = true
} else {
info.Height = fmt.Sprintf("%d", tx_result.Txs[0].Block_Height)
}
for x := range tx_result.Txs[0].Output_Indices {
info.OutOffset = append(info.OutOffset, tx_result.Txs[0].Output_Indices[x])
}
//fmt.Printf("tx_result %+v\n",tx_result.Txs)
return load_tx_info_from_tx(info, &tx)
}
func block_handler(w http.ResponseWriter, r *http.Request) {
param := ""
fmt.Sscanf(r.URL.EscapedPath(), "/block/%s", &param)
var blinfo block_info
err := load_block_from_rpc(&blinfo, param, true)
_ = err
// execute template now
data := map[string]interface{}{}
data["title"] = "DERO BlockChain Explorer (Golang)"
data["servertime"] = time.Now().UTC().Format("2006-01-02 15:04:05")
data["block"] = blinfo
t, err := template.New("foo").Parse(header_template + block_template + footer_template)
err = t.ExecuteTemplate(w, "block", data)
if err != nil {
return
}
return
// fmt.Fprint(w, "This is a valid block")
}
func tx_handler(w http.ResponseWriter, r *http.Request) {
var info txinfo
tx_hex := ""
fmt.Sscanf(r.URL.EscapedPath(), "/tx/%s", &tx_hex)
txhash := crypto.HashHexToHash(tx_hex)
log.Debugf("user requested TX %s", tx_hex)
err := load_tx_from_rpc(&info, txhash.String()) //TODO handle error
_ = err
// execute template now
data := map[string]interface{}{}
data["title"] = "DERO BlockChain Explorer (Golang)"
data["servertime"] = time.Now().UTC().Format("2006-01-02 15:04:05")
data["info"] = info
t, err := template.New("foo").Parse(header_template + tx_template + footer_template)
err = t.ExecuteTemplate(w, "tx", data)
if err != nil {
return
}
return
}
func pool_handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "This is a valid pool")
}
// if there is any error, we return back empty
// if pos is wrong we return back
// pos is descending order
func fill_tx_structure(pos int, size_in_blocks int) (data []block_info) {
for i := pos; i > (pos-11) && i >= 0; i-- { // query blocks by height
var blinfo block_info
err := load_block_from_rpc(&blinfo, fmt.Sprintf("%d", i), true)
if err == nil {
data = append(data, blinfo)
}
}
return
}
func show_page(w http.ResponseWriter, page int) {
data := map[string]interface{}{}
var info rpcserver.GetInfo_Result
data["title"] = "DERO BlockChain Explorer (Golang)"
data["servertime"] = time.Now().UTC().Format("2006-01-02 15:04:05")
t, err := template.New("foo").Parse(header_template + txpool_template + main_template + paging_template + footer_template)
// collect all the data afresh
// execute rpc to service
response, err := rpcClient.Call("get_info")
if err != nil {
goto exit_error
}
err = response.GetObject(&info)
if err != nil {
goto exit_error
}
//fmt.Printf("get info %+v", info)
data["Network_Difficulty"] = info.Difficulty
data["hash_rate"] = fmt.Sprintf("%.03f", float32(info.Difficulty/1000000)/float32(info.Target))
data["txpool_size"] = info.Tx_pool_size
data["testnet"] = info.Testnet
if int(info.Height) < page*11 { // use requested invalid page, give page 0
page = 0
}
data["previous_page"] = 0
if page > 0 {
data["previous_page"] = page - 1
}
data["current_page"] = page
data["total_page"] = int(info.Height) / 11
data["next_page"] = page + 1
if (page + 1) > int(info.Height)/11 {
data["next_page"] = page
}
fill_tx_pool_info(data, 25)
data["block_array"] = fill_tx_structure(int(info.Height)-(page*11), 11)
err = t.ExecuteTemplate(w, "main", data)
if err != nil {
goto exit_error
}
return
exit_error:
fmt.Fprintf(w, "Error occurred err %s", err)
}
func txpool_handler(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{}
var info rpcserver.GetInfo_Result
data["title"] = "DERO BlockChain Explorer (Golang)"
data["servertime"] = time.Now().UTC().Format("2006-01-02 15:04:05")
t, err := template.New("foo").Parse(header_template + txpool_template + main_template + paging_template + footer_template + txpool_page_template)
// collect all the data afresh
// execute rpc to service
response, err := rpcClient.Call("get_info")
if err != nil {
goto exit_error
}
err = response.GetObject(&info)
if err != nil {
goto exit_error
}
//fmt.Printf("get info %+v", info)
data["Network_Difficulty"] = info.Difficulty
data["hash_rate"] = fmt.Sprintf("%.03f", float32(info.Difficulty/1000000)/float32(info.Target))
data["txpool_size"] = info.Tx_pool_size
data["testnet"] = info.Testnet
fill_tx_pool_info(data, 500) // show only 500 txs
err = t.ExecuteTemplate(w, "txpool_page", data)
if err != nil {
goto exit_error
}
return
exit_error:
fmt.Fprintf(w, "Error occurred err %s", err)
}
// shows a page
func page_handler(w http.ResponseWriter, r *http.Request) {
page := 0
page_string := r.URL.EscapedPath()
fmt.Sscanf(page_string, "/page/%d", &page)
log.Debugf("user requested page %d", page)
show_page(w, page)
}
// root shows page 0
func root_handler(w http.ResponseWriter, r *http.Request) {
log.Debugf("Showing main page")
show_page(w, 0)
}
// search handler, finds the items using rpc bruteforce
func search_handler(w http.ResponseWriter, r *http.Request) {
log.Debugf("Showing search page")
values, ok := r.URL.Query()["value"]
if !ok || len(values) < 1 {
show_page(w, 0)
return
}
// Query()["key"] will return an array of items,
// we only want the single item.
value := values[0]
// check whether the page is block or tx or height
var blinfo block_info
var tx txinfo
err := load_block_from_rpc(&blinfo, value, false)
if err == nil {
log.Debugf("Redirecting user to block page")
http.Redirect(w, r, "/block/"+value, 302)
return
}
err = load_tx_from_rpc(&tx, value) //TODO handle error
if err == nil {
log.Debugf("Redirecting user to tx page")
http.Redirect(w, r, "/tx/"+value, 302)
return
}
show_page(w, 0)
return
}
// fill all the tx pool info as per requested
func fill_tx_pool_info(data map[string]interface{}, max_count int) error {
var txs []txinfo
var txpool rpcserver.GetTxPool_Result
data["mempool"] = txs // initialize with empty data
// collect all the data afresh
// execute rpc to service
response, err := rpcClient.Call("gettxpool")
if err != nil {
return fmt.Errorf("gettxpool rpc failed")
}
err = response.GetObject(&txpool)
if err != nil {
return fmt.Errorf("gettxpool rpc failed")
}
for i := range txpool.Tx_list {
var info txinfo
err := load_tx_from_rpc(&info, txpool.Tx_list[i]) //TODO handle error
if err != nil {
continue
}
txs = append(txs, info)
if len(txs) >= max_count {
break
}
}
data["mempool"] = txs
return nil
}

+ 489
- 0
cmd/explorer/templates.go

@ -0,0 +1,489 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package main
// this files defines all the templates
var header_template string = `
{{define "header"}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
<title>{{ .title }}</title>
<!--<link rel="stylesheet" type="text/css" href="/css/style.css">-->
<style type="text/css">
body {
margin: 0;
padding: 0;
color: green;
background-color: white;
}
h1, h2, h3, h4, h5, h6 {
text-align: center;
}
.center {
margin: auto;
width: 96%;
/*border: 1px solid #73AD21;
padding: 10px;*/
}
tr, li, #pages, .info {
font-family: "Lucida Console", Monaco, monospace;
font-size : 12px;
height: 22px;
}
#pages
{
margin-top: 15px;
}
td {
text-align: center;
}
a:link {
text-decoration: none;
color: blue;
}
a:visited {
text-decoration: none;
color: blue;
}
a:hover {
text-decoration: underline;
color: blue;
}
a:active {
text-decoration: none;
color: blue;
}
form {
display: inline-block;
text-align: center;
}
.style-1 input[type="text"] {
padding: 2px;
border: solid 1px #dcdcdc;
transition: box-shadow 0.3s, border 0.3s;
}
.style-1 input[type="text"]:focus,
.style-1 input[type="text"].focus {
border: solid 1px #707070;
box-shadow: 0 0 5px 1px #969696;
}
.tabs {
position: relative;
min-height: 220px; /* This part sucks */
clear: both;
margin: 25px 0;
}
.tab {
float: left;
}
.tab label {
background: white;
padding: 10px;
border: 1px solid #ccc;
margin-left: -1px;
position: relative;
left: 1px;
}
.tab [type=radio] {
display: none;
}
.content {
position: absolute;
top: 28px;
left: 0;
background: white;
right: 0;
bottom: 0;
padding: 20px;
border: 1px solid #ccc;
}
[type=radio]:checked ~ label {
background: #505050 ;
border-bottom: 1px solid green;
z-index: 2;
}
[type=radio]:checked ~ label ~ .content {
z-index: 1;
}
input#toggle-1[type=checkbox] {
position: absolute;
/*top: -9999px;*/
left: -9999px;
}
label#show-decoded-inputs {
/*-webkit-appearance: push-button;*/
/*-moz-appearance: button;*/
display: inline-block;
/*margin: 60px 0 10px 0;*/
cursor: pointer;
background-color: white;;
color: green;
width: 100%;
text-align: center;
}
div#decoded-inputs{
display: none;
}
/* Toggled State */
input#toggle-1[type=checkbox]:checked ~ div#decoded-inputs {
display: block;
}
</style>
</head>
<body>
<div>
<div class="center">
<h1 class="center"><a href="/">{{ .title }} {{if .testnet}} TestNet {{end}}</a></h1>
<!-- <h4 style="font-size: 15px; margin: 0px">(no javascript - no cookies - no web analytics trackers - no images - open sourced)</h4> -->
</div>
<div class="center">
<form action="/search" method="get" style="width:100%; margin-top:15px" class="style-1">
<input type="text" name="value" size="120"
placeholder="block height, block hash, transaction hash">
<input type="submit" value="Search">
</form>
</div>
</div>
{{if .Network_Difficulty}}
<div class="center">
<h3 style="font-size: 12px; margin-top: 20px">
Server time: {{ .servertime }} | <a href="/txpool">Transaction pool</a>
</h3>
<h3 style="font-size: 12px; margin-top: 5px; margin-bottom: 3">
Network difficulty: {{ .Network_Difficulty }}
| Hash rate: {{ .hash_rate }} MH&#x2F;s
| Mempool size : {{ .txpool_size }}
<!-- | Fee per kb: 0.001198930000
| Median block size limit: 292.97 kB
-->
</h3>
</div>
{{end}}
{{end}}
`
var block_template string = `{{define "block"}}
{{ template "header" . }}
<div>
<H4>Block hash (height): {{.block.Hash}} ({{.block.Height}})</H4>
<H5>Previous block: <a href="/block/{{.block.Prev_Hash}}">{{.block.Prev_Hash}}</a></H5>
<!--
<H5>Next block: <a href="/block/a8ade20d5cad5e23105cfc25687beb2498844a984b1450330c67705b6c720596">a8ade20d5cad5e23105cfc25687beb2498844a984b1450330c67705b6c720596</a></H5>
-->
<table class="center">
<tr>
<td>Timestamp [UCT] (epoch):</td><td>{{.block.Block_time}} ({{.block.Epoch}})</td>
<td>Age [h:m:s]:</td><td>{{.block.Age}}</td>
<td>Δ [h:m:s]:</td><td></td>
</tr>
<tr>
<td>Major.minor version:</td><td>{{.block.Major_Version}}.{{.block.Minor_Version}}</td>
<td>Block reward:</td><td>{{.block.Reward}}</td>
<td>Block size [kB]:</td><td>{{.block.Size}}</td>
</tr>
<tr>
<td>nonce:</td><td>{{.block.Nonce}}</td>
<td>Total fees:</td><td>{{.block.Fees}}</td>
<td>No of txs:</td><td>{{.block.Tx_Count}}</td>
</tr>
</table>
<h3>Miner reward transaction</h3>
<table class="center">
<tr>
<td>hash</td>
<td>outputs</td>
<td>size [kB]</td>
<td>version</td>
</tr>
<tr>
<td><a href="/tx/{{.block.Mtx.Hash}}">{{.block.Mtx.Hash}}</a>
<td>{{.block.Mtx.Amount}}</td>
<td>{{.block.Mtx.Size}}</td>
<td>{{.block.Mtx.Version}}</td>
</tr>
</table>
<h3>Transactions ({{.block.Tx_Count}})</h3>
<table class="center" style="width:80%">
<tr>
<td>hash</td>
<td>outputs</td>
<td>fee</td>
<td>ring size</td>
<td>in/out</td>
<td>version</td>
<td>size [kB]</td>
</tr>
{{range .block.Txs}}
<tr>
<td><a href="/tx/{{.Hash}}">{{.Hash}}</a></td>
<td>?</td>
<td>{{.Fee}}</td>
<td>{{.Ring_size}}</td>
<td>{{.In}}/{{.Out}}</td>
<td>{{.Version}}</td>
<td>{{.Size}}</td>
</tr>
{{end}}
</table>
</div>
{{ template "footer" . }}
{{end}}
`
var tx_template string = `{{define "tx"}}
{{ template "header" . }}
<div>
<H4 style="margin:5px">Tx hash: {{.info.Hash}}</H4>
<H5 style="margin:5px">Tx prefix hash: {{.info.PrefixHash}}</H5>
<H5 style="margin:5px">Tx public key: TODO</H5>
<table class="center" style="width: 80%; margin-top:10px">
<tr>
<td>Timestamp: {{.info.Timestamp}} </td>
<td>Timestamp [UCT]: {{.info.Block_time}}</td>
<td>Age [y:d:h:m:s]: {{.info.Age}} </td>
</tr>
<tr>
<td>Block: <a href="/block/{{.info.Height}}">{{.info.Height}}</a></td>
<td>Fee: {{.info.Fee}}</td>
<td>Tx size: {{.info.Size}} kB</td>
</tr>
<tr>
<td>Tx version: {{.info.Version}}</td>
<td>No of confirmations: {{.info.Depth}}</td>
<td>Signature type: {{.info.Type}}</td>
</tr>
<tr>
<td colspan="3">Extra: {{.info.Extra}}</td>
</tr>
</table>
<h3>{{.info.Out}} output(s) for total of {{.info.Amount}} dero</h3>
<div class="center">
<table class="center">
<tr>
<td>stealth address</td>
<td>amount</td>
<td>amount idx</td>
</tr>
{{range $i, $e := .info.OutAddress}}
<tr>
<td>{{ $e }}</td>
<td>{{$.info.Amount}}</td>
<td>{{index $.info.OutOffset $i}}</td>
</tr>
{{end}}
</table>
</div>
<!-- TODO currently we donot enable user to prove or decode something -->
{{if eq .info.CoinBase false}}
<h3>{{.info.In}} input(s) for total of ? dero</h3>
<div class="center">
<table class="center">
{{range .info.Keyimages}}
<tr>
<td style="text-align: center;">
key image {{ . }}
</td>
<td>amount: ?</td>
</tr>
{{end}}
</table>
</div>
{{end}}
</div>
{{ template "footer" . }}
{{end}}`
var txpool_template string = `{{define "txpool"}}
<h2 style="margin-bottom: 0px">
Transaction pool
</h2>
<h4 style="font-size: 12px; margin-top: 0px">(no of txs: {{ .txpool_size }}, size: 0.00 kB, updated every 5 seconds)</h4>
<div class="center">
<table class="center" style="width:80%">
<tr>
<td>age [h:m:s]</td>
<td>transaction hash</td>
<td>fee</td>
<td>outputs</td>
<td>in(nonrct)/out</td>
<td>ring size</td>
<td>tx size [kB]</td>
</tr>
{{range .mempool}}
<tr>
<td></td>
<td><a href="/tx/{{.Hash}}">{{.Hash}}</a></td>
<td>{{.Fee}}</td>
<td>N/A</td>
<td>{{.In}}/{{.Out}}</td>
<td>{{.Ring_size}}</td>
<td>{{.Size}}</td>
</tr>
{{end}}
</table>
</div>
{{end}}`
// full page txpool_template
var txpool_page_template string = `{{define "txpool_page"}}
{{ template "header" . }}
{{ template "txpool" . }}
{{ template "footer" . }}
{{end}}`
var main_template string = `
{{define "main"}}
{{ template "header" . }}
{{ template "txpool" . }}
<h2 style="margin-bottom: 0px">Transactions in the last 11 blocks</h2>
<h4 style="font-size: 14px; margin-top: 0px">(Median size of these blocks: 0.09 kB)</h4>
<div class="center">
<table class="center">
<tr>
<td>height</td>
<td>age [h:m:s]<!--(Δm)--></td>
<td>size [kB]<!--(Δm)--></td>
<td>tx hash</td>
<td>fees</td>
<td>outputs</td>
<td>in(nonrct)/out</td>
<td>ring size</td>
<td>tx size [kB]</td>
</tr>
{{range .block_array}}
<tr>
<td><a href="/block/{{.Height}}">{{.Height}}</a></td>
<td>{{.Age}}</td>
<td>{{.Size}}</td>
<td><a href="/tx/{{.Mtx.Hash}}">{{.Mtx.Hash}}</a></td>
<td>N/A</td>
<td>{{.Mtx.Amount}}</td>
<td>{{.Mtx.In}}/{{.Mtx.Out}}</td>
<td>0</td>
<td>{{.Mtx.Size}}</td>
</tr>
{{range .Txs}}
<tr>
<td></td>
<td></td>
<td></td>
<td><a href="/tx/{{.Hash}}">{{.Hash}}</a></td>
<td>{{.Fee}}</td>
<td>N/A</td>
<td>{{.In}}/{{.Out}}</td>
<td>{{.Ring_size}}</td>
<td>{{.Size}}</td>
</tr>
{{end}}
{{end}}
</table>
{{ template "paging" . }}
</div>
{{ template "footer" . }}
{{end}}`
var paging_template string = `{{ define "paging"}}
<div id="pages" class="center" style="text-align: center;">
<a href="/page/{{.previous_page}}">previous page</a> |
<a href="/">first page</a> |
current page: {{.current_page}}/<a href="/page/{{.total_page}}">{{.total_page}}</a>
| <a href="/page/{{.next_page}}">next page</a>
</div>
{{end}}`
var footer_template string = ` {{define "footer"}}
<div class="center">
<h6 style="margin-top:10px">
<a href="https://github.com/deroproject/">DERO explorer source code</a>
| explorer version (api): under development (1.0)
| dero version: golang pre-alpha
| Copyright 2017-2018 Dero Project
</h6>
</div>
</body>
</html>
{{end}}
`

+ 90
- 0
config/LICENSE

@ -0,0 +1,90 @@
RESEARCH LICENSE
Version 1.1.2
I. DEFINITIONS.
"Licensee " means You and any other party that has entered into and has in effect a version of this License.
“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees.
"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology.
"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage.
"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License.
"Technology Site" means the website designated by Licensor for accessing the Technology.
"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License.
II. PURPOSE.
Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology.
COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT <url>.
III. RESEARCH USE RIGHTS.
A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only:
1. reproduce, create Modifications of, and use the Technology alone, or with Modifications;
2. share source code of the Technology alone, or with Modifications, with other Licensees;
3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and
4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology.
B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights.
C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License.
D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution.
IV. INTELLECTUAL PROPERTY REQUIREMENTS
As a condition to Your License, You agree to comply with the following restrictions and responsibilities:
A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology.
B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License.
V. GENERAL TERMS.
A. Disclaimer Of Warranties.
TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE.
B. Infringement; Limitation Of Liability.
1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site.
2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY.
C. Termination.
1. You may terminate this License at any time by notifying Licensor in writing.
2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance.
3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination.
D. Miscellaneous.
1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor.
2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof.
3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate.
4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter.
5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications.
READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING.
BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS.
IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM.

+ 39
- 2
config/config.go

@ -1,9 +1,24 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package config package config
import "github.com/satori/go.uuid" import "github.com/satori/go.uuid"
import "github.com/deroproject/derosuite/crypto" import "github.com/deroproject/derosuite/crypto"
// all global configuration variables are picked from here // all global configuration variables are picked from here
var BLOCK_TIME = uint64(120) var BLOCK_TIME = uint64(120)
@ -17,15 +32,37 @@ var COIN_DIFFICULTY_TARGET = uint64(120) // this is a feeder to
var COIN_FINAL_SUBSIDY_PER_MINUTE = uint64(300000000000) // 0.3 DERO per minute = 157680 per year roughly var COIN_FINAL_SUBSIDY_PER_MINUTE = uint64(300000000000) // 0.3 DERO per minute = 157680 per year roughly
var CRYPTONOTE_REWARD_BLOCKS_WINDOW = uint64(100) // last 100 blocks are used to create var CRYPTONOTE_REWARD_BLOCKS_WINDOW = uint64(100) // last 100 blocks are used to create
var MINER_TX_AMOUNT_UNLOCK = uint64(60) // miner tx will need 60 blocks to mature
var NORMAL_TX_AMOUNT_UNLOCK = uint64(10) // normal transfers will mature at 10th (9 blocks distance) blocks to mature
// this is used to find whether output is locked to height or time
// see input maturity to find how it works
// if locked is less than this, then it is considered locked to height else epoch
var CRYPTONOTE_MAX_BLOCK_NUMBER = uint64(500000000)
var MAX_CHAIN_HEIGHT = uint64(2147483648) // 2^31 var MAX_CHAIN_HEIGHT = uint64(2147483648) // 2^31
// we use this for scheduled hardforks // we use this for scheduled hardforks
var CURRENT_BLOCK_MAJOR_VERSION = 6 var CURRENT_BLOCK_MAJOR_VERSION = 6
var CURRENT_BLOCK_MINOR_VERSION = 6 var CURRENT_BLOCK_MINOR_VERSION = 6
// this is also the minimum block size
var CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE = uint64(300000) // after this block size , reward calculated differently var CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE = uint64(300000) // after this block size , reward calculated differently
var CRYPTONOTE_MAX_TX_SIZE = uint64(100 * 1024 * 1024) // 100 MB, we must rationalize it
// we only accept blocks which are this much into future, 2 hours
const CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT = 60 * 60 * 20
// block is checked that the timestamp is not less than the median of this many blocks
const BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW = 60
// consider last 30 blocks for calculating difficulty // consider last 30 blocks for calculating difficulty
var DIFFICULTY_BLOCKS_COUNT_V2 = 30
const DIFFICULTY_BLOCKS_COUNT_V2 = 30
// FEE calculation constants are here
// the constants can be found in cryptonote_config.h
const DYNAMIC_FEE_PER_KB_BASE_FEE_V5 = uint64((2000000000 * 60000) / 300000)
const DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD = uint64(10000000000000) // 10 * pow(10,12)
const PROJECT_NAME = "dero" const PROJECT_NAME = "dero"
const POOLDATA_FILENAME = "poolstate.bin" const POOLDATA_FILENAME = "poolstate.bin"

+ 6
- 2
config/dummy_test.go

@ -1,8 +1,12 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
package config package config
import "testing" import "testing"
func Test_Part1(t *testing.T) {
func Test_Part1(t *testing.T){
} }

+ 90
- 0
crypto/LICENSE

@ -0,0 +1,90 @@
RESEARCH LICENSE
Version 1.1.2
I. DEFINITIONS.
"Licensee " means You and any other party that has entered into and has in effect a version of this License.
“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees.
"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology.
"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage.
"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License.
"Technology Site" means the website designated by Licensor for accessing the Technology.
"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License.
II. PURPOSE.
Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology.
COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT <url>.
III. RESEARCH USE RIGHTS.
A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only:
1. reproduce, create Modifications of, and use the Technology alone, or with Modifications;
2. share source code of the Technology alone, or with Modifications, with other Licensees;
3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and
4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology.
B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights.
C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License.
D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution.
IV. INTELLECTUAL PROPERTY REQUIREMENTS
As a condition to Your License, You agree to comply with the following restrictions and responsibilities:
A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology.
B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License.
V. GENERAL TERMS.
A. Disclaimer Of Warranties.
TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE.
B. Infringement; Limitation Of Liability.
1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site.
2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY.
C. Termination.
1. You may terminate this License at any time by notifying Licensor in writing.
2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance.
3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination.
D. Miscellaneous.
1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor.
2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof.
3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate.
4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter.
5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications.
READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING.
BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS.
IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM.

+ 1444
- 0
crypto/const.go
File diff suppressed because it is too large
View File


+ 196
- 0
crypto/crypto_test.go

@ -0,0 +1,196 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package crypto
//import "fmt"
import "testing"
import "bufio"
import "log"
import "os"
import "strings"
import "strconv"
import "encoding/hex"
// these tests, specifically "tests_data.txt" are available in the monero project and used here to verify whether we implement everything
func Test_Crypto(t *testing.T) {
file, err := os.Open("tests_data.txt")
if err != nil {
log.Fatalf("Test file tests_data is missing, err %s ", err)
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
// parse the line
line := scanner.Text()
words := strings.Fields(line)
if len(words) < 2 {
continue
}
switch words[0] {
case "check_scalar":
scalar := HexToKey(words[1])
expected := "true" == words[2]
actual := ScValid(&scalar) == true
if actual != expected {
t.Fatalf("Failed %s: Expected %v, got %v.", words[0], expected, actual)
}
case "check_key":
public_key := HexToKey(words[1])
expected := "true" == words[2]
actual := public_key.Public_Key_Valid() == true
if actual != expected {
t.Logf("Failed %s: Expected %v, got %v %s", words[0], expected, actual, public_key)
}
case "random_scalar": // ignore them
case "hash_to_scalar":
data, _ := hex.DecodeString(words[1])
expected := HexToKey(words[2])
actual := HashToScalar(data)
if *actual != expected {
t.Fatalf("Failed %s: Expected %v, got %v.", words[0], expected, actual)
}
//t.Logf("executing %s\n", expected)
case "generate_keys": // this test is meant to test RNG ??
key_secret := HexToKey(words[2])
key_public := HexToKey(words[1])
if key_public != *(key_secret.PublicKey()) {
t.Errorf("Failed %s key generation testing failed %s ", words[0], key_secret)
}
case "secret_key_to_public_key":
key_secret := HexToKey(words[1])
expected := "true" == words[2]
actual := key_secret.Private_Key_Valid()
if expected != actual {
t.Fatalf("Failed %s: Expected %v, got %v. %s", words[0], expected, actual, key_secret)
}
if actual { // test only if required
key_public := HexToKey(words[3])
if key_public != *(key_secret.PublicKey()) {
t.Errorf("Failed %s key generation testing failed %s ", words[0], key_secret)
}
}
case "generate_key_derivation":
public_key := HexToKey(words[1])
private_key := HexToKey(words[2])
expected := "true" == words[3]
actual := public_key.Public_Key_Valid()
if expected != actual {
t.Fatalf(" Failed %s: Expected %v, got %v. %s", words[0], expected, actual, public_key)
}
if expected == true { // yes knowingly using the same variables
expected := HexToKey(words[4])
actual := KeyDerivation(&public_key, &private_key)
if expected != actual {
t.Fatalf("Failed %s: Expected %v, got %v. %s", words[0], expected, actual, public_key)
}
}
case "derive_public_key":
kd := HexToKey(words[1]) //
outIdx, _ := strconv.ParseUint(words[2], 10, 0)
base := HexToKey(words[3])
var expected1, actual1 bool
var expected2, actual2 Key
expected1 = words[4] == "true"
if expected1 {
expected2 = HexToKey(words[5])
}
actual1 = base.Public_Key_Valid()
if actual1 != expected1 {
t.Fatalf("%s: Expected %v, got %v.", words[0], expected1, actual1)
}
if expected1 {
actual2 = kd.KeyDerivation_To_PublicKey(outIdx, base)
if actual2 != expected2 {
t.Fatalf("%s: Expected %v, got %v.", words[0], expected2, actual2)
}
}
case "derive_secret_key":
kd := HexToKey(words[1]) //
outIdx, _ := strconv.ParseUint(words[2], 10, 0)
base := HexToKey(words[3])
expected := HexToKey(words[4])
actual := kd.KeyDerivation_To_PrivateKey(outIdx, base)
if actual != expected {
t.Fatalf("%s: Expected %v, got %v.", words[0], expected, actual)
}
case "hash_to_point": // this is different check than HashToPoint
hash := HexToKey(words[1])
expected := HexToKey(words[2])
var actual Key
var p1 ProjectiveGroupElement
p1.FromBytes(&hash)
p1.ToBytes(&actual)
if actual != expected {
t.Logf("%s: Expected %v, got %v.", words[0], expected, actual)
}
case "hash_to_ec":
pub := HexToKey(words[1])
expected := HexToKey(words[2])
var actual Key
ex := pub.HashToEC()
ex.ToBytes(&actual)
if actual != expected {
t.Fatalf("%s: Expected %s, got %s.", words[0], expected, actual)
}
case "generate_key_image":
public_key := HexToKey(words[1])
private_key := HexToKey(words[2])
expected := HexToKey(words[3])
actual := GenerateKeyImage(public_key, private_key)
if actual != expected {
t.Fatalf("%s: Expected %s, got %s.", words[0], expected, actual)
}
// these are ignored because they are not required DERO project is based on ringct+
case "generate_signature":
case "check_signature":
case "generate_ring_signature":
case "check_ring_signature":
default:
t.Fatalf("This test is not handled %s: ", words[0])
}
}
}

+ 3176
- 0
crypto/edwards25519.go
File diff suppressed because it is too large
View File


+ 1630
- 0
crypto/edwards25519_test.go
File diff suppressed because it is too large
View File


+ 21
- 0
crypto/hash.go

@ -1,3 +1,19 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package crypto package crypto
import "fmt" import "fmt"
@ -15,6 +31,11 @@ func (h Hash) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("%x", h[:])), nil return []byte(fmt.Sprintf("%x", h[:])), nil
} }
// stringifier
func (h Hash) String() string {
return fmt.Sprintf("%x", h[:])
}
// convert a hash of hex form to binary form, returns a zero hash if any error // convert a hash of hex form to binary form, returns a zero hash if any error
// TODO this should be in crypto // TODO this should be in crypto
func HashHexToHash(hash_hex string) (hash Hash) { func HashHexToHash(hash_hex string) (hash Hash) {

+ 16
- 2
crypto/keccak.go

@ -1,9 +1,23 @@
package crypto
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package crypto
import "github.com/ebfe/keccak" import "github.com/ebfe/keccak"
// quick keccak wrapper // quick keccak wrapper
func Keccak256(data ...[]byte) (result Hash) { func Keccak256(data ...[]byte) (result Hash) {
h := keccak.New256() h := keccak.New256()

+ 16
- 22
crypto/keccak_test.go

@ -1,29 +1,24 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package crypto package crypto
import "testing" import "testing"
import "encoding/hex" import "encoding/hex"
// convert a hex string to a key
func HexToKey(h string) (result Key) {
byteSlice, _ := hex.DecodeString(h)
if len(byteSlice) != 32 {
panic("Incorrect key size")
}
copy(result[:], byteSlice)
return
}
func HexToHash(h string) (result Hash) {
byteSlice, _ := hex.DecodeString(h)
if len(byteSlice) != 32 {
panic("Incorrect key size")
}
copy(result[:], byteSlice)
return
}
func TestKeccak256(t *testing.T) { func TestKeccak256(t *testing.T) {
tests := []struct { tests := []struct {
name string name string
@ -50,7 +45,6 @@ func TestKeccak256(t *testing.T) {
messageHex: "0f3fe9c20b24a11bf4d6d1acd335c6a80543f1f0380590d7323caf1390c78e88", messageHex: "0f3fe9c20b24a11bf4d6d1acd335c6a80543f1f0380590d7323caf1390c78e88",
wantHex: "73b7a236f2a97c4e1805f7a319f1283e3276598567757186c526caf9a49e0a92", wantHex: "73b7a236f2a97c4e1805f7a319f1283e3276598567757186c526caf9a49e0a92",
}, },
} }
for _, test := range tests { for _, test := range tests {
message, _ := hex.DecodeString(test.messageHex) message, _ := hex.DecodeString(test.messageHex)

+ 392
- 1
crypto/key.go

@ -1,13 +1,404 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package crypto package crypto
import "io"
import "fmt" import "fmt"
import "bytes"
import "crypto/rand"
import "encoding/hex"
import "encoding/binary"
const KeyLength = 32 const KeyLength = 32
// Key can be a Scalar or a Point // Key can be a Scalar or a Point
type Key [KeyLength]byte type Key [KeyLength]byte
func (k Key) MarshalText() ([]byte, error) { func (k Key) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("%x", k[:])), nil return []byte(fmt.Sprintf("%x", k[:])), nil
} }
func (k Key) String() string {
return fmt.Sprintf("%x", k[:])
}
func (p *Key) FromBytes(b [KeyLength]byte) {
*p = b
}
func (p *Key) ToBytes() (result [KeyLength]byte) {
result = [KeyLength]byte(*p)
return
}
// convert a hex string to a key
func HexToKey(h string) (result Key) {
byteSlice, _ := hex.DecodeString(h)
if len(byteSlice) != 32 {
panic("Incorrect key size")
}
copy(result[:], byteSlice)
return
}
func HexToHash(h string) (result Hash) {
byteSlice, _ := hex.DecodeString(h)
if len(byteSlice) != 32 {
panic("Incorrect key size")
}
copy(result[:], byteSlice)
return
}
// generates a public from the secret key
func (p *Key) PublicKey() (pubKey *Key) {
point := new(ExtendedGroupElement)
GeScalarMultBase(point, p)
pubKey = new(Key)
point.ToBytes(pubKey)
return
}
// tests whether the key is valid ( represents a point on the curve )
func (k *Key) Public_Key_Valid() bool {
var point ExtendedGroupElement
return point.FromBytes(k)
}
func (k *Key) Private_Key_Valid() bool {
return Sc_check(k)
}
// Creates a point on the Edwards Curve by hashing the key
func (p *Key) HashToEC() (result *ExtendedGroupElement) {
result = new(ExtendedGroupElement)
var p1 ProjectiveGroupElement
var p2 CompletedGroupElement
h := Key(Keccak256(p[:]))
p1.FromBytes(&h)
GeMul8(&p2, &p1)
p2.ToExtended(result)
return
}
func (p *Key) HashToPoint() (result Key) {
extended := p.HashToEC()
extended.ToBytes(&result)
return
}
// this uses random number generator from the OS
func RandomScalar() (result *Key) {
result = new(Key)
var reduceFrom [KeyLength * 2]byte
tmp := make([]byte, KeyLength*2)
rand.Read(tmp)
copy(reduceFrom[:], tmp)
ScReduce(result, &reduceFrom)
return
}
// generate a new private-public key pair
func NewKeyPair() (privKey *Key, pubKey *Key) {
privKey = RandomScalar()
pubKey = privKey.PublicKey()
return
}
func ParseKey(buf io.Reader) (result Key, err error) {
key := make([]byte, KeyLength)
if _, err = buf.Read(key); err != nil {
return
}
copy(result[:], key)
return
}
/*
//does a * G where a is a scalar and G is the curve basepoint
key scalarmultBase(const key & a) {
ge_p3 point;
key aG;
sc_reduce32copy(aG.bytes, a.bytes); //do this beforehand
ge_scalarmult_base(&point, aG.bytes);
ge_p3_tobytes(aG.bytes, &point);
return aG;
}
*/
//does a * G where a is a scalar and G is the curve basepoint
func ScalarmultBase(a Key) (aG Key) {
reduce32copy := a
ScReduce32(&reduce32copy)
point := new(ExtendedGroupElement)
GeScalarMultBase(point, &a)
point.ToBytes(&aG)
return aG
}
// generates a key which can be used as private key or mask
// this function is similiar to RandomScalar except for reduce32, TODO can we merge both
func skGen() Key {
skey := RandomScalar()
ScReduce32(skey)
return *skey
}
func (k *Key) ToExtended() (result *ExtendedGroupElement) {
result = new(ExtendedGroupElement)
result.FromBytes(k)
return
}
// bothe the function resturn identity of the ed25519 curve
func identity() (result *Key) {
result = new(Key)
result[0] = 1
return
}
func CurveIdentity() (result Key) {
result = Identity
return result
}
func CurveOrder() (result Key) {
result = L
return result
}
// convert a uint64 to a scalar
func d2h(val uint64) (result *Key) {
result = new(Key)
for i := 0; val > 0; i++ {
result[i] = byte(val & 0xFF)
val /= 256
}
return
}
func HashToScalar(data ...[]byte) (result *Key) {
result = new(Key)
*result = Key(Keccak256(data...))
ScReduce32(result)
return
}
// does a * P where a is a scalar and P is an arbitrary point
func ScalarMultKey(Point *Key, scalar *Key) (result *Key) {
P := new(ExtendedGroupElement)
P.FromBytes(Point)
resultPoint := new(ProjectiveGroupElement)
GeScalarMult(resultPoint, scalar, P)
result = new(Key)
resultPoint.ToBytes(result)
return
}
// multiply a scalar by H (second curve point of Pedersen Commitment)
func ScalarMultH(scalar *Key) (result *Key) {
h := new(ExtendedGroupElement)
h.FromBytes(&H)
resultPoint := new(ProjectiveGroupElement)
GeScalarMult(resultPoint, scalar, h)
result = new(Key)
resultPoint.ToBytes(result)
return
}
// add two points together
func AddKeys(sum, k1, k2 *Key) {
a := k1.ToExtended()
b := new(CachedGroupElement)
k2.ToExtended().ToCached(b)
c := new(CompletedGroupElement)
geAdd(c, a, b)
tmp := new(ExtendedGroupElement)
c.ToExtended(tmp)
tmp.ToBytes(sum)
return
}
// compute a*G + b*B
func AddKeys2(result, a, b, B *Key) {
BPoint := B.ToExtended()
RPoint := new(ProjectiveGroupElement)
GeDoubleScalarMultVartime(RPoint, b, BPoint, a)
RPoint.ToBytes(result)
return
}
//addKeys3
//aAbB = a*A + b*B where a, b are scalars, A, B are curve points
//B must be input after applying "precomp"
func AddKeys3(result *Key, a *Key, A *Key, b *Key, B_Precomputed *[8]CachedGroupElement) {
A_Point := new(ExtendedGroupElement)
A_Point.FromBytes(A)
result_projective := new(ProjectiveGroupElement)
GeDoubleScalarMultPrecompVartime(result_projective, a, A_Point, b, B_Precomputed)
result_projective.ToBytes(result)
}
// subtract two points A - B
func SubKeys(diff, k1, k2 *Key) {
a := k1.ToExtended()
b := new(CachedGroupElement)
k2.ToExtended().ToCached(b)
c := new(CompletedGroupElement)
geSub(c, a, b)
tmp := new(ExtendedGroupElement)
c.ToExtended(tmp)
tmp.ToBytes(diff)
return
}
// this gives you a commitment from an amount
// this is used to convert tx fee or miner tx amount to commitment
func Commitment_From_Amount(amount uint64) Key {
return *(ScalarMultH(d2h(amount)))
}
// this is used to convert miner tx commitment to mask
// equivalent to rctOps.cpp zeroCommit
func ZeroCommitment_From_Amount(amount uint64) Key {
mask := *(identity())
mask = ScalarmultBase(mask)
am := d2h(amount)
bH := ScalarMultH(am)
AddKeys(&mask, &mask, bH)
return mask
}
// zero fill the key
func Sc_0(k *Key) {
for i := 0; i < 32; i++ {
k[i] = 0
}
}
// RandomPubKey takes a random scalar, interprets it as a point on the curve
// remember the low order bug and do more auditing of the entire thing
func RandomPubKey() (result *Key) {
result = new(Key)
p3 := new(ExtendedGroupElement)
var p1 ProjectiveGroupElement
var p2 CompletedGroupElement
h := RandomScalar()
p1.FromBytes(h)
GeMul8(&p2, &p1)
p2.ToExtended(p3)
p3.ToBytes(result)
return
}
// this is the main key derivation function and is the crux
// when deriving keys in the case user A wants to send DERO to another user B ( this is outgoing case)
// public key is B's view key
// private keys is TX private key
// if user B wants to derive key, he needs to ( this is incoming case )
// public key is TX public key
// private is B's private keys
// HOPE the above is clean and clear
func KeyDerivation(pub *Key, priv *Key) (KeyDerivation Key) {
var point ExtendedGroupElement
var point2 ProjectiveGroupElement
var point3 CompletedGroupElement
if !priv.Private_Key_Valid() {
panic("Invalid private key.")
}
tmp := *pub
if !point.FromBytes(&tmp) {
panic("Invalid public key.")
}
tmp = *priv
GeScalarMult(&point2, &tmp, &point)
GeMul8(&point3, &point2)
point3.ToProjective(&point2)
point2.ToBytes(&tmp)
return tmp
}
// the origincal c implementation needs to be checked for varint overflow
// we also need to check the compatibility of golang varint with cryptonote implemented varint
// outputIndex is the position of output within that specific transaction
func (k *Key) KeyDerivationToScalar(outputIndex uint64) (scalar *Key) {
tmp := make([]byte, 12, 12)
length := binary.PutUvarint(tmp, outputIndex)
tmp = tmp[:length]
var buf bytes.Buffer
buf.Write(k[:])
buf.Write(tmp)
scalar = HashToScalar(buf.Bytes())
return
}
// generate ephermal keys from a key derivation
// base key is the B's public spend key or A's private spend key
// outputIndex is the position of output within that specific transaction
func (kd *Key) KeyDerivation_To_PublicKey(outputIndex uint64, baseKey Key) Key {
var point1, point2 ExtendedGroupElement
var point3 CachedGroupElement
var point4 CompletedGroupElement
var point5 ProjectiveGroupElement
tmp := baseKey
if !point1.FromBytes(&tmp) {
panic("Invalid public key.")
}
scalar := kd.KeyDerivationToScalar(outputIndex)
GeScalarMultBase(&point2, scalar)
point2.ToCached(&point3)
geAdd(&point4, &point1, &point3)
point4.ToProjective(&point5)
point5.ToBytes(&tmp)
return tmp
}
// generate ephermal keys from a key derivation
// base key is the A's private spend key
// outputIndex is the position of output within that specific transaction
func (kd *Key) KeyDerivation_To_PrivateKey(outputIndex uint64, baseKey Key) Key {
if !baseKey.Private_Key_Valid() {
panic("Invalid private key.")
}
scalar := kd.KeyDerivationToScalar(outputIndex)
tmp := baseKey
ScAdd(&tmp, &tmp, scalar)
return tmp
}
// NewKeyImage creates a new KeyImage from the given public and private keys.
// The keys are usually the ephemeral keys derived using KeyDerivation.
func GenerateKeyImage(pub Key, private Key) Key {
var proj ProjectiveGroupElement
ext := pub.HashToEC()
GeScalarMult(&proj, &private, ext)
var ki Key
proj.ToBytes(&ki)
return ki
}

+ 163
- 0
crypto/public_private_test.go

@ -0,0 +1,163 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package crypto
//import "fmt"
import "testing"
// these test were orignally written for mnemonics, but they can be used here also
func Test_Public_Private_Key(t *testing.T) {
tests := []struct {
name string
seed string
spend_key_secret string
spend_key_public string
view_key_secret string
view_key_public string
Address string
}{
{
name: "English",
seed: "sequence atlas unveil summon pebbles tuesday beer rudely snake rockets different fuselage woven tagged bested dented vegan hover rapid fawns obvious muppet randomly seasons randomly",
spend_key_secret: "b0ef6bd527b9b23b9ceef70dc8b4cd1ee83ca14541964e764ad23f5151204f0f",
spend_key_public: "7d996b0f2db6dbb5f2a086211f2399a4a7479b2c911af307fdc3f7f61a88cb0e",
view_key_secret: "42ba20adb337e5eca797565be11c9adb0a8bef8c830bccc2df712535d3b8f608",
view_key_public: "1c06bcac7082f73af10460b5f2849aded79374b2fbdaae5d9384b9b6514fddcb",
Address: "dETocsF4EuzXaxLNbDLLWi6xNEzzBJ2He5WSf7He8peuPt4nTyakAFyNuXqrHAGQt1PBSBonCRRj8daUtF7TPXFW42YQkxUQzg",
},
{
name: "Deutsch",
seed: "Dekade Spagat Bereich Radclub Yeti Dialekt Unimog Nomade Anlage Hirte Besitz Märzluft Krabbe Nabel Halsader Chefarzt Hering tauchen Neuerung Reifen Umgang Hürde Alchimie Amnesie Reifen",
spend_key_secret: "a00b3c431e0037426f12b255aaca918863c8bbc690ff3765564bcc1de7fbb303",
spend_key_public: "6f6d202f715d23ff4034a42298fd7b36431dbbfe8559df642911a9c3143ab802",
view_key_secret: "eb2e288ac34e8d4f51cf73b8fda5240c2f3a25f72f4e7b4ac33f33fdc6602300",
view_key_public: "ec9769a6fc9a10a474ba27bb62a58cb55e51aca4107b3daa613c054e4a104d75",
Address: "dETobGVx1rYGaagDmPbfGjjQ5zeVkHXDeG2ssGnyrWgbApeTgRHhPJBSmdAj76XJFKUh3FtNv7fjMMcbGsLnms8V1cqG9Euc5i",
},
{
name: "Español",
seed: "perfil lujo faja puma favor pedir detalle doble carbón neón paella cuarto ánimo cuento conga correr dental moneda león donar entero logro realidad acceso doble",
spend_key_secret: "4f1101c4cc6adc6e6a63acde4e71fd76dc4471fa54769866d5e80a0a3d53d00c",
spend_key_public: "7f28c0b9c5e59fb57a6c4171f6b19faa369bd50c53b792fcdf2402369ded26a7",
view_key_secret: "2de547b9fa3be9db08871d3964027a8f0d8d9c36755257841ba838cfff9fd60a",
view_key_public: "caf4787a2eb8aa94e11a5a7ac912daa820a8148ea175b03a13d4322adab0c33f",
Address: "dETod3T65GgfQe4xkLfu2mWiAzdR6ZRPgXhuAdJqKRUpgffP7dP3C5BXtVhPTwLJZE49uhjBDBkLxLgj3835HxiM7hWoS7trc1",
},
{
name: "Français",
seed: "lisser onctueux pierre trace flair riche machine ordre soir nougat talon balle biceps crier trame tenu gorge cuisine taverne presque laque argent roche secte ordre",
spend_key_secret: "340ed50ef73ba172e2fef23dc9f60e314f609bb7692d22d59f3938c391570b0a",
spend_key_public: "1b2e329fb7fbf1e3d93a30d66e72f13e19addc49ece84839bf2772d685b1bf20",
view_key_secret: "415068b05bfe34ee250b1b0fb0847a7cef7bc1e99ab407dedcf779348097210b",
view_key_public: "a7d037f5f73677c4d1ba32559238886c9011d682121946cf06f9bb59efe75862",
Address: "dEToRmE1GKxj9BVmA46whoLE5vKNnBH6BfrRoaoGLig4WjN9WHF3FCJA7QZwkkGP1KATSXC7cLB9s5EDT5Xfczdk9mV1pUkkUg",
},
{
name: "Italiano",
seed: "sospiro uomo sommario orecchio muscolo testa avido sponda mutande levare lamento frumento volpe zainetto ammirare stufa convegno patente salto venire pianeta marinaio minuto moneta moneta",
spend_key_secret: "21cb90e631866952954cdcba042a3ae90407c40c052cc067226df0b454933502",
spend_key_public: "540850fa07de29317467980349436266652e1a0d4ba9b758568428a5881a6e4a",
view_key_secret: "a106482cc83587c3b39f152ddfa0a447a7647b7977deb400e56166fa7fcc9c0a",
view_key_public: "e076d540a85fb63fdb417304effa0541de65b80883b7b773b5d736a7face10dc",
Address: "dEToYBF9F58eAEsRFgQjaYCGiM1ngwjiSVPTfH6c1A5D5RQuWLjg7cBH1XUaQnY9v6ipWigbhHQN6XjHK6yXdUws8ovPF3F19g",
},
{
name: "Nederlands",
seed: "veto hobo tolvrij cricket somber omaans lourdes kokhals ionisch lipman freon neptunus zimmerman rijbaan wisgerhof oudachtig nerd walraven ruis gevecht foolen onheilig rugnummer russchen cricket",
spend_key_secret: "921cbd7640df5fd12effb8f4269c5a47bac0ef3f75a0c25aa9f174f589801102",
spend_key_public: "f136d2467e0e1826218b83d148374cd215358d1fe6951eab0b6046e632170072",
view_key_secret: "ff10ba6ee19a563b60ac8ab5d94916993a1ff05c644c3f73056c91edd1423b06",
view_key_public: "7506289e53bcfaee88ce5ff5a83d2818d066db2b8d776a15808e5c3fd9a49cde",
Address: "dEToqunYRNu3MjViW649P5AFUquDmjZW5RwedfYZ6xbT4r9TKMQVk34YcLzXmSx4CPBEJARk23ZKzLyUDJMAzJdN7EovWv3GRd",
},
{
name: "Português",
seed: "guloso caatinga enunciar newtoniano aprumo ilogismo vazio gibi imovel mixuruca bauxita paludismo unanimidade zumbi vozes roer anzol leonardo roer ucraniano elmo paete susto taco imovel",
spend_key_secret: "92da2722c7138e65559973131fd2c69b4a0ae4faf0e12b7abe096d5870d6a700",
spend_key_public: "f2daf0540863ae830c6f994fc467900f77dfac153f36e84e9e0eaa074333a3e9",
view_key_secret: "2de03327764d8d8fdb210560ce3e78b6698023ea9993a104afccf34495a82506",
view_key_public: "2e0db07e7ea17fd49a2a92d7ca5071445033c0107f7d4f5adb9cb063b7aab7ea",
Address: "dERopX3LiCoHg3AFLgZB5dJKgvLESnnqLABfvPAM4u869dya9oocJGVU1kG8wQjC25ETPmRyMKw98MxfVwqxbmdY7UEGsR2czw",
},
{
name: "русский язык",
seed: "шорох рента увлекать пешеход гонка сеять пчела ваза апатия пишущий готовый вибрация юбка здоровье машина штука охрана доза рынок клоун рецепт отпуск шестерка эволюция вибрация",
spend_key_secret: "3d0fb729be695b865c073eed68ee91f06d429a27f8eaaaa6a99f954edbef8406",
spend_key_public: "c564b0e4d2992b534f796d70d38d283e3fb53cee717ecd1aad1156e2b79abc85",
view_key_secret: "7c048a8c4f9b1aaba092f5cbc07bded9bfe35fcad7ce46634639d042011b8b04",
view_key_public: "8d9f057765ab73b2ae890c5073737ba009539c8b4746a5e58e74a6cb7150a8c2",
Address: "dERojPZ7WjBScw9H8PS6oCQcQJBXJaQdNND8ZYbYBr2SSt8wzG8HFg8VgJKcsDonhYLKL5Q71UNWACpNiaESzsJx44HUmJzaWW",
},
{
name: "日本語",
seed: "かわく ねまき けもの せいげん ためる にんめい てあみ にりんしゃ さわやか えらい うちき けいかく あたる せっきゃく ずっしり かいよう おおや てらす くれる ばかり なこうど たいうん そまつ たいえき せいげん",
spend_key_secret: "e12da07065554a32ac798396f74dbb35557164f9f39291a3f95705e62e0d7703",
spend_key_public: "09cc0d2adecd40f1118dffce60d1f5d6876ed898ef9360e867bc1e52df36b6fb",
view_key_secret: "90346fc93565c41686eb23fe4fae22a89e59f2ea14d0ba8ad3b16a99ebd80e0b",
view_key_public: "982046c49edc082df0e44a739b831a7c0a325766f9c4fa09fbf8c984a8c6bc06",
Address: "dERoNDzRBZfbLDdeoKD8Zdc7svU36AKPtReksucYRpy4A9oWVcc5dFsdoaxnS7ddmtNvsL5w1eWkYZwvQqApAg8X8XomwZSLws",
},
{
name: "简体中文 (中国)",
seed: "启 写 输 苯 加 担 乳 代 集 预 懂 均 倒 革 熟 载 隆 台 幸 谋 轮 抚 扩 急 输",
spend_key_secret: "3bfd99190f28bd7830b3631cfa514176fc24e88281fe056ce447a5a7fcdc9a02",
spend_key_public: "f27221193c3ab0709009e2225578ff93d86efc178ebc0b482e8d9ec7e741df40",
view_key_secret: "1786f5656bc093a06d5064a80bb891e2e1873699da5e3b63bb16af2bc5563b0c",
view_key_public: "976d8c38f15220a3ee33724c3eb5315589b41e7b2f4b0ee2be04e92edae94418",
Address: "dERopUMxPjhApMpS4vt2B6MEqTpvQbZo3YTGFr7MoabYC23RE7DvTQCEjju9jXHfwBXJoBfHaCVupDZAAgZpLaY99qhsXcCFmg",
},
{
name: "Esperanto",
seed: "amrakonto facila vibri obtuza gondolo membro alkoholo oferti ciumi reinspekti azteka kupro gombo keglo dugongo diino hemisfero sume servilo bambuo sekretario alta diurno duloka hemisfero",
spend_key_secret: "61abd2a5625a95371882117d8652e0735779b7b535008c73d65735b9477b1105",
spend_key_public: "74484fccc824cecdb0a9e69a163938f5d075fcf4d649444e86187cde130b2f04",
view_key_secret: "ba6202a8b877b6c58eb7239d9a23166202ae454a9c98de74d29ba593782ce20c",
view_key_public: "22437d58b154e9b5f35526dbfd6d6e71769103536de248eea98df7209de9759b",
Address: "dERoaEnz1jm7A5kv9xFxgdAa8Y7SCqepmDFnEo4Rkwe22sVjoBThDweFCmBjkJMLSQKJd4soX6wBierFKbDTh1SL9r8XY829pb",
},
}
for _, test := range tests {
spend_key_secret := HexToKey(test.spend_key_secret)
spend_key_public := HexToKey(test.spend_key_public)
if spend_key_public != *(spend_key_secret.PublicKey()) {
t.Errorf("%s key generation testing failed ", test.name)
}
view_key_secret := HexToKey(test.view_key_secret)
view_key_public := HexToKey(test.view_key_public)
if view_key_public != *(view_key_secret.PublicKey()) {
t.Errorf("%s key generation testing failed for spend key ", test.name)
}
}
}

+ 90
- 0
crypto/ringct/LICENSE

@ -0,0 +1,90 @@
RESEARCH LICENSE
Version 1.1.2
I. DEFINITIONS.
"Licensee " means You and any other party that has entered into and has in effect a version of this License.
“Licensor” means DERO PROJECT(GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8) and its successors and assignees.
"Modifications" means any (a) change or addition to the Technology or (b) new source or object code implementing any portion of the Technology.
"Research Use" means research, evaluation, or development for the purpose of advancing knowledge, teaching, learning, or customizing the Technology for personal use. Research Use expressly excludes use or distribution for direct or indirect commercial (including strategic) gain or advantage.
"Technology" means the source code, object code and specifications of the technology made available by Licensor pursuant to this License.
"Technology Site" means the website designated by Licensor for accessing the Technology.
"You" means the individual executing this License or the legal entity or entities represented by the individual executing this License.
II. PURPOSE.
Licensor is licensing the Technology under this Research License (the "License") to promote research, education, innovation, and development using the Technology.
COMMERCIAL USE AND DISTRIBUTION OF TECHNOLOGY AND MODIFICATIONS IS PERMITTED ONLY UNDER AN APPROPRIATE COMMERCIAL USE LICENSE AVAILABLE FROM LICENSOR AT <url>.
III. RESEARCH USE RIGHTS.
A. Subject to the conditions contained herein, Licensor grants to You a non-exclusive, non-transferable, worldwide, and royalty-free license to do the following for Your Research Use only:
1. reproduce, create Modifications of, and use the Technology alone, or with Modifications;
2. share source code of the Technology alone, or with Modifications, with other Licensees;
3. distribute object code of the Technology, alone, or with Modifications, to any third parties for Research Use only, under a license of Your choice that is consistent with this License; and
4. publish papers and books discussing the Technology which may include relevant excerpts that do not in the aggregate constitute a significant portion of the Technology.
B. Residual Rights. You may use any information in intangible form that you remember after accessing the Technology, except when such use violates Licensor's copyrights or patent rights.
C. No Implied Licenses. Other than the rights granted herein, Licensor retains all rights, title, and interest in Technology , and You retain all rights, title, and interest in Your Modifications and associated specifications, subject to the terms of this License.
D. Open Source Licenses. Portions of the Technology may be provided with notices and open source licenses from open source communities and third parties that govern the use of those portions, and any licenses granted hereunder do not alter any rights and obligations you may have under such open source licenses, however, the disclaimer of warranty and limitation of liability provisions in this License will apply to all Technology in this distribution.
IV. INTELLECTUAL PROPERTY REQUIREMENTS
As a condition to Your License, You agree to comply with the following restrictions and responsibilities:
A. License and Copyright Notices. You must include a copy of this License in a Readme file for any Technology or Modifications you distribute. You must also include the following statement, "Use and distribution of this technology is subject to the Java Research License included herein", (a) once prominently in the source code tree and/or specifications for Your source code distributions, and (b) once in the same file as Your copyright or proprietary notices for Your binary code distributions. You must cause any files containing Your Modification to carry prominent notice stating that You changed the files. You must not remove or alter any copyright or other proprietary notices in the Technology.
B. Licensee Exchanges. Any Technology and Modifications You receive from any Licensee are governed by this License.
V. GENERAL TERMS.
A. Disclaimer Of Warranties.
TECHNOLOGY IS PROVIDED "AS IS", WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT ANY SUCH TECHNOLOGY IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING OF THIRD PARTY RIGHTS. YOU AGREE THAT YOU BEAR THE ENTIRE RISK IN CONNECTION WITH YOUR USE AND DISTRIBUTION OF ANY AND ALL TECHNOLOGY UNDER THIS LICENSE.
B. Infringement; Limitation Of Liability.
1. If any portion of, or functionality implemented by, the Technology becomes the subject of a claim or threatened claim of infringement ("Affected Materials"), Licensor may, in its unrestricted discretion, suspend Your rights to use and distribute the Affected Materials under this License. Such suspension of rights will be effective immediately upon Licensor's posting of notice of suspension on the Technology Site.
2. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES IN CONNECTION WITH OR ARISING OUT OF THIS LICENSE (INCLUDING, WITHOUT LIMITATION, LOSS OF PROFITS, USE, DATA, OR ECONOMIC ADVANTAGE OF ANY SORT), HOWEVER IT ARISES AND ON ANY THEORY OF LIABILITY (including negligence), WHETHER OR NOT LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. LIABILITY UNDER THIS SECTION V.B.2 SHALL BE SO LIMITED AND EXCLUDED, NOTWITHSTANDING FAILURE OF THE ESSENTIAL PURPOSE OF ANY REMEDY.
C. Termination.
1. You may terminate this License at any time by notifying Licensor in writing.
2. All Your rights will terminate under this License if You fail to comply with any of its material terms or conditions and do not cure such failure within thirty (30) days after becoming aware of such noncompliance.
3. Upon termination, You must discontinue all uses and distribution of the Technology , and all provisions of this Section V shall survive termination.
D. Miscellaneous.
1. Trademark. You agree to comply with Licensor's Trademark & Logo Usage Requirements, if any and as modified from time to time, available at the Technology Site. Except as expressly provided in this License, You are granted no rights in or to any Licensor's trademarks now or hereafter used or licensed by Licensor.
2. Integration. This License represents the complete agreement of the parties concerning the subject matter hereof.
3. Severability. If any provision of this License is held unenforceable, such provision shall be reformed to the extent necessary to make it enforceable unless to do so would defeat the intent of the parties, in which case, this License shall terminate.
4. Governing Law. This License is governed by the laws of the United States and the State of California, as applied to contracts entered into and performed in California between California residents. In no event shall this License be construed against the drafter.
5. Export Control. You agree to comply with the U.S. export controlsand trade laws of other countries that apply to Technology and Modifications.
READ ALL THE TERMS OF THIS LICENSE CAREFULLY BEFORE ACCEPTING.
BY CLICKING ON THE YES BUTTON BELOW OR USING THE TECHNOLOGY, YOU ARE ACCEPTING AND AGREEING TO ABIDE BY THE TERMS AND CONDITIONS OF THIS LICENSE. YOU MUST BE AT LEAST 18 YEARS OF AGE AND OTHERWISE COMPETENT TO ENTER INTO CONTRACTS.
IF YOU DO NOT MEET THESE CRITERIA, OR YOU DO NOT AGREE TO ANY OF THE TERMS OF THIS LICENSE, DO NOT USE THIS SOFTWARE IN ANY FORM.

+ 25
- 9
crypto/ringct/basic.go

@ -1,3 +1,19 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ringct package ringct
import "encoding/hex" import "encoding/hex"
@ -7,27 +23,27 @@ import "github.com/deroproject/derosuite/crypto"
// a copy of these functions exists in the crypto package also // a copy of these functions exists in the crypto package also
func HexToKey(h string) (result Key) { func HexToKey(h string) (result Key) {
byteSlice, _ := hex.DecodeString(h) byteSlice, _ := hex.DecodeString(h)
if len(byteSlice) != 32 {
panic("Incorrect key size")
}
if len(byteSlice) != 32 {
panic("Incorrect key size")
}
copy(result[:], byteSlice) copy(result[:], byteSlice)
return return
} }
func HexToHash(h string) (result crypto.Hash) { func HexToHash(h string) (result crypto.Hash) {
byteSlice, _ := hex.DecodeString(h) byteSlice, _ := hex.DecodeString(h)
if len(byteSlice) != 32 {
panic("Incorrect key size")
}
if len(byteSlice) != 32 {
panic("Incorrect key size")
}
copy(result[:], byteSlice) copy(result[:], byteSlice)
return return
} }
// zero fill the key // zero fill the key
func Sc_0(k *Key) { func Sc_0(k *Key) {
for i:=0; i < 32;i++{
k[i]=0
}
for i := 0; i < 32; i++ {
k[i] = 0
}
} }
// RandomPubKey takes a random scalar, interprets it as a point on the curve // RandomPubKey takes a random scalar, interprets it as a point on the curve

+ 19
- 2
crypto/ringct/const.go

@ -1,10 +1,27 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ringct package ringct
// Zero, Identity and L?
// Zero, Identity and L
var Zero = Key{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} var Zero = Key{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
var Identity = Key{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} var Identity = Key{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
// this is the curve order of ed25519
var L = Key{0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10} var L = Key{0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10}
// The other basepoint for use in Pedersen Commitments, which is used for // The other basepoint for use in Pedersen Commitments, which is used for
@ -12,6 +29,7 @@ var L = Key{0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0x
// H = G.HashToEC(), where G is the basepoint basically H = toPoint(cn_fast_hash(G)) // H = G.HashToEC(), where G is the basepoint basically H = toPoint(cn_fast_hash(G))
var H = Key{0x8b, 0x65, 0x59, 0x70, 0x15, 0x37, 0x99, 0xaf, 0x2a, 0xea, 0xdc, 0x9f, 0xf1, 0xad, 0xd0, 0xea, 0x6c, 0x72, 0x51, 0xd5, 0x41, 0x54, 0xcf, 0xa9, 0x2c, 0x17, 0x3a, 0x0d, 0xd3, 0x9c, 0x1f, 0x94} var H = Key{0x8b, 0x65, 0x59, 0x70, 0x15, 0x37, 0x99, 0xaf, 0x2a, 0xea, 0xdc, 0x9f, 0xf1, 0xad, 0xd0, 0xea, 0x6c, 0x72, 0x51, 0xd5, 0x41, 0x54, 0xcf, 0xa9, 0x2c, 0x17, 0x3a, 0x0d, 0xd3, 0x9c, 0x1f, 0x94}
// much of this will be useless after bullet-proofs
// H2 is an array of Keys H, 2H, 4H, 8H, ..., 2^64H // H2 is an array of Keys H, 2H, 4H, 8H, ..., 2^64H
// This is used for the range proofG // This is used for the range proofG
var H2 = Key64{ var H2 = Key64{
@ -97,7 +115,6 @@ var A = FieldElement{
486662, 0, 0, 0, 0, 0, 0, 0, 0, 0, 486662, 0, 0, 0, 0, 0, 0, 0, 0, 0,
} }
// precomputed elements for speeding up computations // precomputed elements for speeding up computations
var bi = [8]PreComputedGroupElement{ var bi = [8]PreComputedGroupElement{
{ {

+ 15
- 0
crypto/ringct/edwards25519.go

@ -1,3 +1,18 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Copyright 2013 The Go Authors. All rights reserved. // Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style

+ 16
- 0
crypto/ringct/edwards25519_test.go

@ -1,3 +1,19 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ringct package ringct
import ( import (

+ 103
- 17
crypto/ringct/key.go

@ -1,19 +1,40 @@
package ringct
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ringct
import "io" import "io"
import "fmt"
import "crypto/rand" import "crypto/rand"
import "github.com/deroproject/derosuite/crypto" import "github.com/deroproject/derosuite/crypto"
const KeyLength = 32 const KeyLength = 32
// Key can be a Scalar or a Point // Key can be a Scalar or a Point
type Key [KeyLength]byte type Key [KeyLength]byte
func (k Key) MarshalText() ([]byte, error) {
return []byte(fmt.Sprintf("%x", k[:])), nil
}
func (k Key) String() string {
return fmt.Sprintf("%x", k[:])
}
func (p *Key) FromBytes(b [KeyLength]byte) { func (p *Key) FromBytes(b [KeyLength]byte) {
*p = b *p = b
} }
@ -43,6 +64,11 @@ func (p *Key) HashToEC() (result *ExtendedGroupElement) {
return return
} }
func (p *Key) HashToPoint() (result Key) {
extended := p.HashToEC()
extended.ToBytes(&result)
return
}
func RandomScalar() (result *Key) { func RandomScalar() (result *Key) {
result = new(Key) result = new(Key)
var reduceFrom [KeyLength * 2]byte var reduceFrom [KeyLength * 2]byte
@ -78,38 +104,47 @@ func ParseKey(buf io.Reader) (result Key, err error) {
ge_p3_tobytes(aG.bytes, &point); ge_p3_tobytes(aG.bytes, &point);
return aG; return aG;
} }
*/
*/
//does a * G where a is a scalar and G is the curve basepoint //does a * G where a is a scalar and G is the curve basepoint
func ScalarmultBase(a Key) (aG Key){
reduce32copy := a
ScReduce32(&reduce32copy)
point := new(ExtendedGroupElement)
GeScalarMultBase(point, &a)
point.ToBytes(&aG)
return aG
}
func ScalarmultBase(a Key) (aG Key) {
reduce32copy := a
ScReduce32(&reduce32copy)
point := new(ExtendedGroupElement)
GeScalarMultBase(point, &a)
point.ToBytes(&aG)
return aG
}
// generates a key which can be used as private key or mask // generates a key which can be used as private key or mask
// this function is similiar to RandomScalar except for reduce32, TODO can we merge both // this function is similiar to RandomScalar except for reduce32, TODO can we merge both
func skGen() Key { func skGen() Key {
skey := RandomScalar()
ScReduce32(skey)
return *skey
skey := RandomScalar()
ScReduce32(skey)
return *skey
} }
func (k *Key) ToExtended() (result *ExtendedGroupElement) { func (k *Key) ToExtended() (result *ExtendedGroupElement) {
result = new(ExtendedGroupElement) result = new(ExtendedGroupElement)
result.FromBytes(k) result.FromBytes(k)
return return
} }
// bothe the function resturn identity of the ed25519 curve
func identity() (result *Key) { func identity() (result *Key) {
result = new(Key) result = new(Key)
result[0] = 1 result[0] = 1
return return
} }
func CurveIdentity() (result Key) {
result = Identity
return result
}
func CurveOrder() (result Key) {
result = L
return result
}
// convert a uint64 to a scalar // convert a uint64 to a scalar
func d2h(val uint64) (result *Key) { func d2h(val uint64) (result *Key) {
@ -121,6 +156,16 @@ func d2h(val uint64) (result *Key) {
return return
} }
//32 byte key to uint long long
// if the key holds a value > 2^64
// then the value in the first 8 bytes is returned
func h2d(input Key) (value uint64) {
for j := 7; j >= 0; j-- {
value = (value*256 + uint64(input[j]))
}
return value
}
func HashToScalar(data ...[]byte) (result *Key) { func HashToScalar(data ...[]byte) (result *Key) {
result = new(Key) result = new(Key)
*result = Key(crypto.Keccak256(data...)) *result = Key(crypto.Keccak256(data...))
@ -128,6 +173,17 @@ func HashToScalar(data ...[]byte) (result *Key) {
return return
} }
// does a * P where a is a scalar and P is an arbitrary point
func ScalarMultKey(Point *Key, scalar *Key) (result *Key) {
P := new(ExtendedGroupElement)
P.FromBytes(Point)
resultPoint := new(ProjectiveGroupElement)
GeScalarMult(resultPoint, scalar, P)
result = new(Key)
resultPoint.ToBytes(result)
return
}
// multiply a scalar by H (second curve point of Pedersen Commitment) // multiply a scalar by H (second curve point of Pedersen Commitment)
func ScalarMultH(scalar *Key) (result *Key) { func ScalarMultH(scalar *Key) (result *Key) {
h := new(ExtendedGroupElement) h := new(ExtendedGroupElement)
@ -161,6 +217,19 @@ func AddKeys2(result, a, b, B *Key) {
return return
} }
//addKeys3
//aAbB = a*A + b*B where a, b are scalars, A, B are curve points
//B must be input after applying "precomp"
func AddKeys3(result *Key, a *Key, A *Key, b *Key, B_Precomputed *[8]CachedGroupElement) {
A_Point := new(ExtendedGroupElement)
A_Point.FromBytes(A)
result_projective := new(ProjectiveGroupElement)
GeDoubleScalarMultPrecompVartime(result_projective, a, A_Point, b, B_Precomputed)
result_projective.ToBytes(result)
}
// subtract two points A - B // subtract two points A - B
func SubKeys(diff, k1, k2 *Key) { func SubKeys(diff, k1, k2 *Key) {
a := k1.ToExtended() a := k1.ToExtended()
@ -173,3 +242,20 @@ func SubKeys(diff, k1, k2 *Key) {
tmp.ToBytes(diff) tmp.ToBytes(diff)
return return
} }
// this gives you a commitment from an amount
// this is used to convert tx fee or miner tx amount to commitment
func Commitment_From_Amount(amount uint64) Key {
return *(ScalarMultH(d2h(amount)))
}
// this is used to convert miner tx commitment to mask
// equivalent to rctOps.cpp zeroCommit
func ZeroCommitment_From_Amount(amount uint64) Key {
mask := *(identity())
mask = ScalarmultBase(mask)
am := d2h(amount)
bH := ScalarMultH(am)
AddKeys(&mask, &mask, bH)
return mask
}

+ 224
- 30
crypto/ringct/mlsag.go

@ -3,37 +3,231 @@ package ringct
import "fmt" import "fmt"
import "github.com/deroproject/derosuite/crypto" import "github.com/deroproject/derosuite/crypto"
// this file has license pending since it triggers a hard to find golang bug TODO add license after the golang bug is fixed
/* This file implements MLSAG signatures for the transactions */ /* This file implements MLSAG signatures for the transactions */
// get the hash of the transaction which is used to create the mlsag later on, this hash is input to MLSAG
// get the hash of the transaction which is used to create the mlsag later on, this hash is input to MLSAG
// the hash is = hash( message + hash(basehash) + hash(pederson and borromean data)) // the hash is = hash( message + hash(basehash) + hash(pederson and borromean data))
func Get_pre_mlsag_hash(sig *RctSig) (crypto.Hash) {
message_hash := sig.Message
base_hash := crypto.Keccak256(sig.SerializeBase())
fmt.Printf("Message hash %x\n", message_hash)
fmt.Printf("Base hash %x\n", base_hash)
// now join the borromean signature and extract a sig
var other_data []byte
for i := range sig.rangeSigs {
other_data = append(other_data,sig.rangeSigs[i].asig.s0.Serialize()...)
other_data = append(other_data,sig.rangeSigs[i].asig.s1.Serialize()...)
other_data = append(other_data, sig.rangeSigs[i].ci.Serialize()...)
}
other_data_hash := crypto.Keccak256(other_data)
fmt.Printf("other hash %x\n", other_data_hash)
// join all 3 hashes and hash them again to get the data
final_data := append(message_hash[:], base_hash[:]...)
final_data = append(final_data, other_data_hash[:]...)
final_data_hash := crypto.Keccak256(final_data)
fmt.Printf("final_data_hash hash %x\n", other_data_hash)
return final_data_hash
func Get_pre_mlsag_hash(sig *RctSig) crypto.Hash {
message_hash := sig.Message
base_hash := crypto.Keccak256(sig.SerializeBase())
//fmt.Printf("Message hash %s\n", message_hash)
//fmt.Printf("Base hash %s\n", base_hash)
// now join the borromean signature and extract a sig
var other_data []byte
for i := range sig.rangeSigs {
//other_data = append(other_data,sig.rangeSigs[i].asig.s0.Serialize()...)
//other_data = append(other_data,sig.rangeSigs[i].asig.s1.Serialize()...)
//other_data = append(other_data,sig.rangeSigs[i].asig.ee[:]...)
//OR
// other_data = append(other_data, sig.rangeSigs[i].asig.Serialize()...) // serialise borrosig
// other_data = append(other_data, sig.rangeSigs[i].ci.Serialize()...)
// OR
other_data = append(other_data, sig.rangeSigs[i].Serialize()...) // range sig serialise
}
other_data_hash := crypto.Keccak256(other_data)
//fmt.Printf("other hash %s\n", other_data_hash)
// join all 3 hashes and hash them again to get the data
final_data := append(message_hash[:], base_hash[:]...)
final_data = append(final_data, other_data_hash[:]...)
final_data_hash := crypto.Keccak256(final_data)
if DEBUGGING_MODE {
fmt.Printf("final_data_hash hash %s\n", final_data_hash)
}
return final_data_hash
}
//Multilayered Spontaneous Anonymous Group Signatures (MLSAG signatures)
//This is a just slghtly more efficient version than the ones described below
//(will be explained in more detail in Ring Multisig paper
//These are aka MG signatutes in earlier drafts of the ring ct paper
// c.f. http://eprint.iacr.org/2015/1098 section 2.
// keyImageV just does I[i] = xx[i] * Hash(xx[i] * G) for each i
// Gen creates a signature which proves that for some column in the keymatrix "pk"
// the signer knows a secret key for each row in that column
// Ver verifies that the MG sig was created correctly
func MLSAG_Ver(message Key, pk [][]Key, rv *MlsagSig, dsRows int, r *RctSig) (result bool) {
result = false
cols := len(pk)
if cols < 2 {
if DEBUGGING_MODE {
fmt.Printf("RingCT MLSAG_Ver must have cols > 1\n")
}
result = false
return
}
rows := len(pk[0])
if rows < 1 {
if DEBUGGING_MODE {
fmt.Printf("RingCT MLSAG_Ver must have rows > 0\n")
}
result = false
return
}
for i := 0; i < cols; i++ {
if len(pk[i]) != rows {
if DEBUGGING_MODE {
fmt.Printf("RingCT MLSAG_Ver pk matrix not rectangular\n")
}
result = false
return
}
}
if len(rv.II) != dsRows {
if DEBUGGING_MODE {
fmt.Printf("RingCT MLSAG_Ver Bad II size\n")
}
result = false
return
}
if len(rv.ss) != cols {
if DEBUGGING_MODE {
fmt.Printf("RingCT MLSAG_Ver Bad rv.ss size len(rv.ss) = %d cols = %d\n", len(rv.ss), cols)
}
result = false
return
}
for i := 0; i < cols; i++ {
if len(rv.ss[i]) != rows {
if DEBUGGING_MODE {
fmt.Printf("RingCT MLSAG_Ver rv.ss is not rectangular\n")
}
result = false
return
}
}
if dsRows > rows {
if DEBUGGING_MODE {
fmt.Printf("RingCT MLSAG_Ver Bad dsRows value\n")
}
result = false
return
}
for i := 0; i < len(rv.ss); i++ {
for j := 0; j < len(rv.ss[i]); j++ {
if !ScValid(&rv.ss[i][j]) {
if DEBUGGING_MODE {
fmt.Printf("RingCT MLSAG_Ver Bad ss slot\n")
}
result = false
return
}
}
}
if !ScValid(&rv.cc) {
if DEBUGGING_MODE {
fmt.Printf("RingCT MLSAG_Ver Bad r.cc slot\n")
}
result = false
return
}
Ip := make([][8]CachedGroupElement, dsRows, dsRows) // do pre computation of key keyImage
for i := 0; i < dsRows; i++ {
key_image_point := new(ExtendedGroupElement)
key_image_point.FromBytes(&rv.II[i])
GePrecompute(&Ip[i], key_image_point)
}
ndsRows := 3 * dsRows //non Double Spendable Rows (see identity chains paper
toHash := make([]Key, 1+3*dsRows+2*(rows-dsRows), 1+3*dsRows+2*(rows-dsRows))
toHash[0] = message
// golang does NOT allow to use casts without using unsafe, so we can be slow but safe
toHash_bytes := make([]byte, 0, (1+3*dsRows+2*(rows-dsRows))*len(message))
var c Key
c_old := rv.cc
for i := 0; i < cols; i++ {
Sc_0(&c) // zero out c
// BUG BUG BUG
// DERO project has found a go bug
// This bug affects all known golang supported platforms and architectures (arm/386/amd64/...?)
// even the golang 1.10 release candidates are affected ( though tip has not been tested )
//
// if you comment the line below and uncomment similiar line in first loop, the bug triggers for 1 in 20000 RCT full transactions, this means the the entire block chain cannot be verified before the bug fails the crypto
// this bug triggers at high probability when the affected code is executed by multiple goroutines simultaneously
// since the bug is notoriously hard to trigger while execution
// we have figured out an easy way to visibly demonstrate that the bug is present
// if the variables are declared within first loop, second loop is able to access them without declaring them
// this causes random memory to be used during CPU load, causing the transaction to fail since crypto checksums mark it as failure ( TODO detailed analysis)
// this bug may be the source of several other random crash bugs and need to be given a detailed looked
// this may be the source of the follown known but not-understood (cause not found) bugs
// https://github.com/golang/go/issues/15658
// https://github.com/golang/go/issues/20427
// https://github.com/golang/go/issues/22988
// https://github.com/golang/go/issues/20300 and even more
// NOTE: for golang developers, this bug needs to studied and fixed correctly. Since, another bug seems to exists
// which causes constants to flip ( yes consts ). However, we cannot be certain if its the same bug, once this gets quashed, we will test the other one too.
var L, R, Hi Key // comment this line and uncomment similiar line in first loop to trigger BUG
// first loop
for j := 0; j < dsRows; j++ {
//var L, R, Hi Key // uncomment this line to trigger golang compiler BUG ( atleast on linux amd64)
AddKeys2(&L, &rv.ss[i][j], &c_old, &pk[i][j])
Hi = pk[i][j].HashToPoint()
AddKeys3(&R, &rv.ss[i][j], &Hi, &c_old, &Ip[j])
toHash[3*j+1] = pk[i][j]
toHash[3*j+2] = L
toHash[3*j+3] = R
}
//second loop
for j, ii := dsRows, 0; j < rows; j, ii = j+1, ii+1 {
AddKeys2(&L, &rv.ss[i][j], &c_old, &pk[i][j]) // here L is getting used again
toHash[ndsRows+2*ii+1] = pk[i][j]
toHash[ndsRows+2*ii+2] = L
}
toHash_bytes = toHash_bytes[:0] // zero out everything
for k := range toHash {
toHash_bytes = append(toHash_bytes, toHash[k][:]...)
}
c = *(HashToScalar(toHash_bytes)) // hash_to_scalar(toHash);
copy(c_old[:], c[:]) // flipping the args here, will cause all transactions to become valid
}
if DEBUGGING_MODE {
//fmt.Printf("c %x\n",c)
fmt.Printf("c_old %s\n", c_old)
fmt.Printf("rv.ss %s\n", rv.cc)
}
// c = c_old-rv.cc
ScSub(&c, &c_old, &rv.cc)
// if 0 checksum verified, otherwise checksum failed
result = ScIsZero(&c)
if DEBUGGING_MODE {
if result {
fmt.Printf("RingCT MLSAG_Ver Success\n")
} else {
fmt.Printf("RingCT MLSAG_Ver verification failed\n")
}
}
return
} }

+ 36
- 0
crypto/ringct/order_test.go

@ -0,0 +1,36 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ringct
import "testing"
func Test_LowOrder_KeyImage(t *testing.T) {
k_image := HexToKey("04331738293495ffc0b6121d3c4d3b3fd2931ea0768c5f9ddc4df6867411a20d")
curve_order := CurveOrder()
mult_result := ScalarMultKey(&k_image, &curve_order)
if *mult_result != Identity {
t.Errorf("Low order key image Testing failed")
}
// fmt.Printf("identity %s\n", ringct.Identity)
// fmt.Printf("curve_order %s\n", curve_order)
// fmt.Printf("mult_result %s\n", mult_result)
}

+ 123
- 118
crypto/ringct/range.go

@ -1,5 +1,20 @@
package ringct
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ringct
//import "fmt" //import "fmt"
@ -7,66 +22,62 @@ const ATOMS = 64 // 64 bit in the amount field
type bits64 [ATOMS]bool type bits64 [ATOMS]bool
// implementation of d2b from rctTypes.cpp
// lays out the number from lowest bit at pos 0 and highest at bit 63
func d2b_uint64_to_bits(amount uint64) bits64 {
var bits bits64
for i := 0; amount != 0; i++ {
if (amount & 1) == 1 {
bits[i] = true
}
amount = amount >> 1
}
return bits
}
// implementation of d2b from rctTypes.cpp
// lays out the number from lowest bit at pos 0 and highest at bit 63
func d2b_uint64_to_bits(amount uint64)(bits64){
var bits bits64
for i := 0; amount != 0; i++ {
if (amount&1) == 1 {
bits[i] = true
}
amount = amount >> 1
}
return bits
}
//ProveRange and VerifyRange
//ProveRange gives C, and mask such that \sumCi = C
// c.f. http://eprint.iacr.org/2015/1098 section 5.1
// and Ci is a commitment to either 0 or 2^i, i=0,...,63
// thus this proves that "amount" is in [0, 2^64]
// mask is a such that C = aG + bH, and b = amount
//VerifyRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
// this function proves a range using Pedersen commitment and borromean signatures
// implemented in cryptonote rctSigs.cpp
func ProveRange (C *Key, mask *Key, amount uint64) ( *RangeSig){
Sc_0(mask)
copy(C[:], (*identity())[:]) // set C to identity
var ai Key64
var Cih Key64
var sig RangeSig
bits := d2b_uint64_to_bits(amount)
//fmt.Printf("bits %+v\n", bits)
for i := 0; i < ATOMS;i++{
ai[i] = *(RandomScalar()) // grab a random key
// Sc_0(&ai[i]); // make random key zero for tesing puprpose // BUG if line is uncommented
ScReduce32(&ai[i]) // reduce it
// fmt.Printf("ai[%2d] %x\n",i, ai[i])
sig.ci[i] = ScalarmultBase(ai[i])
// fmt.Printf("ci[%2d] %x\n",i, sig.ci[i])
if bits[i] {
AddKeys(&sig.ci[i],&sig.ci[i],&H2[i])
}
SubKeys(&Cih[i],&sig.ci[i],&H2[i])
ScAdd(mask,mask,&ai[i])
AddKeys(C,C,&sig.ci[i])
}
//fmt.Print("C %x\n", *C)
// TODO caculate Borromean signature here
sig.asig = GenerateBorromean(ai, sig.ci, Cih, bits);
return &sig
//ProveRange and VerifyRange
//ProveRange gives C, and mask such that \sumCi = C
// c.f. http://eprint.iacr.org/2015/1098 section 5.1
// and Ci is a commitment to either 0 or 2^i, i=0,...,63
// thus this proves that "amount" is in [0, 2^64]
// mask is a such that C = aG + bH, and b = amount
//VerifyRange verifies that \sum Ci = C and that each Ci is a commitment to 0 or 2^i
// this function proves a range using Pedersen commitment and borromean signatures
// implemented in cryptonote rctSigs.cpp
func ProveRange(C *Key, mask *Key, amount uint64) *RangeSig {
Sc_0(mask)
copy(C[:], (*identity())[:]) // set C to identity
var ai Key64
var Cih Key64
var sig RangeSig
bits := d2b_uint64_to_bits(amount)
//fmt.Printf("bits %+v\n", bits)
for i := 0; i < ATOMS; i++ {
ai[i] = *(RandomScalar()) // grab a random key
// Sc_0(&ai[i]); // make random key zero for tesing puprpose // BUG if line is uncommented
ScReduce32(&ai[i]) // reduce it
// fmt.Printf("ai[%2d] %x\n",i, ai[i])
sig.ci[i] = ScalarmultBase(ai[i])
// fmt.Printf("ci[%2d] %x\n",i, sig.ci[i])
if bits[i] {
AddKeys(&sig.ci[i], &sig.ci[i], &H2[i])
}
SubKeys(&Cih[i], &sig.ci[i], &H2[i])
ScAdd(mask, mask, &ai[i])
AddKeys(C, C, &sig.ci[i])
}
//fmt.Print("C %x\n", *C)
// TODO caculate Borromean signature here
sig.asig = GenerateBorromean(ai, sig.ci, Cih, bits)
return &sig
} }
func VerifyRange(c *Key, as RangeSig) bool { func VerifyRange(c *Key, as RangeSig) bool {
@ -76,9 +87,9 @@ func VerifyRange(c *Key, as RangeSig) bool {
SubKeys(&CiH[i], &as.ci[i], &H2[i]) SubKeys(&CiH[i], &as.ci[i], &H2[i])
AddKeys(tmp, tmp, &as.ci[i]) AddKeys(tmp, tmp, &as.ci[i])
} }
// fmt.Printf("C %x\n", *c)
// fmt.Printf("tmp %x\n", *tmp)
// fmt.Printf("C %x\n", *c)
// fmt.Printf("tmp %x\n", *tmp)
if *c != *tmp { if *c != *tmp {
return false return false
} }
@ -86,61 +97,55 @@ func VerifyRange(c *Key, as RangeSig) bool {
return VerifyBorromean(&as.asig, &as.ci, &CiH) return VerifyBorromean(&as.asig, &as.ci, &CiH)
} }
//Borromean (c.f. gmax/andytoshi's paper) //Borromean (c.f. gmax/andytoshi's paper)
func GenerateBorromean(x Key64, P1 Key64, P2 Key64, indices bits64) (BoroSig){
var bb BoroSig
var alpha Key64
var L [2]Key64
var c Key
var data_bytes []byte
for ii := 0; ii < ATOMS;ii++{
var naught,prime int
if indices[ii]{
naught = 1
}else{
naught = 0
}
prime = (naught+1)%2 // basically it is the inverse of naught
alpha[ii] = skGen() // generate a new random scalar
L[naught][ii] = ScalarmultBase(alpha[ii])
if naught == 0 {
bb.s1[ii] = skGen()
c = *(HashToScalar(L[naught][ii][:]))
AddKeys2(&L[prime][ii], &bb.s1[ii], &c, &P2[ii])
}
// original cryptonote does NOT clear out some unset bytes, verify whether it may be a problem for them
data_bytes = append(data_bytes, L[1][ii][:]...)
}
// take the hash of the L1 keys all 64 of them
// we have been collecting them above
bb.ee = *(HashToScalar(data_bytes));
// fmt.Printf("bb.ee %x\n", bb.ee)
var LL, cc Key
for jj := 0 ; jj < ATOMS;jj++{
if indices[jj] == false {
ScMulSub(&bb.s0[jj], &x[jj], &bb.ee, &alpha[jj])
}else{
bb.s0[jj] = skGen()
AddKeys2(&LL, &bb.s0[jj], &bb.ee, &P1[jj])
cc = *(HashToScalar(LL[:]))
ScMulSub(&bb.s1[jj], &x[jj], &cc, &alpha[jj])
}
}
return bb
}
func GenerateBorromean(x Key64, P1 Key64, P2 Key64, indices bits64) BoroSig {
var bb BoroSig
var alpha Key64
var L [2]Key64
var c Key
var data_bytes []byte
for ii := 0; ii < ATOMS; ii++ {
var naught, prime int
if indices[ii] {
naught = 1
} else {
naught = 0
}
prime = (naught + 1) % 2 // basically it is the inverse of naught
alpha[ii] = skGen() // generate a new random scalar
L[naught][ii] = ScalarmultBase(alpha[ii])
if naught == 0 {
bb.s1[ii] = skGen()
c = *(HashToScalar(L[naught][ii][:]))
AddKeys2(&L[prime][ii], &bb.s1[ii], &c, &P2[ii])
}
// original cryptonote does NOT clear out some unset bytes, verify whether it may be a problem for them
data_bytes = append(data_bytes, L[1][ii][:]...)
}
// take the hash of the L1 keys all 64 of them
// we have been collecting them above
bb.ee = *(HashToScalar(data_bytes))
// fmt.Printf("bb.ee %x\n", bb.ee)
var LL, cc Key
for jj := 0; jj < ATOMS; jj++ {
if indices[jj] == false {
ScMulSub(&bb.s0[jj], &x[jj], &bb.ee, &alpha[jj])
} else {
bb.s0[jj] = skGen()
AddKeys2(&LL, &bb.s0[jj], &bb.ee, &P1[jj])
cc = *(HashToScalar(LL[:]))
ScMulSub(&bb.s1[jj], &x[jj], &cc, &alpha[jj])
}
}
return bb
}
// Verify the Borromean sig // Verify the Borromean sig
func VerifyBorromean(b *BoroSig, p1, p2 *Key64) bool { func VerifyBorromean(b *BoroSig, p1, p2 *Key64) bool {
@ -153,7 +158,7 @@ func VerifyBorromean(b *BoroSig, p1, p2 *Key64) bool {
data = append(data, tmp2[:]...) data = append(data, tmp2[:]...)
} }
computed := HashToScalar(data) computed := HashToScalar(data)
// fmt.Printf("comp %x\n", computed)
// fmt.Printf("comp %x\n", computed)
return *computed == b.ee return *computed == b.ee
} }

+ 28
- 17
crypto/ringct/range_test.go

@ -1,23 +1,34 @@
package ringct
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ringct
import "testing" import "testing"
import "math/rand" import "math/rand"
func Test_Range_and_Borromean_Signature(t *testing.T){
var c,mask Key
for i := 0; i < 50;i++{ // test it 500 times
var amount uint64 = rand.Uint64()
sig := ProveRange(&c,&mask,amount)
if VerifyRange(&c, *sig) == false {
t.Errorf("Range Test failed")
return
}
}
func Test_Range_and_Borromean_Signature(t *testing.T) {
var c, mask Key
for i := 0; i < 50; i++ { // test it 500 times
var amount uint64 = rand.Uint64()
sig := ProveRange(&c, &mask, amount)
if VerifyRange(&c, *sig) == false {
t.Errorf("Range Test failed")
return
}
}
} }

+ 156
- 68
crypto/ringct/ringct.go

@ -1,3 +1,19 @@
// Copyright 2017-2018 DERO Project. All rights reserved.
// Use of this source code in any form is governed by RESEARCH license.
// license can be found in the LICENSE file.
// GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
//
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package ringct package ringct
import "io" import "io"
@ -5,6 +21,9 @@ import "fmt"
import "github.com/deroproject/derosuite/crypto" import "github.com/deroproject/derosuite/crypto"
// enable debuggin mode within ringct
// if true debugging mode enabled
const DEBUGGING_MODE = false
// TODO this package need serious love of atleast few weeks // TODO this package need serious love of atleast few weeks
// but atleast the parser and serdes works // but atleast the parser and serdes works
@ -20,16 +39,15 @@ const (
// Pedersen Commitment is generated from this struct // Pedersen Commitment is generated from this struct
// C = aG + bH where a = mask and b = amount // C = aG + bH where a = mask and b = amount
// senderPk is the one-time public key for ECDH exchange // senderPk is the one-time public key for ECDH exchange
type ecdhTuple struct {
mask Key
amount Key
senderPk Key
type ECdhTuple struct {
Mask Key `msgpack:"M"`
Amount Key `msgpack:"A"`
// senderPk Key
} }
// Range proof commitments // Range proof commitments
type Key64 [64]Key type Key64 [64]Key
// Range Signature // Range Signature
// Essentially data for a Borromean Signature // Essentially data for a Borromean Signature
type RangeSig struct { type RangeSig struct {
@ -46,36 +64,35 @@ type BoroSig struct {
// MLSAG (Multilayered Linkable Spontaneous Anonymous Group) Signature // MLSAG (Multilayered Linkable Spontaneous Anonymous Group) Signature
type MlsagSig struct { type MlsagSig struct {
ss [][]Key
cc Key // this stores the starting point
ss [][]Key
cc Key // this stores the starting point
II []Key // this stores the keyimage, but is taken from the tx,it is NOT serialized II []Key // this stores the keyimage, but is taken from the tx,it is NOT serialized
} }
// Confidential Transaction Keys, mask is Pedersen Commitment // Confidential Transaction Keys, mask is Pedersen Commitment
// most of the time, it holds public keys, except where it holds private keys
// most of the time, it holds public keys, except (transaction making ) where it holds private keys
type CtKey struct { type CtKey struct {
Destination Key // this is the destination and needs to expanded from blockchain
Mask Key // this is the public key mask
Destination Key `msgpack:"D"` // this is the destination and needs to expanded from blockchain
Mask Key `msgpack:"M"` // this is the public key amount/commitment homomorphic mask
} }
// Ring Confidential Signature parts that we have to keep // Ring Confidential Signature parts that we have to keep
type RctSigBase struct { type RctSigBase struct {
sigType uint8 sigType uint8
Message Key // transaction prefix hash
Message Key // transaction prefix hash
MixRing [][]CtKey // this is not serialized MixRing [][]CtKey // this is not serialized
pseudoOuts []Key pseudoOuts []Key
ecdhInfo []ecdhTuple
outPk []CtKey // only mask amount is serialized
ECdhInfo []ECdhTuple
OutPk []CtKey // only mask amount is serialized
txFee uint64 txFee uint64
Txid crypto.Hash // this field is extra and only used for logging purposes to track which txid was at fault
Txid crypto.Hash // this field is extra and only used for logging purposes to track which txid was at fault
} }
// Ring Confidential Signature parts that we can just prune later // Ring Confidential Signature parts that we can just prune later
type RctSigPrunable struct { type RctSigPrunable struct {
rangeSigs []RangeSig rangeSigs []RangeSig
MlsagSigs []MlsagSig
MlsagSigs []MlsagSig // there can be as many mlsagsigs as many vins
} }
// Ring Confidential Signature struct that can verify everything // Ring Confidential Signature struct that can verify everything
@ -84,7 +101,6 @@ type RctSig struct {
RctSigPrunable RctSigPrunable
} }
func (k *Key64) Serialize() (result []byte) { func (k *Key64) Serialize() (result []byte) {
for _, key := range k { for _, key := range k {
result = append(result, key[:]...) result = append(result, key[:]...)
@ -125,11 +141,11 @@ func (r *RctSigBase) SerializeBase() (result []byte) {
result = append(result, input[:]...) result = append(result, input[:]...)
} }
} }
for _, ecdh := range r.ecdhInfo {
result = append(result, ecdh.mask[:]...)
result = append(result, ecdh.amount[:]...)
for _, ecdh := range r.ECdhInfo {
result = append(result, ecdh.Mask[:]...)
result = append(result, ecdh.Amount[:]...)
} }
for _, ctKey := range r.outPk {
for _, ctKey := range r.OutPk {
result = append(result, ctKey.Mask[:]...) result = append(result, ctKey.Mask[:]...)
} }
return return
@ -153,8 +169,7 @@ func (r *RctSig) SerializePrunable() (result []byte) {
return return
} }
func (r *RctSig) Get_Sig_Type() (byte) {
func (r *RctSig) Get_Sig_Type() byte {
return r.sigType return r.sigType
} }
@ -165,8 +180,6 @@ func (r *RctSig) Get_TX_Fee() (result uint64) {
return r.txFee return r.txFee
} }
func (r *RctSig) PrunableHash() (result crypto.Hash) { func (r *RctSig) PrunableHash() (result crypto.Hash) {
if r.sigType == RCTTypeNull { if r.sigType == RCTTypeNull {
return return
@ -175,41 +188,46 @@ func (r *RctSig) PrunableHash() (result crypto.Hash) {
return return
} }
// this is the function which should be used by external world
// if any exceptions occur while handling, we simply return false
// transaction must be expanded before verification
// coinbase transactions are always success, since they are tied to PoW of block
func (r *RctSig) Verify() (result bool) {
result = false
defer func() { // safety so if anything wrong happens, verification fails
if r := recover(); r != nil {
//connection.logger.Fatalf("Recovered while Verify transaction", r)
fmt.Printf("Recovered while Verify transaction")
result = false
}
}()
switch r.sigType {
case RCTTypeNull:
return true /// this is only possible for miner tx
case RCTTypeFull:
return r.VerifyRctFull()
case RCTTypeSimple:
return r.VerifyRctSimple()
default:
return false
}
// this is the function which should be used by external world
func (r *RctSig) Verify() (result bool) {
result = false
defer func() { // safety so if anything wrong happens, verification fails
if r := recover(); r != nil {
//connection.logger.Fatalf("Recovered while Verify transaction", r)
fmt.Printf("Recovered while Verify transaction")
result = false
}}()
switch r.sigType {
case RCTTypeNull: return true /// this is only possible for miner tx
case RCTTypeFull : return r.VerifyRctFull()
case RCTTypeSimple: return r.VerifyRctSimple()
default :
return false
}
return false
// can never reach here
// return false
} }
// Verify a RCTTypeSimple RingCT Signature // Verify a RCTTypeSimple RingCT Signature
func (r *RctSig) VerifyRctSimple() bool { func (r *RctSig) VerifyRctSimple() bool {
sumOutPks := identity() sumOutPks := identity()
for _, ctKey := range r.outPk {
for _, ctKey := range r.OutPk {
AddKeys(sumOutPks, sumOutPks, &ctKey.Mask) AddKeys(sumOutPks, sumOutPks, &ctKey.Mask)
} }
txFeeKey := ScalarMultH(d2h(r.txFee))
AddKeys(sumOutPks, sumOutPks, txFeeKey)
//txFeeKey := ScalarMultH(d2h(r.txFee))
txFeeKey := Commitment_From_Amount(r.txFee)
AddKeys(sumOutPks, sumOutPks, &txFeeKey)
sumPseudoOuts := identity() sumPseudoOuts := identity()
for _, pseudoOut := range r.pseudoOuts { for _, pseudoOut := range r.pseudoOuts {
AddKeys(sumPseudoOuts, sumPseudoOuts, &pseudoOut) AddKeys(sumPseudoOuts, sumPseudoOuts, &pseudoOut)
@ -217,26 +235,22 @@ func (r *RctSig) VerifyRctSimple() bool {
if *sumPseudoOuts != *sumOutPks { if *sumPseudoOuts != *sumOutPks {
return false return false
} }
for i, ctKey := range r.outPk {
for i, ctKey := range r.OutPk {
if !VerifyRange(&ctKey.Mask, r.rangeSigs[i]) { if !VerifyRange(&ctKey.Mask, r.rangeSigs[i]) {
return false return false
} }
} }
// BUG BUG we are not verifying mlsag here, Do it once the core finishes
return true
return r.VerifyRCTSimple_Core()
} }
func (r *RctSig) VerifyRctFull() bool { func (r *RctSig) VerifyRctFull() bool {
for i, ctKey := range r.outPk {
for i, ctKey := range r.OutPk {
if !VerifyRange(&ctKey.Mask, r.rangeSigs[i]) { if !VerifyRange(&ctKey.Mask, r.rangeSigs[i]) {
return false return false
} }
} }
// BUG BUG we are not verifying mlsag here, Do it once the core is finished
return true
return r.VerifyRCTFull_Core()
} }
func ParseCtKey(buf io.Reader) (result CtKey, err error) { func ParseCtKey(buf io.Reader) (result CtKey, err error) {
@ -255,7 +269,6 @@ func ParseKey64(buf io.Reader) (result Key64, err error) {
return return
} }
// parse Borromean signature // parse Borromean signature
func ParseBoroSig(buf io.Reader) (result BoroSig, err error) { func ParseBoroSig(buf io.Reader) (result BoroSig, err error) {
if result.s0, err = ParseKey64(buf); err != nil { if result.s0, err = ParseKey64(buf); err != nil {
@ -295,9 +308,22 @@ func ParseRingCtSignature(buf io.Reader, nInputs, nOutputs, nMixin int) (result
result = r result = r
return return
} }
if r.sigType != RCTTypeFull || r.sigType != RCTTypeSimple {
/* This triggers go vet saying suspect OR
if (r.sigType != RCTTypeFull) || (r.sigType != RCTTypeSimple) {
err = fmt.Errorf("Bad signature Type %d", r.sigType)
return
}*/
switch r.sigType {
case RCTTypeFull:
case RCTTypeSimple:
default:
err = fmt.Errorf("Bad signature Type %d", r.sigType) err = fmt.Errorf("Bad signature Type %d", r.sigType)
return
} }
r.txFee, err = ReadVarInt(buf) r.txFee, err = ReadVarInt(buf)
if err != nil { if err != nil {
return return
@ -316,18 +342,18 @@ func ParseRingCtSignature(buf io.Reader, nInputs, nOutputs, nMixin int) (result
nMg = 1 nMg = 1
nSS = nInputs + 1 nSS = nInputs + 1
} }
r.ecdhInfo = make([]ecdhTuple, nOutputs)
r.ECdhInfo = make([]ECdhTuple, nOutputs)
for i := 0; i < nOutputs; i++ { for i := 0; i < nOutputs; i++ {
if r.ecdhInfo[i].mask, err = ParseKey(buf); err != nil {
if r.ECdhInfo[i].Mask, err = ParseKey(buf); err != nil {
return return
} }
if r.ecdhInfo[i].amount, err = ParseKey(buf); err != nil {
if r.ECdhInfo[i].Amount, err = ParseKey(buf); err != nil {
return return
} }
} }
r.outPk = make([]CtKey, nOutputs)
r.OutPk = make([]CtKey, nOutputs)
for i := 0; i < nOutputs; i++ { for i := 0; i < nOutputs; i++ {
if r.outPk[i], err = ParseCtKey(buf); err != nil {
if r.OutPk[i], err = ParseCtKey(buf); err != nil {
return return
} }
} }
@ -355,3 +381,65 @@ func ParseRingCtSignature(buf io.Reader, nInputs, nOutputs, nMixin int) (result
result = r result = r
return return
} }
/*
//Elliptic Curve Diffie Helman: encodes and decodes the amount b and mask a
// where C= aG + bH
void ecdhEncode(ecdhTuple & unmasked, const key & sharedSec) {
key sharedSec1 = hash_to_scalar(sharedSec);
key sharedSec2 = hash_to_scalar(sharedSec1);
//encode
sc_add(unmasked.mask.bytes, unmasked.mask.bytes, sharedSec1.bytes);
sc_add(unmasked.amount.bytes, unmasked.amount.bytes, sharedSec2.bytes);
}
void ecdhDecode(ecdhTuple & masked, const key & sharedSec) {
key sharedSec1 = hash_to_scalar(sharedSec);
key sharedSec2 = hash_to_scalar(sharedSec1);
//decode
sc_sub(masked.mask.bytes, masked.mask.bytes, sharedSec1.bytes);
sc_sub(masked.amount.bytes, masked.amount.bytes, sharedSec2.bytes);
}
*/
func ecdhEncode(tuple *ECdhTuple, shared_secret Key) {
shared_secret1 := HashToScalar(shared_secret[:])
shared_secret2 := HashToScalar(shared_secret1[:])
// encode
ScAdd(&tuple.Mask, &tuple.Mask, shared_secret1)
ScAdd(&tuple.Amount, &tuple.Amount, shared_secret2)
}
func ecdhDecode(tuple *ECdhTuple, shared_secret Key) {
shared_secret1 := HashToScalar(shared_secret[:])
shared_secret2 := HashToScalar(shared_secret1[:])
// encode
ScSub(&tuple.Mask, &tuple.Mask, shared_secret1)
ScSub(&tuple.Amount, &tuple.Amount, shared_secret2)
}
// decode and verify a previously encrypted tuple
// the keys come in from the wallet
// tuple is the encoded data
// skey is the secret scalar key
// outpk is public key used to verify whether the decode was sucessfull
func Decode_Amount(tuple ECdhTuple, skey Key, outpk Key) (amount uint64, mask Key, result bool) {
var Ctmp Key
ecdhDecode(&tuple, skey) // decode the amounts
// saniity check similiar to original one
// addKeys2(Ctmp, mask, amount, H);
AddKeys2(&Ctmp, &tuple.Mask, &tuple.Amount, &H)
if Ctmp != outpk {
fmt.Printf("warning, amount decoded incorrectly, will be unable to spend")
result = false
return
}
amount = h2d(tuple.Amount)
mask = tuple.Mask
result = true
return
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save