<commit_before>{-# LANGUAGE OverloadedStrings #-}

module Main (
  main
  ) where

import Control.Monad.IO.Class
import Control.Monad.State
import Control.Monad.Trans.Resource
import Data.Bits
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import Data.Time.Clock
import Data.Word
import Network
import Network.Haskoin.Crypto hiding (Address)
import System.Entropy
import System.Environment
import System.IO


import Blockchain.Data.RLP

import Blockchain.BlockChain
import Blockchain.BlockSynchronizer
import Blockchain.Communication
import Blockchain.Constants
import Blockchain.Context
import Blockchain.Data.Address
import Blockchain.Data.BlockDB
import Blockchain.Data.DataDefs
--import Blockchain.Data.SignedTransaction
--import Blockchain.Data.Transaction
import Blockchain.Data.Wire
import Blockchain.Database.MerklePatricia
import Blockchain.DB.CodeDB
import Blockchain.DB.ModifyStateDB
import Blockchain.DBM
import Blockchain.Display
import Blockchain.PeerUrls
--import Blockchain.SampleTransactions
import Blockchain.SHA
--import Blockchain.SigningTools
import Blockchain.Util

--import Debug.Trace


import Crypto.PubKey.ECC.DH
import Crypto.Types.PubKey.ECC
import Crypto.Random
import Data.Maybe
--import qualified Network.Haskoin.Internals as H

import Blockchain.Format

import Blockchain.Frame
import Blockchain.UDP
import Blockchain.RLPx










prvKey::PrvKey
Just prvKey = makePrvKey 0xac3e8ce2ef31c3f45d5da860bcd9aee4b37a05c5a3ddee40dd061620c3dab380

getNextBlock::Block->UTCTime->ContextM Block
getNextBlock b ts = do
  let theCoinbase = prvKey2Address prvKey
  lift $ setStateRoot $ blockDataStateRoot bd
  addToBalance theCoinbase (1500*finney)

  dbs <- lift get

  return Block{
               blockBlockData=testGetNextBlockData $ stateRoot $ stateDB dbs,
               blockReceiptTransactions=[],
               blockBlockUncles=[]
             }
  where
    testGetNextBlockData::SHAPtr->BlockData
    testGetNextBlockData sr =
      BlockData {
        blockDataParentHash=blockHash b,
        blockDataUnclesHash=hash $ B.pack [0xc0],
        blockDataCoinbase=prvKey2Address prvKey,
        blockDataStateRoot = sr,
        blockDataTransactionsRoot = emptyTriePtr,
        blockDataReceiptsRoot = emptyTriePtr,
        blockDataLogBloom = B.pack [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],         
        blockDataDifficulty = nextDifficulty (blockDataDifficulty bd) (blockDataTimestamp bd) ts,
        blockDataNumber = blockDataNumber bd + 1,
        blockDataGasLimit = max 125000 ((blockDataGasLimit bd * 1023 + blockDataGasUsed bd *6 `quot` 5) `quot` 1024),
        blockDataGasUsed = 0,
        blockDataTimestamp = ts,  
        blockDataExtraData = 0,
        blockDataNonce = SHA 5
        }
    bd = blockBlockData b


submitNextBlock::Integer->Block->EthCryptM ContextM ()
submitNextBlock baseDifficulty b = do
        ts <- liftIO getCurrentTime
        newBlock <- lift $ getNextBlock b ts
        n <- liftIO $ fastFindNonce newBlock

        --let theBytes = headerHashWithoutNonce newBlock `B.append` B.pack (integer2Bytes n)
        let theNewBlock = addNonceToBlock newBlock n
        sendMsg $ NewBlockPacket theNewBlock (baseDifficulty + blockDataDifficulty (blockBlockData theNewBlock))
        lift $ addBlocks [theNewBlock]

ifBlockInDBSubmitNextBlock::Integer->Block->EthCryptM ContextM ()
ifBlockInDBSubmitNextBlock baseDifficulty b = do
  maybeBlock <- lift $ lift $ getBlock (blockHash b)
  case maybeBlock of
    Nothing -> return ()
    _ -> submitNextBlock baseDifficulty b



handleMsg::Message->EthCryptM ContextM ()
handleMsg m = do
  lift $ displayMessage False m
  case m of
    Hello{} -> do
             bestBlock <- lift getBestBlock
             genesisBlockHash <- lift getGenesisBlockHash
             sendMsg Status{
               protocolVersion=fromIntegral ethVersion,
               networkID="",
               totalDifficulty=0,
               latestHash=blockHash bestBlock,
               genesisHash=genesisBlockHash
               }
    Ping -> do
      lift addPingCount
      sendMsg Pong
    GetPeers -> do
      sendMsg $ Peers []
      sendMsg GetPeers
    (Peers thePeers) -> do
      lift $ setPeers thePeers
    BlockHashes blockHashes -> handleNewBlockHashes blockHashes
    Blocks blocks -> do
      handleNewBlocks blocks
    NewBlockPacket block baseDifficulty -> do
      lift $ addBlocks [block]
      ifBlockInDBSubmitNextBlock baseDifficulty block

    Status{latestHash=lh, genesisHash=gh} -> do
      genesisBlockHash <- lift getGenesisBlockHash
      when (gh /= genesisBlockHash) $ error "Wrong genesis block hash!!!!!!!!"
      handleNewBlockHashes [lh]
    GetTransactions -> do
      sendMsg $ Transactions []
      --liftIO $ sendMessage handle GetTransactions
      return ()
      
    _-> return ()

getPayloads::[Word8]->[[Word8]]
getPayloads [] = []
getPayloads (0x22:0x40:0x08:0x91:s1:s2:s3:s4:remainder) =
  take payloadLength remainder:getPayloads (drop payloadLength remainder)
  where
    payloadLength = shift (fromIntegral s1) 24 + shift (fromIntegral s2) 16 + shift (fromIntegral s3) 8 + fromIntegral s4
getPayloads _ = error "Malformed data sent to getPayloads"

readAndOutput::EthCryptM ContextM ()
readAndOutput = do
  msg <- recvMsg
  handleMsg msg
  readAndOutput
  
mkHello::IO Message
mkHello = do
  peerId <- getEntropy 64
  return Hello {
               version = 3,
               clientId = "Ethereum(G)/v0.6.4//linux/Haskell",
               capability = [ETH ethVersion], -- , SHH shhVersion],
               port = 30303,
               nodeId = fromIntegral $ byteString2Integer peerId
             }

