module bc import Crypto.Hash.SHA1 import Data.Func import Data.Integer, Data.Integer.GenJSON import Data.List import Math.Random import StdEnv import System.Process import System.Time import Text import iTasks import iTasks.Extensions.DateTime NONCESIZE :== 2 :: HashFun :== String -> String :: ValidationFun :== String -> Bool :: Block = {nonce :: !Int, prevHash :: !String, data :: !String, hash :: !String} :: BlockChain :== [Block] :: Settings = {difficulty :: Int, workers :: [Int]} derive class iTask Settings, Block Start w = doTasks main w mine :: !HashFun !ValidationFun !String !String !Int -> Block mine hfun pred prev data seed # (nonce, hash) = hd $ filter (pred o snd) $ map hash $ genRandInt seed = {nonce=nonce,prevHash=prev,data=data,hash=hash} where hash i = (i, hfun $ data +++ prev +++ toString i) dataShare :: SimpleSDSLens [String] dataShare = sharedStore "data" [] chainShare :: SimpleSDSLens [Block] chainShare = sharedStore "chain" [] messageShare :: SimpleSDSLens [String] messageShare = sharedStore "messages" [] settingsShare :: SimpleSDSLens Settings settingsShare = sharedStore "settings" {difficulty=4, workers=[8000,8001,8002]} main = (parallel [(Embedded, \_->chainViewer <<@ Title "Chain") ,(Embedded, \_->minerTask <<@ Title "Pool" @! ()) ,(Embedded, \_->updateSharedInformation [] settingsShare <<@ Title "Settings" @! ()) ] [] <<@ ArrangeWithTabs False) >>* [OnAction (Action "Shutdown") $ always $ shutDown 0] where chainViewer :: Task () chainViewer = (addData <<@ heightAttr (ExactSize 80)) -|| (viewSharedInformation [] chainShare <<@ Label "Chain") where addData = (enterInformation [] <<@ Label "Add data") >>? \x->upd (\q->q ++ [x]) dataShare >-| addData minerTask :: Task () minerTask = get applicationOptions >>- \opts->wait (not o isEmpty) dataShare >>- \[data:_]->upd (\[_:qs]->qs) dataShare >-| get settingsShare >>- \sett->get chainShare @ maybe "" (\b->b.hash) o listToMaybe >>- \prevhash->anyTask [ mineTask i opts.appPath port sett.difficulty data prevhash \\ port <- sett.workers & i <- [0..]] >>- \block->upd (\chain->[block:chain]) chainShare >-| minerTask where mineTask :: Int String Int Int String String -> Task Block mineTask num appPath port difficulty data prevHash = Title ("Worker " +++ toString num) @>> ApplyLayout (toPanel False) @>> withShared [] \stdin-> withShared ([], []) \stdout-> workerproc stdin stdout ||- workerTask (mapRead fst stdout) where workerproc = externalProcess {tv_sec=0,tv_nsec=100000000} appPath ["--distributed", toString port, "--distributedChild"] Nothing 9 (Just defaultPtyOptions) workerTask stdout = wait (any (startsWith "SDS server listening on ") o split "\n" o concat) stdout >-| asyncTask "localhost" port (get randomInt >>- return o mine sha1 (startsWith (createArray difficulty '0')) prevHash data)