diff --git a/database.go b/database.go new file mode 100644 index 0000000000..f74c1dc7ff --- /dev/null +++ b/database.go @@ -0,0 +1,94 @@ +package main + +import ( + "path" + "os/user" + "github.com/syndtr/goleveldb/leveldb" + "fmt" +) + +type Database struct { + db *leveldb.DB + trie *Trie +} + +func NewDatabase() (*Database, error) { + // This will eventually have to be something like a resource folder. + // it works on my system for now. Probably won't work on Windows + usr, _ := user.Current() + dbPath := path.Join(usr.HomeDir, ".ethereum", "database") + + // Open the db + db, err := leveldb.OpenFile(dbPath, nil) + if err != nil { + return nil, err + } + + database := &Database{db: db} + + // Bootstrap database. Sets a few defaults; such as the last block + database.Bootstrap() + + return database, nil +} + +func (db *Database) Bootstrap() error { + db.trie = NewTrie(db) + + return nil +} + +func (db *Database) Put(key []byte, value []byte) { + err := db.db.Put(key, value, nil) + if err != nil { + fmt.Println("Error put", err) + } +} + +func (db *Database) Close() { + // Close the leveldb database + db.db.Close() +} + +type Trie struct { + root string + db *Database +} + +func NewTrie(db *Database) *Trie { + return &Trie{db: db, root: ""} +} + +func (t *Trie) Update(key string, value string) { + k := CompactHexDecode(key) + + t.root = t.UpdateState(t.root, k, value) +} + +func (t *Trie) Get(key []byte) ([]byte, error) { + return nil, nil +} + +// Inserts a new sate or delete a state based on the value +func (t *Trie) UpdateState(node, key, value string) string { + if value != "" { + return t.InsertState(node, key, value) + } else { + // delete it + } + + return "" +} + +func (t *Trie) InsertState(node, key, value string) string { + return "" +} + +func (t *Trie) Put(node []byte) []byte { + enc := Encode(node) + sha := Sha256Bin(enc) + + t.db.Put([]byte(sha), enc) + + return sha +} diff --git a/database_test.go b/database_test.go new file mode 100644 index 0000000000..c1a6c7d16a --- /dev/null +++ b/database_test.go @@ -0,0 +1,43 @@ +package main + +import ( + "testing" + _"fmt" +) + +func TestTriePut(t *testing.T) { + db, err := NewDatabase() + defer db.Close() + + if err != nil { + t.Error("Error starting db") + } + + key := db.trie.Put([]byte("testing node")) + + data, err := db.db.Get(key, nil) + if err != nil { + t.Error("Nothing at node") + } + + s, _ := Decode(data, 0) + if str, ok := s.([]byte); ok { + if string(str) != "testing node" { + t.Error("Wrong value node", str) + } + } else { + t.Error("Invalid return type") + } +} + +func TestTrieUpdate(t *testing.T) { + db, err := NewDatabase() + defer db.Close() + + if err != nil { + t.Error("Error starting db") + } + + db.trie.Update("test", "test") +} + diff --git a/genesis.go b/genesis.go new file mode 100644 index 0000000000..aae9cd1cfe --- /dev/null +++ b/genesis.go @@ -0,0 +1,36 @@ +package main + +import ( + "math" +) + +/* + * This is the special genesis block. + */ + +var GenisisHeader = []interface{}{ + // Block number + uint32(0), + // Previous hash (none) + "", + // Sha of uncles + string(Sha256Bin(Encode([]interface{}{}))), + // Coinbase + "", + // Root state + "", + // Sha of transactions + string(Sha256Bin(Encode([]interface{}{}))), + // Difficulty + uint32(math.Pow(2, 36)), + // Time + uint64(1), + // Nonce + uint32(0), + // Extra + "", +} + +var Genesis = []interface{}{ GenisisHeader, []interface{}{}, []interface{}{} } + +var GenisisBlock = NewBlock( Encode(Genesis) ) diff --git a/server.go b/server.go new file mode 100644 index 0000000000..0c74887873 --- /dev/null +++ b/server.go @@ -0,0 +1,55 @@ +package main + +import ( + "container/list" + "time" +) + +type Server struct { + // Channel for shutting down the server + shutdownChan chan bool + // DB interface + db *Database + // Peers (NYI) + peers *list.List +} + +func NewServer() (*Server, error) { + db, err := NewDatabase() + if err != nil { + return nil, err + } + + server := &Server{ + shutdownChan: make(chan bool), + db: db, + peers: list.New(), + } + + return server, nil +} + +// Start the server +func (s *Server) Start() { + // For now this function just blocks the main thread + for { + time.Sleep( time.Second ) + } +} + +func (s *Server) Stop() { + // Close the database + defer s.db.Close() + + // Loop thru the peers and close them (if we had them) + for e := s.peers.Front(); e != nil; e = e.Next() { + // peer close etc + } + + s.shutdownChan <- true +} + +// This function will wait for a shutdown and resumes main thread execution +func (s *Server) WaitForShutdown() { + <- s.shutdownChan +}