{-
createTransaction::Transaction->ContextM SignedTransaction
createTransaction t = do
    userNonce <- lift $ addressStateNonce <$> getAddressState (prvKey2Address prvKey)<commit_msg>More cleanup.<commit_after>{-# LANGUAGE OverloadedStrings #-}

module Main (
  main
  ) where

import Control.Monad.IO.Class
import Control.Monad.State
import Control.Monad.Trans.Resource
import Crypto.PubKey.ECC.DH
import Crypto.Types.PubKey.ECC
import Crypto.Random
import qualified Data.ByteString as B
import Data.Time.Clock
import Network.Haskoin.Crypto hiding (Address)
import System.Entropy
import System.Environment

import Blockchain.Frame
import Blockchain.UDP
import Blockchain.RLPx

import Blockchain.BlockChain
import Blockchain.BlockSynchronizer
import Blockchain.Communication
import Blockchain.Constants
import Blockchain.Context
import Blockchain.Data.Address
import Blockchain.Data.BlockDB
import Blockchain.Data.DataDefs
--import Blockchain.Data.SignedTransaction
--import Blockchain.Data.Transaction
import Blockchain.Data.Wire
import Blockchain.Database.MerklePatricia
import Blockchain.DB.CodeDB
import Blockchain.DB.ModifyStateDB
import Blockchain.DBM
import Blockchain.Display
import Blockchain.PeerUrls
--import Blockchain.SampleTransactions
import Blockchain.SHA
--import Blockchain.SigningTools
import Blockchain.Util

--import Debug.Trace

prvKey::PrvKey
Just prvKey = makePrvKey 0xac3e8ce2ef31c3f45d5da860bcd9aee4b37a05c5a3ddee40dd061620c3dab380

getNextBlock::Block->UTCTime->ContextM Block
getNextBlock b ts = do
  let theCoinbase = prvKey2Address prvKey
  lift $ setStateRoot $ blockDataStateRoot bd
  addToBalance theCoinbase (1500*finney)

  dbs <- lift get

  return Block{
               blockBlockData=testGetNextBlockData $ stateRoot $ stateDB dbs,
               blockReceiptTransactions=[],
               blockBlockUncles=[]
             }
  where
    testGetNextBlockData::SHAPtr->BlockData
    testGetNextBlockData sr =
      BlockData {
        blockDataParentHash=blockHash b,
        blockDataUnclesHash=hash $ B.pack [0xc0],
        blockDataCoinbase=prvKey2Address prvKey,
        blockDataStateRoot = sr,
        blockDataTransactionsRoot = emptyTriePtr,
        blockDataReceiptsRoot = emptyTriePtr,
        blockDataLogBloom = B.pack [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],         
        blockDataDifficulty = nextDifficulty (blockDataDifficulty bd) (blockDataTimestamp bd) ts,
        blockDataNumber = blockDataNumber bd + 1,
        blockDataGasLimit = max 125000 ((blockDataGasLimit bd * 1023 + blockDataGasUsed bd *6 `quot` 5) `quot` 1024),
        blockDataGasUsed = 0,
        blockDataTimestamp = ts,  
        blockDataExtraData = 0,
        blockDataNonce = SHA 5
        }
    bd = blockBlockData b


submitNextBlock::Integer->Block->EthCryptM ContextM ()
submitNextBlock baseDifficulty b = do
        ts <- liftIO getCurrentTime
        newBlock <- lift $ getNextBlock b ts
        n <- liftIO $ fastFindNonce newBlock

        --let theBytes = headerHashWithoutNonce newBlock `B.append` B.pack (integer2Bytes n)
        let theNewBlock = addNonceToBlock newBlock n
        sendMsg $ NewBlockPacket theNewBlock (baseDifficulty + blockDataDifficulty (blockBlockData theNewBlock))
        lift $ addBlocks [theNewBlock]

ifBlockInDBSubmitNextBlock::Integer->Block->EthCryptM ContextM ()
ifBlockInDBSubmitNextBlock baseDifficulty b = do
  maybeBlock <- lift $ lift $ getBlock (blockHash b)
  case maybeBlock of
    Nothing -> return ()
    _ -> submitNextBlock baseDifficulty b



handleMsg::Message->EthCryptM ContextM ()
handleMsg m = do
  lift $ displayMessage False m
  case m of
    Hello{} -> do
             bestBlock <- lift getBestBlock
             genesisBlockHash <- lift getGenesisBlockHash
             sendMsg Status{
               protocolVersion=fromIntegral ethVersion,
               networkID="",
               totalDifficulty=0,
               latestHash=blockHash bestBlock,
               genesisHash=genesisBlockHash
               }
    Ping -> do
      lift addPingCount
      sendMsg Pong
    GetPeers -> do
      sendMsg $ Peers []
      sendMsg GetPeers
    (Peers thePeers) -> do
      lift $ setPeers thePeers
    BlockHashes blockHashes -> handleNewBlockHashes blockHashes
    Blocks blocks -> do
      handleNewBlocks blocks
    NewBlockPacket block baseDifficulty -> do
      lift $ addBlocks [block]
      ifBlockInDBSubmitNextBlock baseDifficulty block

    Status{latestHash=lh, genesisHash=gh} -> do
      genesisBlockHash <- lift getGenesisBlockHash
      when (gh /= genesisBlockHash) $ error "Wrong genesis block hash!!!!!!!!"
      handleNewBlockHashes [lh]
    GetTransactions -> do
      sendMsg $ Transactions []
      --liftIO $ sendMessage handle GetTransactions
      return ()
      
    _-> return ()

readAndOutput::EthCryptM ContextM ()
readAndOutput = do
  msg <- recvMsg
  handleMsg msg
  readAndOutput
  
mkHello::IO Message
mkHello = do
  peerId <- getEntropy 64
  return Hello {
               version = 3,
               clientId = "Ethereum(G)/v0.6.4//linux/Haskell",
               capability = [ETH ethVersion], -- , SHH shhVersion],
               port = 30303,
               nodeId = fromIntegral $ byteString2Integer peerId
             }

{-
createTransaction::Transaction->ContextM SignedTransaction
createTransaction t = do
    userNonce <- lift $ addressStateNonce <$> getAddressState (prvKey2Address prvKey)
{'fraction_non_alphanumeric': 0.08188585607940446, 'fraction_numerical': 0.0272066643034385, 'mean_word_length': 3.2730026505111702, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 48, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5063856', 'n_tokens_mistral': 3670, 'n_tokens_neox': 3455, 'n_words': 799}