package main import ( "github.com/ethereum/go-ethereum/swarm/storage/feed/lookup" "github.com/ethereum/go-ethereum/swarm/pss" "context" "bufio" "fmt" "crypto/ecdsa" "os" "bytes" "time" "io/ioutil" "encoding/json" "github.com/ethereum/go-ethereum/log" "strconv" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/swarm/storage/feed" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/swarm" // "github.com/ethereum/go-ethereum/swarm/network" bzzapi "github.com/ethereum/go-ethereum/swarm/api" // XXX: Shouldn't this be bzzclient? feedsapi "github.com/ethereum/go-ethereum/swarm/api/client" ) var ( // logger Log = log.New("hello-pss", "*") // XXX: Should be multiple, but cheating and only taking parent0 lastParent = "" // Set of seen parent0 swarm hash messages SeenSet = make(map[string]bool) ) // TODO: Ensure node starts in light node so it doesn't eat up a lot of disk space // XXX: Warning, this is bad design. Should use keystore for this. func getHexPrivateKey() string { privateKey, err := crypto.GenerateKey() if err != nil { Log.Crit("can't generate private key", err) } privateKeyBytes := crypto.FromECDSA(privateKey) // Debugging and basic key operations //publicKey := privateKey.Public() //publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey) //if !ok { // log.Crit("error casting public key to ECDSA", err) //} //publicKeyBytes := crypto.FromECDSAPub(publicKeyECDSA) //address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex() //fmt.Println("Private Key: ", hexutil.Encode(privateKeyBytes)) //fmt.Println("Public Key: ", hexutil.Encode(publicKeyBytes[4:])) //fmt.Println("Address: ", address) return hexutil.Encode(privateKeyBytes) } func getPrivateKeyFromFile(keyfile string) *ecdsa.PrivateKey { contents, err := ioutil.ReadFile(keyfile) if err != nil { log.Crit("Unable to read keyfile", keyfile) } println(string(contents)) privateKeyBytes, err := hexutil.Decode(string(contents)) if err != nil { log.Crit("Unable to get private key bytes", err) } privateKey, err := crypto.ToECDSA(privateKeyBytes) if err != nil { log.Crit("Unable to get private key", err) } return privateKey } // XXX: This shouldn't be needed func getp2pConfig(listenaddr string) p2p.Config { return p2p.Config{ ListenAddr: listenaddr, MaxPeers: 25, NAT: nat.Any(), } } // Create a node func newNode(port int) (*node.Node, error) { cfg := &node.DefaultConfig cfg.DataDir = fmt.Sprintf("%s%d", ".data_", port) // XXX: cfg.P2P.ListenAddr = fmt.Sprintf(":%d", port), should work if port == 9600 { cfg.P2P = getp2pConfig(":30400") } else if port == 9601 { cfg.P2P = getp2pConfig(":30401") } else if port == 9602 { cfg.P2P = getp2pConfig(":30402") } else { log.Crit("Ports be fucked up", "yeah") } cfg.HTTPPort = port cfg.IPCPath = "bzz.ipc" //fmt.Printf("Current data directory is %s\n", cfg.DataDir) return node.New(cfg) } // TODO: How do we know this // XXX: We can probably cheat with in-memory only by downloading all messages and A is restarting func seen(hash string) bool { return SeenSet[hash] } func fetchMessage(hash string) { // download from swarm httpClient := feedsapi.NewClient("http://localhost:9602") // XXX 9601 response, _, err := httpClient.DownloadRaw(hash) if err != nil { fmt.Println("Unable to download raw", err) os.Exit(1) } // Assuming no error, save hash to SeenSet so we don't download again // XXX: Edge case because message id of pss message not seen, so calculate again? SeenSet[hash] = true buf := new(bytes.Buffer) buf.ReadFrom(response) str := buf.String() msg := deserialize(str) //fmt.Println("***Download raw", str) handleMessage(msg) } // XXX: Assumes no duplicates func handleMessage(msg message) { // Cheating // XXX so much duplication eh httpClient := feedsapi.NewClient("http://localhost:9602") // XXX 9601 // How many cases are there? // We have all the dependencies // We need to fetch more dependencies // We have seen it before // We have not seen it before // XXX: Edge case, incoming message don't have hash stored already // XXX: Hack work around, upload message and check if hash is same // Should be possible to figure out hash locally but yeah // XXX: Assuming hash is same, which it should be payload := serialize(msg) hash, err := httpClient.UploadRaw(bytes.NewReader(payload), int64(len(payload)), false) if err != nil { fmt.Println("Unable to upload raw", err) os.Exit(1) } //fmt.Println("** Adding hash of message to SeenSet", hash) SeenSet[hash] = true // Interesting, this seems to unroll and deal with order automatically // XXX: Edge cases here because it doesn't save messages, just happy path stack parent0 := msg.Parents[0] if (parent0 != "") && !seen(parent0) { fmt.Printf("[Unmet dependency, downloading: %s]\n", parent0) fetchMessage(parent0) } // Only print it if all dependencies are met fmt.Println("Alice:", string(msg.Text)) // fmt.Println("Alice:", string(msg.Text), "- parent0:", string(msg.Parents[0])) // fmt.Println("Feed result: ", msg.Text, "- parent0:", msg.Parents[0]) } func listenForMessages(msgC chan pss.APIMsg) { for { in := <-msgC // XXX: Who is in.key really? want readable public key here // XXX: The UX is an illusion // XXX: parsing logic should be same for pull from feed parsed := deserialize(string(in.Msg)) //fmt.Println("Alice old:", string(in.Msg)) // XXX Only one parent // TODO: Get all the parents here handleMessage(parsed) //fmt.Println("\nReceived message", string(in.Msg), "from", fmt.Sprintf("%x", in.Key)) } } // TODO: Error handling if fail func postToFeed(client *rpc.Client, signer *feed.GenericSigner, receiver string, topic string, data []byte) { // For creating manifest, then posting, then finally getting // Create a new feed with user and topic. f := new(feed.Feed) f.User = signer.Address() f.Topic, _ = feed.NewTopic("bob", nil) query := feed.NewQueryLatest(f, lookup.NoClue) // XXX: Ok feeds seems fairly broken //httpClient := feedsapi.NewClient("https://swarm-gateways.net") // Cheating httpClient := feedsapi.NewClient("http://localhost:9602") // XXX 9600 // local sender alice //httpClient := feedsapi.NewClient("http://localhost:9600") //XXX doesnt even work //httpClient := feedsapi.NewClient("https://swarm-gateways.net") // XXX: Post to multiple feeds? //fmt.Println("signer Address: ", f.User.Hex()) request, err := httpClient.GetFeedRequest(query, "") if err != nil { fmt.Printf("Error retrieving feed status: %s", err.Error()) } request.SetData(data) if err = request.Sign(signer); err != nil { fmt.Printf("Error signing feed update: %s", err.Error()) } //fmt.Println("*** signed request", request) // manifest, err := httpClient.CreateFeedWithManifest(request) // if err != nil { // fmt.Printf("Error getting manifest: %s", manifest) // } // fmt.Println("MANIFEST:", manifest) // XXX: What do I want to do with feeds manifest? // 567f611190b2758fa625b3be14b2b9becf6f0e8887015b7c40d6cbe0e5fa14aa // Success: this works, also from 9601 Bob: // curl 'http://localhost:9600/bzz-feed:/?user=0xBCa21d9c6031b1965a9e0233D9B905d2f10CA259&name=bob' // XXX: Why do we need the second argument manifestAddressOrDomain? // It's already baked into httpClient and query. // Indeed: // > You only need to provide either manifestAddressOrDomain or Query to QueryFeed(). Set to "" or nil respectively. // response, err := httpClient.QueryFeed(query, "") // if err != nil { // fmt.Println("QueryFeed error", err) // } // buf := new(bytes.Buffer) // buf.ReadFrom(response) // feedStr := buf.String() // fmt.Println("Feed result: ", feedStr) // XXX Want to set level and time? // POST /bzz-feed:/?topic=&user=&level=&time=