From 5369a5c54dca1e7b96680997083035a0f9170d60 Mon Sep 17 00:00:00 2001 From: Sorin Neacsu Date: Thu, 28 Dec 2017 05:15:33 -0800 Subject: [PATCH 01/25] rpc: allow OPTIONS requests without Content-Type (#15759) Fixes #15740 --- rpc/http.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/http.go b/rpc/http.go index a26559b122..d61b0e470b 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -177,7 +177,7 @@ func validateRequest(r *http.Request) (int, error) { return http.StatusRequestEntityTooLarge, err } mt, _, err := mime.ParseMediaType(r.Header.Get("content-type")) - if err != nil || mt != contentType { + if r.Method != http.MethodOptions && (err != nil || mt != contentType) { err := fmt.Errorf("invalid content type, only %s is supported", contentType) return http.StatusUnsupportedMediaType, err } From c15d76a40f330561b2491718a143fd494a2b7b5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 28 Dec 2017 15:17:03 +0200 Subject: [PATCH 02/25] p2p/discv5: fix reg lookup, polish code, use logger (#15737) --- p2p/discv5/net.go | 56 +++++------ p2p/discv5/node.go | 5 + p2p/discv5/ticket.go | 221 +++++++++++++++++++++---------------------- p2p/discv5/topic.go | 3 +- 4 files changed, 141 insertions(+), 144 deletions(-) diff --git a/p2p/discv5/net.go b/p2p/discv5/net.go index 2fbb60824c..cd9981584d 100644 --- a/p2p/discv5/net.go +++ b/p2p/discv5/net.go @@ -51,16 +51,9 @@ const ( const testTopic = "foo" const ( - printDebugLogs = false printTestImgLogs = false ) -func debugLog(s string) { - if printDebugLogs { - fmt.Println(s) - } -} - // Network manages the table and all protocol interaction. type Network struct { db *nodeDB // database of known nodes @@ -388,14 +381,14 @@ func (net *Network) loop() { } }() resetNextTicket := func() { - t, timeout := net.ticketStore.nextFilteredTicket() - if t != nextTicket { - nextTicket = t + ticket, timeout := net.ticketStore.nextFilteredTicket() + if nextTicket != ticket { + nextTicket = ticket if nextRegisterTimer != nil { nextRegisterTimer.Stop() nextRegisterTime = nil } - if t != nil { + if ticket != nil { nextRegisterTimer = time.NewTimer(timeout) nextRegisterTime = nextRegisterTimer.C } @@ -423,13 +416,13 @@ loop: select { case <-net.closeReq: - debugLog("<-net.closeReq") + log.Trace("<-net.closeReq") break loop // Ingress packet handling. case pkt := <-net.read: //fmt.Println("read", pkt.ev) - debugLog("<-net.read") + log.Trace("<-net.read") n := net.internNode(&pkt) prestate := n.state status := "ok" @@ -444,7 +437,7 @@ loop: // State transition timeouts. case timeout := <-net.timeout: - debugLog("<-net.timeout") + log.Trace("<-net.timeout") if net.timeoutTimers[timeout] == nil { // Stale timer (was aborted). continue @@ -462,20 +455,20 @@ loop: // Querying. case q := <-net.queryReq: - debugLog("<-net.queryReq") + log.Trace("<-net.queryReq") if !q.start(net) { q.remote.deferQuery(q) } // Interacting with the table. case f := <-net.tableOpReq: - debugLog("<-net.tableOpReq") + log.Trace("<-net.tableOpReq") f() net.tableOpResp <- struct{}{} // Topic registration stuff. case req := <-net.topicRegisterReq: - debugLog("<-net.topicRegisterReq") + log.Trace("<-net.topicRegisterReq") if !req.add { net.ticketStore.removeRegisterTopic(req.topic) continue @@ -486,7 +479,7 @@ loop: // determination for new topics. // if topicRegisterLookupDone == nil { if topicRegisterLookupTarget.target == (common.Hash{}) { - debugLog("topicRegisterLookupTarget == null") + log.Trace("topicRegisterLookupTarget == null") if topicRegisterLookupTick.Stop() { <-topicRegisterLookupTick.C } @@ -496,7 +489,7 @@ loop: } case nodes := <-topicRegisterLookupDone: - debugLog("<-topicRegisterLookupDone") + log.Trace("<-topicRegisterLookupDone") net.ticketStore.registerLookupDone(topicRegisterLookupTarget, nodes, func(n *Node) []byte { net.ping(n, n.addr()) return n.pingEcho @@ -507,7 +500,7 @@ loop: topicRegisterLookupDone = nil case <-topicRegisterLookupTick.C: - debugLog("<-topicRegisterLookupTick") + log.Trace("<-topicRegisterLookupTick") if (topicRegisterLookupTarget.target == common.Hash{}) { target, delay := net.ticketStore.nextRegisterLookup() topicRegisterLookupTarget = target @@ -520,14 +513,14 @@ loop: } case <-nextRegisterTime: - debugLog("<-nextRegisterTime") + log.Trace("<-nextRegisterTime") net.ticketStore.ticketRegistered(*nextTicket) //fmt.Println("sendTopicRegister", nextTicket.t.node.addr().String(), nextTicket.t.topics, nextTicket.idx, nextTicket.t.pong) net.conn.sendTopicRegister(nextTicket.t.node, nextTicket.t.topics, nextTicket.idx, nextTicket.t.pong) case req := <-net.topicSearchReq: if refreshDone == nil { - debugLog("<-net.topicSearchReq") + log.Trace("<-net.topicSearchReq") info, ok := searchInfo[req.topic] if ok { if req.delay == time.Duration(0) { @@ -588,7 +581,7 @@ loop: }) case <-statsDump.C: - debugLog("<-statsDump.C") + log.Trace("<-statsDump.C") /*r, ok := net.ticketStore.radius[testTopic] if !ok { fmt.Printf("(%x) no radius @ %v\n", net.tab.self.ID[:8], time.Now()) @@ -617,7 +610,7 @@ loop: // Periodic / lookup-initiated bucket refresh. case <-refreshTimer.C: - debugLog("<-refreshTimer.C") + log.Trace("<-refreshTimer.C") // TODO: ideally we would start the refresh timer after // fallback nodes have been set for the first time. if refreshDone == nil { @@ -631,7 +624,7 @@ loop: bucketRefreshTimer.Reset(bucketRefreshInterval) }() case newNursery := <-net.refreshReq: - debugLog("<-net.refreshReq") + log.Trace("<-net.refreshReq") if newNursery != nil { net.nursery = newNursery } @@ -641,7 +634,7 @@ loop: } net.refreshResp <- refreshDone case <-refreshDone: - debugLog("<-net.refreshDone") + log.Trace("<-net.refreshDone") refreshDone = nil list := searchReqWhenRefreshDone searchReqWhenRefreshDone = nil @@ -652,7 +645,7 @@ loop: }() } } - debugLog("loop stopped") + log.Trace("loop stopped") log.Debug(fmt.Sprintf("shutting down")) if net.conn != nil { @@ -1109,14 +1102,14 @@ func (net *Network) ping(n *Node, addr *net.UDPAddr) { //fmt.Println(" not sent") return } - debugLog(fmt.Sprintf("ping(node = %x)", n.ID[:8])) + log.Trace("Pinging remote node", "node", n.ID) n.pingTopics = net.ticketStore.regTopicSet() n.pingEcho = net.conn.sendPing(n, addr, n.pingTopics) net.timedEvent(respTimeout, n, pongTimeout) } func (net *Network) handlePing(n *Node, pkt *ingressPacket) { - debugLog(fmt.Sprintf("handlePing(node = %x)", n.ID[:8])) + log.Trace("Handling remote ping", "node", n.ID) ping := pkt.data.(*ping) n.TCP = ping.From.TCP t := net.topictab.getTicket(n, ping.Topics) @@ -1131,7 +1124,7 @@ func (net *Network) handlePing(n *Node, pkt *ingressPacket) { } func (net *Network) handleKnownPong(n *Node, pkt *ingressPacket) error { - debugLog(fmt.Sprintf("handleKnownPong(node = %x)", n.ID[:8])) + log.Trace("Handling known pong", "node", n.ID) net.abortTimedEvent(n, pongTimeout) now := mclock.Now() ticket, err := pongToTicket(now, n.pingTopics, n, pkt) @@ -1139,9 +1132,8 @@ func (net *Network) handleKnownPong(n *Node, pkt *ingressPacket) error { // fmt.Printf("(%x) ticket: %+v\n", net.tab.self.ID[:8], pkt.data) net.ticketStore.addTicket(now, pkt.data.(*pong).ReplyTok, ticket) } else { - debugLog(fmt.Sprintf(" error: %v", err)) + log.Trace("Failed to convert pong to ticket", "err", err) } - n.pingEcho = nil n.pingTopics = nil return err diff --git a/p2p/discv5/node.go b/p2p/discv5/node.go index 2db7a508f0..fd88a55b15 100644 --- a/p2p/discv5/node.go +++ b/p2p/discv5/node.go @@ -273,6 +273,11 @@ func (n NodeID) GoString() string { return fmt.Sprintf("discover.HexID(\"%x\")", n[:]) } +// TerminalString returns a shortened hex string for terminal logging. +func (n NodeID) TerminalString() string { + return hex.EncodeToString(n[:8]) +} + // HexID converts a hex string to a NodeID. // The string may be prefixed with 0x. func HexID(in string) (NodeID, error) { diff --git a/p2p/discv5/ticket.go b/p2p/discv5/ticket.go index 193cef4be5..b45ec4d2be 100644 --- a/p2p/discv5/ticket.go +++ b/p2p/discv5/ticket.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/mclock" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/log" ) const ( @@ -128,8 +129,11 @@ type ticketStore struct { // Contains buckets (for each absolute minute) of tickets // that can be used in that minute. // This is only set if the topic is being registered. - tickets map[Topic]topicTickets - regtopics []Topic + tickets map[Topic]*topicTickets + + regQueue []Topic // Topic registration queue for round robin attempts + regSet map[Topic]struct{} // Topic registration queue contents for fast filling + nodes map[*Node]*ticket nodeLastReq map[*Node]reqInfo @@ -152,14 +156,16 @@ type sentQuery struct { } type topicTickets struct { - buckets map[timeBucket][]ticketRef - nextLookup, nextReg mclock.AbsTime + buckets map[timeBucket][]ticketRef + nextLookup mclock.AbsTime + nextReg mclock.AbsTime } func newTicketStore() *ticketStore { return &ticketStore{ radius: make(map[Topic]*topicRadius), - tickets: make(map[Topic]topicTickets), + tickets: make(map[Topic]*topicTickets), + regSet: make(map[Topic]struct{}), nodes: make(map[*Node]*ticket), nodeLastReq: make(map[*Node]reqInfo), searchTopicMap: make(map[Topic]searchTopic), @@ -169,13 +175,13 @@ func newTicketStore() *ticketStore { // addTopic starts tracking a topic. If register is true, // the local node will register the topic and tickets will be collected. -func (s *ticketStore) addTopic(t Topic, register bool) { - debugLog(fmt.Sprintf(" addTopic(%v, %v)", t, register)) - if s.radius[t] == nil { - s.radius[t] = newTopicRadius(t) +func (s *ticketStore) addTopic(topic Topic, register bool) { + log.Trace("Adding discovery topic", "topic", topic, "register", register) + if s.radius[topic] == nil { + s.radius[topic] = newTopicRadius(topic) } - if register && s.tickets[t].buckets == nil { - s.tickets[t] = topicTickets{buckets: make(map[timeBucket][]ticketRef)} + if register && s.tickets[topic] == nil { + s.tickets[topic] = &topicTickets{buckets: make(map[timeBucket][]ticketRef)} } } @@ -194,7 +200,11 @@ func (s *ticketStore) removeSearchTopic(t Topic) { // removeRegisterTopic deletes all tickets for the given topic. func (s *ticketStore) removeRegisterTopic(topic Topic) { - debugLog(fmt.Sprintf(" removeRegisterTopic(%v)", topic)) + log.Trace("Removing discovery topic", "topic", topic) + if s.tickets[topic] == nil { + log.Warn("Removing non-existent discovery topic", "topic", topic) + return + } for _, list := range s.tickets[topic].buckets { for _, ref := range list { ref.t.refCnt-- @@ -216,23 +226,35 @@ func (s *ticketStore) regTopicSet() []Topic { } // nextRegisterLookup returns the target of the next lookup for ticket collection. -func (s *ticketStore) nextRegisterLookup() (lookup lookupInfo, delay time.Duration) { - debugLog("nextRegisterLookup()") - firstTopic, ok := s.iterRegTopics() - for topic := firstTopic; ok; { - debugLog(fmt.Sprintf(" checking topic %v, len(s.tickets[topic]) = %d", topic, len(s.tickets[topic].buckets))) - if s.tickets[topic].buckets != nil && s.needMoreTickets(topic) { - next := s.radius[topic].nextTarget(false) - debugLog(fmt.Sprintf(" %x 1s", next.target[:8])) - return next, 100 * time.Millisecond - } - topic, ok = s.iterRegTopics() - if topic == firstTopic { - break // We have checked all topics. +func (s *ticketStore) nextRegisterLookup() (lookupInfo, time.Duration) { + // Queue up any new topics (or discarded ones), preserving iteration order + for topic := range s.tickets { + if _, ok := s.regSet[topic]; !ok { + s.regQueue = append(s.regQueue, topic) + s.regSet[topic] = struct{}{} } } - debugLog(" null, 40s") - return lookupInfo{}, 40 * time.Second + // Iterate over the set of all topics and look up the next suitable one + for len(s.regQueue) > 0 { + // Fetch the next topic from the queue, and ensure it still exists + topic := s.regQueue[0] + s.regQueue = s.regQueue[1:] + delete(s.regSet, topic) + + if s.tickets[topic] == nil { + continue + } + // If the topic needs more tickets, return it + if s.tickets[topic].nextLookup < mclock.Now() { + next, delay := s.radius[topic].nextTarget(false), 100*time.Millisecond + log.Trace("Found discovery topic to register", "topic", topic, "target", next.target, "delay", delay) + return next, delay + } + } + // No registration topics found or all exhausted, sleep + delay := 40 * time.Second + log.Trace("No topic found to register", "delay", delay) + return lookupInfo{}, delay } func (s *ticketStore) nextSearchLookup(topic Topic) lookupInfo { @@ -246,40 +268,22 @@ func (s *ticketStore) nextSearchLookup(topic Topic) lookupInfo { return target } -// iterRegTopics returns topics to register in arbitrary order. -// The second return value is false if there are no topics. -func (s *ticketStore) iterRegTopics() (Topic, bool) { - debugLog("iterRegTopics()") - if len(s.regtopics) == 0 { - if len(s.tickets) == 0 { - debugLog(" false") - return "", false - } - // Refill register list. - for t := range s.tickets { - s.regtopics = append(s.regtopics, t) - } - } - topic := s.regtopics[len(s.regtopics)-1] - s.regtopics = s.regtopics[:len(s.regtopics)-1] - debugLog(" " + string(topic) + " true") - return topic, true -} - -func (s *ticketStore) needMoreTickets(t Topic) bool { - return s.tickets[t].nextLookup < mclock.Now() -} - // ticketsInWindow returns the tickets of a given topic in the registration window. -func (s *ticketStore) ticketsInWindow(t Topic) []ticketRef { - ltBucket := s.lastBucketFetched - var res []ticketRef - tickets := s.tickets[t].buckets - for g := ltBucket; g < ltBucket+timeWindow; g++ { - res = append(res, tickets[g]...) +func (s *ticketStore) ticketsInWindow(topic Topic) []ticketRef { + // Sanity check that the topic still exists before operating on it + if s.tickets[topic] == nil { + log.Warn("Listing non-existing discovery tickets", "topic", topic) + return nil } - debugLog(fmt.Sprintf("ticketsInWindow(%v) = %v", t, len(res))) - return res + // Gather all the tickers in the next time window + var tickets []ticketRef + + buckets := s.tickets[topic].buckets + for idx := timeBucket(0); idx < timeWindow; idx++ { + tickets = append(tickets, buckets[s.lastBucketFetched+idx]...) + } + log.Trace("Retrieved discovery registration tickets", "topic", topic, "from", s.lastBucketFetched, "tickets", len(tickets)) + return tickets } func (s *ticketStore) removeExcessTickets(t Topic) { @@ -317,53 +321,55 @@ func (s ticketRefByWaitTime) Swap(i, j int) { func (s *ticketStore) addTicketRef(r ticketRef) { topic := r.t.topics[r.idx] - t := s.tickets[topic] - if t.buckets == nil { + tickets := s.tickets[topic] + if tickets == nil { + log.Warn("Adding ticket to non-existent topic", "topic", topic) return } bucket := timeBucket(r.t.regTime[r.idx] / mclock.AbsTime(ticketTimeBucketLen)) - t.buckets[bucket] = append(t.buckets[bucket], r) + tickets.buckets[bucket] = append(tickets.buckets[bucket], r) r.t.refCnt++ min := mclock.Now() - mclock.AbsTime(collectFrequency)*maxCollectDebt - if t.nextLookup < min { - t.nextLookup = min + if tickets.nextLookup < min { + tickets.nextLookup = min } - t.nextLookup += mclock.AbsTime(collectFrequency) - s.tickets[topic] = t + tickets.nextLookup += mclock.AbsTime(collectFrequency) //s.removeExcessTickets(topic) } -func (s *ticketStore) nextFilteredTicket() (t *ticketRef, wait time.Duration) { +func (s *ticketStore) nextFilteredTicket() (*ticketRef, time.Duration) { now := mclock.Now() for { - t, wait = s.nextRegisterableTicket() - if t == nil { - return + ticket, wait := s.nextRegisterableTicket() + if ticket == nil { + return ticket, wait } + log.Trace("Found discovery ticket to register", "node", ticket.t.node, "serial", ticket.t.serial, "wait", wait) + regTime := now + mclock.AbsTime(wait) - topic := t.t.topics[t.idx] + topic := ticket.t.topics[ticket.idx] if regTime >= s.tickets[topic].nextReg { - return + return ticket, wait } - s.removeTicketRef(*t) + s.removeTicketRef(*ticket) } } -func (s *ticketStore) ticketRegistered(t ticketRef) { +func (s *ticketStore) ticketRegistered(ref ticketRef) { now := mclock.Now() - topic := t.t.topics[t.idx] - tt := s.tickets[topic] + topic := ref.t.topics[ref.idx] + tickets := s.tickets[topic] min := now - mclock.AbsTime(registerFrequency)*maxRegisterDebt - if min > tt.nextReg { - tt.nextReg = min + if min > tickets.nextReg { + tickets.nextReg = min } - tt.nextReg += mclock.AbsTime(registerFrequency) - s.tickets[topic] = tt + tickets.nextReg += mclock.AbsTime(registerFrequency) + s.tickets[topic] = tickets - s.removeTicketRef(t) + s.removeTicketRef(ref) } // nextRegisterableTicket returns the next ticket that can be used @@ -374,16 +380,7 @@ func (s *ticketStore) ticketRegistered(t ticketRef) { // // A ticket can be returned more than once with <= zero wait time in case // the ticket contains multiple topics. -func (s *ticketStore) nextRegisterableTicket() (t *ticketRef, wait time.Duration) { - defer func() { - if t == nil { - debugLog(" nil") - } else { - debugLog(fmt.Sprintf(" node = %x sn = %v wait = %v", t.t.node.ID[:8], t.t.serial, wait)) - } - }() - - debugLog("nextRegisterableTicket()") +func (s *ticketStore) nextRegisterableTicket() (*ticketRef, time.Duration) { now := mclock.Now() if s.nextTicketCached != nil { return s.nextTicketCached, time.Duration(s.nextTicketCached.topicRegTime() - now) @@ -412,9 +409,8 @@ func (s *ticketStore) nextRegisterableTicket() (t *ticketRef, wait time.Duration return nil, 0 } if nextTicket.t != nil { - wait = time.Duration(nextTicket.topicRegTime() - now) s.nextTicketCached = &nextTicket - return &nextTicket, wait + return &nextTicket, time.Duration(nextTicket.topicRegTime() - now) } s.lastBucketFetched = bucket } @@ -422,14 +418,17 @@ func (s *ticketStore) nextRegisterableTicket() (t *ticketRef, wait time.Duration // removeTicket removes a ticket from the ticket store func (s *ticketStore) removeTicketRef(ref ticketRef) { - debugLog(fmt.Sprintf("removeTicketRef(node = %x sn = %v)", ref.t.node.ID[:8], ref.t.serial)) + log.Trace("Removing discovery ticket reference", "node", ref.t.node.ID, "serial", ref.t.serial) + topic := ref.topic() - tickets := s.tickets[topic].buckets + tickets := s.tickets[topic] + if tickets == nil { + log.Warn("Removing tickets from unknown topic", "topic", topic) return } bucket := timeBucket(ref.t.regTime[ref.idx] / mclock.AbsTime(ticketTimeBucketLen)) - list := tickets[bucket] + list := tickets.buckets[bucket] idx := -1 for i, bt := range list { if bt.t == ref.t { @@ -442,9 +441,9 @@ func (s *ticketStore) removeTicketRef(ref ticketRef) { } list = append(list[:idx], list[idx+1:]...) if len(list) != 0 { - tickets[bucket] = list + tickets.buckets[bucket] = list } else { - delete(tickets, bucket) + delete(tickets.buckets, bucket) } ref.t.refCnt-- if ref.t.refCnt == 0 { @@ -523,21 +522,21 @@ func (s *ticketStore) adjustWithTicket(now mclock.AbsTime, targetHash common.Has } } -func (s *ticketStore) addTicket(localTime mclock.AbsTime, pingHash []byte, t *ticket) { - debugLog(fmt.Sprintf("add(node = %x sn = %v)", t.node.ID[:8], t.serial)) +func (s *ticketStore) addTicket(localTime mclock.AbsTime, pingHash []byte, ticket *ticket) { + log.Trace("Adding discovery ticket", "node", ticket.node.ID, "serial", ticket.serial) - lastReq, ok := s.nodeLastReq[t.node] + lastReq, ok := s.nodeLastReq[ticket.node] if !(ok && bytes.Equal(pingHash, lastReq.pingHash)) { return } - s.adjustWithTicket(localTime, lastReq.lookup.target, t) + s.adjustWithTicket(localTime, lastReq.lookup.target, ticket) - if lastReq.lookup.radiusLookup || s.nodes[t.node] != nil { + if lastReq.lookup.radiusLookup || s.nodes[ticket.node] != nil { return } topic := lastReq.lookup.topic - topicIdx := t.findIdx(topic) + topicIdx := ticket.findIdx(topic) if topicIdx == -1 { return } @@ -548,29 +547,29 @@ func (s *ticketStore) addTicket(localTime mclock.AbsTime, pingHash []byte, t *ti } if _, ok := s.tickets[topic]; ok { - wait := t.regTime[topicIdx] - localTime + wait := ticket.regTime[topicIdx] - localTime rnd := rand.ExpFloat64() if rnd > 10 { rnd = 10 } if float64(wait) < float64(keepTicketConst)+float64(keepTicketExp)*rnd { // use the ticket to register this topic - //fmt.Println("addTicket", t.node.ID[:8], t.node.addr().String(), t.serial, t.pong) - s.addTicketRef(ticketRef{t, topicIdx}) + //fmt.Println("addTicket", ticket.node.ID[:8], ticket.node.addr().String(), ticket.serial, ticket.pong) + s.addTicketRef(ticketRef{ticket, topicIdx}) } } - if t.refCnt > 0 { + if ticket.refCnt > 0 { s.nextTicketCached = nil - s.nodes[t.node] = t + s.nodes[ticket.node] = ticket } } func (s *ticketStore) getNodeTicket(node *Node) *ticket { if s.nodes[node] == nil { - debugLog(fmt.Sprintf("getNodeTicket(%x) sn = nil", node.ID[:8])) + log.Trace("Retrieving node ticket", "node", node.ID, "serial", nil) } else { - debugLog(fmt.Sprintf("getNodeTicket(%x) sn = %v", node.ID[:8], s.nodes[node].serial)) + log.Trace("Retrieving node ticket", "node", node.ID, "serial", s.nodes[node].serial) } return s.nodes[node] } diff --git a/p2p/discv5/topic.go b/p2p/discv5/topic.go index b6bea013c7..e7a7f8e02a 100644 --- a/p2p/discv5/topic.go +++ b/p2p/discv5/topic.go @@ -24,6 +24,7 @@ import ( "time" "github.com/ethereum/go-ethereum/common/mclock" + "github.com/ethereum/go-ethereum/log" ) const ( @@ -235,7 +236,7 @@ func (t *topicTable) deleteEntry(e *topicEntry) { // It is assumed that topics and waitPeriods have the same length. func (t *topicTable) useTicket(node *Node, serialNo uint32, topics []Topic, idx int, issueTime uint64, waitPeriods []uint32) (registered bool) { - debugLog(fmt.Sprintf("useTicket %v %v %v", serialNo, topics, waitPeriods)) + log.Trace("Using discovery ticket", "serial", serialNo, "topics", topics, "waits", waitPeriods) //fmt.Println("useTicket", serialNo, topics, waitPeriods) t.collectGarbage() From f7ca03ae875c7c78191bf38f6ce1cc4bbe5361c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 28 Dec 2017 15:18:34 +0200 Subject: [PATCH 03/25] eth, les, light: expose chain config in les node info too (#15732) --- eth/handler.go | 12 ++++++------ ethstats/ethstats.go | 4 ++-- les/handler.go | 17 ++++++++++++++--- light/lightchain.go | 3 +++ 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/eth/handler.go b/eth/handler.go index cd66662d8f..31c3116873 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -744,10 +744,10 @@ func (self *ProtocolManager) txBroadcastLoop() { } } -// EthNodeInfo represents a short summary of the Ethereum sub-protocol metadata known -// about the host peer. -type EthNodeInfo struct { - Network uint64 `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3) +// NodeInfo represents a short summary of the Ethereum sub-protocol metadata +// known about the host peer. +type NodeInfo struct { + Network uint64 `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3, Rinkeby=4) Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules @@ -755,9 +755,9 @@ type EthNodeInfo struct { } // NodeInfo retrieves some protocol metadata about the running host node. -func (self *ProtocolManager) NodeInfo() *EthNodeInfo { +func (self *ProtocolManager) NodeInfo() *NodeInfo { currentBlock := self.blockchain.CurrentBlock() - return &EthNodeInfo{ + return &NodeInfo{ Network: self.networkId, Difficulty: self.blockchain.GetTd(currentBlock.Hash(), currentBlock.NumberU64()), Genesis: self.blockchain.Genesis().Hash(), diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go index 7065d71629..1e27a1e637 100644 --- a/ethstats/ethstats.go +++ b/ethstats/ethstats.go @@ -374,10 +374,10 @@ func (s *Service) login(conn *websocket.Conn) error { var network, protocol string if info := infos.Protocols["eth"]; info != nil { - network = fmt.Sprintf("%d", info.(*eth.EthNodeInfo).Network) + network = fmt.Sprintf("%d", info.(*eth.NodeInfo).Network) protocol = fmt.Sprintf("eth/%d", eth.ProtocolVersions[0]) } else { - network = fmt.Sprintf("%d", infos.Protocols["les"].(*eth.EthNodeInfo).Network) + network = fmt.Sprintf("%d", infos.Protocols["les"].(*les.NodeInfo).Network) protocol = fmt.Sprintf("les/%d", les.ClientProtocolVersions[0]) } auth := &authMsg{ diff --git a/les/handler.go b/les/handler.go index 613fbb79fe..f8cf63952a 100644 --- a/les/handler.go +++ b/les/handler.go @@ -32,7 +32,6 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/event" @@ -73,6 +72,7 @@ func errResp(code errCode, format string, v ...interface{}) error { } type BlockChain interface { + Config() *params.ChainConfig HasHeader(hash common.Hash, number uint64) bool GetHeader(hash common.Hash, number uint64) *types.Header GetHeaderByHash(hash common.Hash) *types.Header @@ -1123,12 +1123,23 @@ func (pm *ProtocolManager) txStatus(hashes []common.Hash) []txStatus { return stats } +// NodeInfo represents a short summary of the Ethereum sub-protocol metadata +// known about the host peer. +type NodeInfo struct { + Network uint64 `json:"network"` // Ethereum network ID (1=Frontier, 2=Morden, Ropsten=3, Rinkeby=4) + Difficulty *big.Int `json:"difficulty"` // Total difficulty of the host's blockchain + Genesis common.Hash `json:"genesis"` // SHA3 hash of the host's genesis block + Config *params.ChainConfig `json:"config"` // Chain configuration for the fork rules + Head common.Hash `json:"head"` // SHA3 hash of the host's best owned block +} + // NodeInfo retrieves some protocol metadata about the running host node. -func (self *ProtocolManager) NodeInfo() *eth.EthNodeInfo { - return ð.EthNodeInfo{ +func (self *ProtocolManager) NodeInfo() *NodeInfo { + return &NodeInfo{ Network: self.networkId, Difficulty: self.blockchain.GetTdByHash(self.blockchain.LastBlockHash()), Genesis: self.blockchain.Genesis().Hash(), + Config: self.blockchain.Config(), Head: self.blockchain.LastBlockHash(), } } diff --git a/light/lightchain.go b/light/lightchain.go index 30baeaccb7..c5c2dcf465 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -457,6 +457,9 @@ func (self *LightChain) GetHeaderByNumberOdr(ctx context.Context, number uint64) return GetHeaderByNumber(ctx, self.odr, number) } +// Config retrieves the header chain's chain configuration. +func (self *LightChain) Config() *params.ChainConfig { return self.hc.Config() } + func (self *LightChain) SyncCht(ctx context.Context) bool { if self.odr.ChtIndexer() == nil { return false From 36a10875c8c1a34aab851e3f65da48ccbb5367ce Mon Sep 17 00:00:00 2001 From: Anton Evangelatov Date: Fri, 29 Dec 2017 21:18:51 +0100 Subject: [PATCH 04/25] p2p/enr: initial implementation (#15585) Initial implementation of ENR according to ethereum/EIPs#778 --- p2p/enr/enr.go | 290 ++++++++++++++++++++++++++++++++++++++++ p2p/enr/enr_test.go | 318 ++++++++++++++++++++++++++++++++++++++++++++ p2p/enr/entries.go | 160 ++++++++++++++++++++++ 3 files changed, 768 insertions(+) create mode 100644 p2p/enr/enr.go create mode 100644 p2p/enr/enr_test.go create mode 100644 p2p/enr/entries.go diff --git a/p2p/enr/enr.go b/p2p/enr/enr.go new file mode 100644 index 0000000000..2c3afb43e9 --- /dev/null +++ b/p2p/enr/enr.go @@ -0,0 +1,290 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +// Package enr implements Ethereum Node Records as defined in EIP-778. A node record holds +// arbitrary information about a node on the peer-to-peer network. +// +// Records contain named keys. To store and retrieve key/values in a record, use the Entry +// interface. +// +// Records must be signed before transmitting them to another node. Decoding a record verifies +// its signature. When creating a record, set the entries you want, then call Sign to add the +// signature. Modifying a record invalidates the signature. +// +// Package enr supports the "secp256k1-keccak" identity scheme. +package enr + +import ( + "bytes" + "crypto/ecdsa" + "errors" + "fmt" + "io" + "sort" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/crypto/sha3" + "github.com/ethereum/go-ethereum/rlp" +) + +const SizeLimit = 300 // maximum encoded size of a node record in bytes + +const ID_SECP256k1_KECCAK = ID("secp256k1-keccak") // the default identity scheme + +var ( + errNoID = errors.New("unknown or unspecified identity scheme") + errInvalidSigsize = errors.New("invalid signature size") + errInvalidSig = errors.New("invalid signature") + errNotSorted = errors.New("record key/value pairs are not sorted by key") + errDuplicateKey = errors.New("record contains duplicate key") + errIncompletePair = errors.New("record contains incomplete k/v pair") + errTooBig = fmt.Errorf("record bigger than %d bytes", SizeLimit) + errEncodeUnsigned = errors.New("can't encode unsigned record") + errNotFound = errors.New("no such key in record") +) + +// Record represents a node record. The zero value is an empty record. +type Record struct { + seq uint64 // sequence number + signature []byte // the signature + raw []byte // RLP encoded record + pairs []pair // sorted list of all key/value pairs +} + +// pair is a key/value pair in a record. +type pair struct { + k string + v rlp.RawValue +} + +// Signed reports whether the record has a valid signature. +func (r *Record) Signed() bool { + return r.signature != nil +} + +// Seq returns the sequence number. +func (r *Record) Seq() uint64 { + return r.seq +} + +// SetSeq updates the record sequence number. This invalidates any signature on the record. +// Calling SetSeq is usually not required because signing the redord increments the +// sequence number. +func (r *Record) SetSeq(s uint64) { + r.signature = nil + r.raw = nil + r.seq = s +} + +// Load retrieves the value of a key/value pair. The given Entry must be a pointer and will +// be set to the value of the entry in the record. +// +// Errors returned by Load are wrapped in KeyError. You can distinguish decoding errors +// from missing keys using the IsNotFound function. +func (r *Record) Load(e Entry) error { + i := sort.Search(len(r.pairs), func(i int) bool { return r.pairs[i].k >= e.ENRKey() }) + if i < len(r.pairs) && r.pairs[i].k == e.ENRKey() { + if err := rlp.DecodeBytes(r.pairs[i].v, e); err != nil { + return &KeyError{Key: e.ENRKey(), Err: err} + } + return nil + } + return &KeyError{Key: e.ENRKey(), Err: errNotFound} +} + +// Set adds or updates the given entry in the record. +// It panics if the value can't be encoded. +func (r *Record) Set(e Entry) { + r.signature = nil + r.raw = nil + blob, err := rlp.EncodeToBytes(e) + if err != nil { + panic(fmt.Errorf("enr: can't encode %s: %v", e.ENRKey(), err)) + } + + i := sort.Search(len(r.pairs), func(i int) bool { return r.pairs[i].k >= e.ENRKey() }) + + if i < len(r.pairs) && r.pairs[i].k == e.ENRKey() { + // element is present at r.pairs[i] + r.pairs[i].v = blob + return + } else if i < len(r.pairs) { + // insert pair before i-th elem + el := pair{e.ENRKey(), blob} + r.pairs = append(r.pairs, pair{}) + copy(r.pairs[i+1:], r.pairs[i:]) + r.pairs[i] = el + return + } + + // element should be placed at the end of r.pairs + r.pairs = append(r.pairs, pair{e.ENRKey(), blob}) +} + +// EncodeRLP implements rlp.Encoder. Encoding fails if +// the record is unsigned. +func (r Record) EncodeRLP(w io.Writer) error { + if !r.Signed() { + return errEncodeUnsigned + } + _, err := w.Write(r.raw) + return err +} + +// DecodeRLP implements rlp.Decoder. Decoding verifies the signature. +func (r *Record) DecodeRLP(s *rlp.Stream) error { + raw, err := s.Raw() + if err != nil { + return err + } + if len(raw) > SizeLimit { + return errTooBig + } + + // Decode the RLP container. + dec := Record{raw: raw} + s = rlp.NewStream(bytes.NewReader(raw), 0) + if _, err := s.List(); err != nil { + return err + } + if err = s.Decode(&dec.signature); err != nil { + return err + } + if err = s.Decode(&dec.seq); err != nil { + return err + } + // The rest of the record contains sorted k/v pairs. + var prevkey string + for i := 0; ; i++ { + var kv pair + if err := s.Decode(&kv.k); err != nil { + if err == rlp.EOL { + break + } + return err + } + if err := s.Decode(&kv.v); err != nil { + if err == rlp.EOL { + return errIncompletePair + } + return err + } + if i > 0 { + if kv.k == prevkey { + return errDuplicateKey + } + if kv.k < prevkey { + return errNotSorted + } + } + dec.pairs = append(dec.pairs, kv) + prevkey = kv.k + } + if err := s.ListEnd(); err != nil { + return err + } + + // Verify signature. + if err = dec.verifySignature(); err != nil { + return err + } + *r = dec + return nil +} + +type s256raw []byte + +func (s256raw) ENRKey() string { return "secp256k1" } + +// NodeAddr returns the node address. The return value will be nil if the record is +// unsigned. +func (r *Record) NodeAddr() []byte { + var entry s256raw + if r.Load(&entry) != nil { + return nil + } + return crypto.Keccak256(entry) +} + +// Sign signs the record with the given private key. It updates the record's identity +// scheme, public key and increments the sequence number. Sign returns an error if the +// encoded record is larger than the size limit. +func (r *Record) Sign(privkey *ecdsa.PrivateKey) error { + r.seq = r.seq + 1 + r.Set(ID_SECP256k1_KECCAK) + r.Set(Secp256k1(privkey.PublicKey)) + return r.signAndEncode(privkey) +} + +func (r *Record) appendPairs(list []interface{}) []interface{} { + list = append(list, r.seq) + for _, p := range r.pairs { + list = append(list, p.k, p.v) + } + return list +} + +func (r *Record) signAndEncode(privkey *ecdsa.PrivateKey) error { + // Put record elements into a flat list. Leave room for the signature. + list := make([]interface{}, 1, len(r.pairs)*2+2) + list = r.appendPairs(list) + + // Sign the tail of the list. + h := sha3.NewKeccak256() + rlp.Encode(h, list[1:]) + sig, err := crypto.Sign(h.Sum(nil), privkey) + if err != nil { + return err + } + sig = sig[:len(sig)-1] // remove v + + // Put signature in front. + r.signature, list[0] = sig, sig + r.raw, err = rlp.EncodeToBytes(list) + if err != nil { + return err + } + if len(r.raw) > SizeLimit { + return errTooBig + } + return nil +} + +func (r *Record) verifySignature() error { + // Get identity scheme, public key, signature. + var id ID + var entry s256raw + if err := r.Load(&id); err != nil { + return err + } else if id != ID_SECP256k1_KECCAK { + return errNoID + } + if err := r.Load(&entry); err != nil { + return err + } else if len(entry) != 33 { + return fmt.Errorf("invalid public key") + } + + // Verify the signature. + list := make([]interface{}, 0, len(r.pairs)*2+1) + list = r.appendPairs(list) + h := sha3.NewKeccak256() + rlp.Encode(h, list) + if !crypto.VerifySignature(entry, h.Sum(nil), r.signature) { + return errInvalidSig + } + return nil +} diff --git a/p2p/enr/enr_test.go b/p2p/enr/enr_test.go new file mode 100644 index 0000000000..ce7767d105 --- /dev/null +++ b/p2p/enr/enr_test.go @@ -0,0 +1,318 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package enr + +import ( + "bytes" + "encoding/hex" + "fmt" + "math/rand" + "testing" + "time" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + privkey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + pubkey = &privkey.PublicKey +) + +var rnd = rand.New(rand.NewSource(time.Now().UnixNano())) + +func randomString(strlen int) string { + b := make([]byte, strlen) + rnd.Read(b) + return string(b) +} + +// TestGetSetID tests encoding/decoding and setting/getting of the ID key. +func TestGetSetID(t *testing.T) { + id := ID("someid") + var r Record + r.Set(id) + + var id2 ID + require.NoError(t, r.Load(&id2)) + assert.Equal(t, id, id2) +} + +// TestGetSetIP4 tests encoding/decoding and setting/getting of the IP4 key. +func TestGetSetIP4(t *testing.T) { + ip := IP4{192, 168, 0, 3} + var r Record + r.Set(ip) + + var ip2 IP4 + require.NoError(t, r.Load(&ip2)) + assert.Equal(t, ip, ip2) +} + +// TestGetSetIP6 tests encoding/decoding and setting/getting of the IP6 key. +func TestGetSetIP6(t *testing.T) { + ip := IP6{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68} + var r Record + r.Set(ip) + + var ip2 IP6 + require.NoError(t, r.Load(&ip2)) + assert.Equal(t, ip, ip2) +} + +// TestGetSetDiscPort tests encoding/decoding and setting/getting of the DiscPort key. +func TestGetSetDiscPort(t *testing.T) { + port := DiscPort(30309) + var r Record + r.Set(port) + + var port2 DiscPort + require.NoError(t, r.Load(&port2)) + assert.Equal(t, port, port2) +} + +// TestGetSetSecp256k1 tests encoding/decoding and setting/getting of the Secp256k1 key. +func TestGetSetSecp256k1(t *testing.T) { + var r Record + if err := r.Sign(privkey); err != nil { + t.Fatal(err) + } + + var pk Secp256k1 + require.NoError(t, r.Load(&pk)) + assert.EqualValues(t, pubkey, &pk) +} + +func TestLoadErrors(t *testing.T) { + var r Record + ip4 := IP4{127, 0, 0, 1} + r.Set(ip4) + + // Check error for missing keys. + var ip6 IP6 + err := r.Load(&ip6) + if !IsNotFound(err) { + t.Error("IsNotFound should return true for missing key") + } + assert.Equal(t, &KeyError{Key: ip6.ENRKey(), Err: errNotFound}, err) + + // Check error for invalid keys. + var list []uint + err = r.Load(WithEntry(ip4.ENRKey(), &list)) + kerr, ok := err.(*KeyError) + if !ok { + t.Fatalf("expected KeyError, got %T", err) + } + assert.Equal(t, kerr.Key, ip4.ENRKey()) + assert.Error(t, kerr.Err) + if IsNotFound(err) { + t.Error("IsNotFound should return false for decoding errors") + } +} + +// TestSortedGetAndSet tests that Set produced a sorted pairs slice. +func TestSortedGetAndSet(t *testing.T) { + type pair struct { + k string + v uint32 + } + + for _, tt := range []struct { + input []pair + want []pair + }{ + { + input: []pair{{"a", 1}, {"c", 2}, {"b", 3}}, + want: []pair{{"a", 1}, {"b", 3}, {"c", 2}}, + }, + { + input: []pair{{"a", 1}, {"c", 2}, {"b", 3}, {"d", 4}, {"a", 5}, {"bb", 6}}, + want: []pair{{"a", 5}, {"b", 3}, {"bb", 6}, {"c", 2}, {"d", 4}}, + }, + { + input: []pair{{"c", 2}, {"b", 3}, {"d", 4}, {"a", 5}, {"bb", 6}}, + want: []pair{{"a", 5}, {"b", 3}, {"bb", 6}, {"c", 2}, {"d", 4}}, + }, + } { + var r Record + for _, i := range tt.input { + r.Set(WithEntry(i.k, &i.v)) + } + for i, w := range tt.want { + // set got's key from r.pair[i], so that we preserve order of pairs + got := pair{k: r.pairs[i].k} + assert.NoError(t, r.Load(WithEntry(w.k, &got.v))) + assert.Equal(t, w, got) + } + } +} + +// TestDirty tests record signature removal on setting of new key/value pair in record. +func TestDirty(t *testing.T) { + var r Record + + if r.Signed() { + t.Error("Signed returned true for zero record") + } + if _, err := rlp.EncodeToBytes(r); err != errEncodeUnsigned { + t.Errorf("expected errEncodeUnsigned, got %#v", err) + } + + require.NoError(t, r.Sign(privkey)) + if !r.Signed() { + t.Error("Signed return false for signed record") + } + _, err := rlp.EncodeToBytes(r) + assert.NoError(t, err) + + r.SetSeq(3) + if r.Signed() { + t.Error("Signed returned true for modified record") + } + if _, err := rlp.EncodeToBytes(r); err != errEncodeUnsigned { + t.Errorf("expected errEncodeUnsigned, got %#v", err) + } +} + +// TestGetSetOverwrite tests value overwrite when setting a new value with an existing key in record. +func TestGetSetOverwrite(t *testing.T) { + var r Record + + ip := IP4{192, 168, 0, 3} + r.Set(ip) + + ip2 := IP4{192, 168, 0, 4} + r.Set(ip2) + + var ip3 IP4 + require.NoError(t, r.Load(&ip3)) + assert.Equal(t, ip2, ip3) +} + +// TestSignEncodeAndDecode tests signing, RLP encoding and RLP decoding of a record. +func TestSignEncodeAndDecode(t *testing.T) { + var r Record + r.Set(DiscPort(30303)) + r.Set(IP4{127, 0, 0, 1}) + require.NoError(t, r.Sign(privkey)) + + blob, err := rlp.EncodeToBytes(r) + require.NoError(t, err) + + var r2 Record + require.NoError(t, rlp.DecodeBytes(blob, &r2)) + assert.Equal(t, r, r2) + + blob2, err := rlp.EncodeToBytes(r2) + require.NoError(t, err) + assert.Equal(t, blob, blob2) +} + +func TestNodeAddr(t *testing.T) { + var r Record + if addr := r.NodeAddr(); addr != nil { + t.Errorf("wrong address on empty record: got %v, want %v", addr, nil) + } + + require.NoError(t, r.Sign(privkey)) + expected := "caaa1485d83b18b32ed9ad666026151bf0cae8a0a88c857ae2d4c5be2daa6726" + assert.Equal(t, expected, hex.EncodeToString(r.NodeAddr())) +} + +var pyRecord, _ = hex.DecodeString("f896b840954dc36583c1f4b69ab59b1375f362f06ee99f3723cd77e64b6de6d211c27d7870642a79d4516997f94091325d2a7ca6215376971455fb221d34f35b277149a1018664697363763582765f82696490736563703235366b312d6b656363616b83697034847f00000189736563703235366b31a103ca634cae0d49acb401d8a4c6b6fe8c55b70d115bf400769cc1400f3258cd3138") + +// TestPythonInterop checks that we can decode and verify a record produced by the Python +// implementation. +func TestPythonInterop(t *testing.T) { + var r Record + if err := rlp.DecodeBytes(pyRecord, &r); err != nil { + t.Fatalf("can't decode: %v", err) + } + + var ( + wantAddr, _ = hex.DecodeString("caaa1485d83b18b32ed9ad666026151bf0cae8a0a88c857ae2d4c5be2daa6726") + wantSeq = uint64(1) + wantIP = IP4{127, 0, 0, 1} + wantDiscport = DiscPort(30303) + ) + if r.Seq() != wantSeq { + t.Errorf("wrong seq: got %d, want %d", r.Seq(), wantSeq) + } + if addr := r.NodeAddr(); !bytes.Equal(addr, wantAddr) { + t.Errorf("wrong addr: got %x, want %x", addr, wantAddr) + } + want := map[Entry]interface{}{new(IP4): &wantIP, new(DiscPort): &wantDiscport} + for k, v := range want { + desc := fmt.Sprintf("loading key %q", k.ENRKey()) + if assert.NoError(t, r.Load(k), desc) { + assert.Equal(t, k, v, desc) + } + } +} + +// TestRecordTooBig tests that records bigger than SizeLimit bytes cannot be signed. +func TestRecordTooBig(t *testing.T) { + var r Record + key := randomString(10) + + // set a big value for random key, expect error + r.Set(WithEntry(key, randomString(300))) + if err := r.Sign(privkey); err != errTooBig { + t.Fatalf("expected to get errTooBig, got %#v", err) + } + + // set an acceptable value for random key, expect no error + r.Set(WithEntry(key, randomString(100))) + require.NoError(t, r.Sign(privkey)) +} + +// TestSignEncodeAndDecodeRandom tests encoding/decoding of records containing random key/value pairs. +func TestSignEncodeAndDecodeRandom(t *testing.T) { + var r Record + + // random key/value pairs for testing + pairs := map[string]uint32{} + for i := 0; i < 10; i++ { + key := randomString(7) + value := rnd.Uint32() + pairs[key] = value + r.Set(WithEntry(key, &value)) + } + + require.NoError(t, r.Sign(privkey)) + _, err := rlp.EncodeToBytes(r) + require.NoError(t, err) + + for k, v := range pairs { + desc := fmt.Sprintf("key %q", k) + var got uint32 + buf := WithEntry(k, &got) + require.NoError(t, r.Load(buf), desc) + require.Equal(t, v, got, desc) + } +} + +func BenchmarkDecode(b *testing.B) { + var r Record + for i := 0; i < b.N; i++ { + rlp.DecodeBytes(pyRecord, &r) + } + b.StopTimer() + r.NodeAddr() +} diff --git a/p2p/enr/entries.go b/p2p/enr/entries.go new file mode 100644 index 0000000000..7591e6effb --- /dev/null +++ b/p2p/enr/entries.go @@ -0,0 +1,160 @@ +// Copyright 2017 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package enr + +import ( + "crypto/ecdsa" + "fmt" + "io" + "net" + + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/rlp" +) + +// Entry is implemented by known node record entry types. +// +// To define a new entry that is to be included in a node record, +// create a Go type that satisfies this interface. The type should +// also implement rlp.Decoder if additional checks are needed on the value. +type Entry interface { + ENRKey() string +} + +type generic struct { + key string + value interface{} +} + +func (g generic) ENRKey() string { return g.key } + +func (g generic) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, g.value) +} + +func (g *generic) DecodeRLP(s *rlp.Stream) error { + return s.Decode(g.value) +} + +// WithEntry wraps any value with a key name. It can be used to set and load arbitrary values +// in a record. The value v must be supported by rlp. To use WithEntry with Load, the value +// must be a pointer. +func WithEntry(k string, v interface{}) Entry { + return &generic{key: k, value: v} +} + +// DiscPort is the "discv5" key, which holds the UDP port for discovery v5. +type DiscPort uint16 + +func (v DiscPort) ENRKey() string { return "discv5" } + +// ID is the "id" key, which holds the name of the identity scheme. +type ID string + +func (v ID) ENRKey() string { return "id" } + +// IP4 is the "ip4" key, which holds a 4-byte IPv4 address. +type IP4 net.IP + +func (v IP4) ENRKey() string { return "ip4" } + +// EncodeRLP implements rlp.Encoder. +func (v IP4) EncodeRLP(w io.Writer) error { + ip4 := net.IP(v).To4() + if ip4 == nil { + return fmt.Errorf("invalid IPv4 address: %v", v) + } + return rlp.Encode(w, ip4) +} + +// DecodeRLP implements rlp.Decoder. +func (v *IP4) DecodeRLP(s *rlp.Stream) error { + if err := s.Decode((*net.IP)(v)); err != nil { + return err + } + if len(*v) != 4 { + return fmt.Errorf("invalid IPv4 address, want 4 bytes: %v", *v) + } + return nil +} + +// IP6 is the "ip6" key, which holds a 16-byte IPv6 address. +type IP6 net.IP + +func (v IP6) ENRKey() string { return "ip6" } + +// EncodeRLP implements rlp.Encoder. +func (v IP6) EncodeRLP(w io.Writer) error { + ip6 := net.IP(v) + return rlp.Encode(w, ip6) +} + +// DecodeRLP implements rlp.Decoder. +func (v *IP6) DecodeRLP(s *rlp.Stream) error { + if err := s.Decode((*net.IP)(v)); err != nil { + return err + } + if len(*v) != 16 { + return fmt.Errorf("invalid IPv6 address, want 16 bytes: %v", *v) + } + return nil +} + +// Secp256k1 is the "secp256k1" key, which holds a public key. +type Secp256k1 ecdsa.PublicKey + +func (v Secp256k1) ENRKey() string { return "secp256k1" } + +// EncodeRLP implements rlp.Encoder. +func (v Secp256k1) EncodeRLP(w io.Writer) error { + return rlp.Encode(w, crypto.CompressPubkey((*ecdsa.PublicKey)(&v))) +} + +// DecodeRLP implements rlp.Decoder. +func (v *Secp256k1) DecodeRLP(s *rlp.Stream) error { + buf, err := s.Bytes() + if err != nil { + return err + } + pk, err := crypto.DecompressPubkey(buf) + if err != nil { + return err + } + *v = (Secp256k1)(*pk) + return nil +} + +// KeyError is an error related to a key. +type KeyError struct { + Key string + Err error +} + +// Error implements error. +func (err *KeyError) Error() string { + if err.Err == errNotFound { + return fmt.Sprintf("missing ENR key %q", err.Key) + } + return fmt.Sprintf("ENR key %q: %v", err.Key, err.Err) +} + +// IsNotFound reports whether the given error means that a key/value pair is +// missing from a record. +func IsNotFound(err error) bool { + kerr, ok := err.(*KeyError) + return ok && kerr.Err == errNotFound +} From b9731767af634ff90ae9b387bd035d9bc4b128e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Fri, 29 Dec 2017 23:20:02 +0200 Subject: [PATCH 05/25] accounts/abi: handle named ouputs prefixed with underscores (#15766) * accounts/abi: handle named ouputs prefixed with underscores * accounts/abi: handle collinding outputs for struct unpacks * accounts: handle purely underscore output names --- accounts/abi/argument.go | 30 ++++++++++++++-- accounts/abi/bind/bind.go | 20 +++++++++-- accounts/abi/bind/bind_test.go | 62 ++++++++++++++++++++++++++++++++++ accounts/abi/unpack_test.go | 45 ++++++++++++++++++++++++ 4 files changed, 153 insertions(+), 4 deletions(-) diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index ad17fbf2b1..4540c342f6 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -96,6 +96,20 @@ func (arguments Arguments) unpackTuple(v interface{}, output []byte) error { if err := requireUnpackKind(value, typ, kind, arguments); err != nil { return err } + // If the output interface is a struct, make sure names don't collide + if kind == reflect.Struct { + exists := make(map[string]bool) + for _, arg := range arguments { + field := capitalise(arg.Name) + if field == "" { + return fmt.Errorf("abi: purely underscored output cannot unpack to struct") + } + if exists[field] { + return fmt.Errorf("abi: multiple outputs mapping to the same struct field '%s'", field) + } + exists[field] = true + } + } // `i` counts the nonindexed arguments. // `j` counts the number of complex types. // both `i` and `j` are used to to correctly compute `data` offset. @@ -123,10 +137,10 @@ func (arguments Arguments) unpackTuple(v interface{}, output []byte) error { switch kind { case reflect.Struct: + name := capitalise(arg.Name) for j := 0; j < typ.NumField(); j++ { - field := typ.Field(j) // TODO read tags: `abi:"fieldName"` - if field.Name == strings.ToUpper(arg.Name[:1])+arg.Name[1:] { + if typ.Field(j).Name == name { if err := set(value.Field(j), reflectValue, arg); err != nil { return err } @@ -222,3 +236,15 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { return ret, nil } + +// capitalise makes the first character of a string upper case, also removing any +// prefixing underscores from the variable names. +func capitalise(input string) string { + for len(input) > 0 && input[0] == '_' { + input = input[1:] + } + if len(input) == 0 { + return "" + } + return strings.ToUpper(input[:1]) + input[1:] +} diff --git a/accounts/abi/bind/bind.go b/accounts/abi/bind/bind.go index 4dce79b779..8175e3cb9b 100644 --- a/accounts/abi/bind/bind.go +++ b/accounts/abi/bind/bind.go @@ -304,8 +304,15 @@ var methodNormalizer = map[Lang]func(string) string{ LangJava: decapitalise, } -// capitalise makes the first character of a string upper case. +// capitalise makes the first character of a string upper case, also removing any +// prefixing underscores from the variable names. func capitalise(input string) string { + for len(input) > 0 && input[0] == '_' { + input = input[1:] + } + if len(input) == 0 { + return "" + } return strings.ToUpper(input[:1]) + input[1:] } @@ -315,15 +322,24 @@ func decapitalise(input string) string { } // structured checks whether a method has enough information to return a proper -// Go struct ot if flat returns are needed. +// Go struct or if flat returns are needed. func structured(method abi.Method) bool { if len(method.Outputs) < 2 { return false } + exists := make(map[string]bool) for _, out := range method.Outputs { + // If the name is anonymous, we can't organize into a struct if out.Name == "" { return false } + // If the field name is empty when normalized or collides (var, Var, _var, _Var), + // we can't organize into a struct + field := capitalise(out.Name) + if field == "" || exists[field] { + return false + } + exists[field] = true } return true } diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index 43ed53b922..896441d79c 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -126,6 +126,7 @@ var bindTests = []struct { {"type":"function","name":"namedOutput","constant":true,"inputs":[],"outputs":[{"name":"str","type":"string"}]}, {"type":"function","name":"anonOutput","constant":true,"inputs":[],"outputs":[{"name":"","type":"string"}]}, {"type":"function","name":"namedOutputs","constant":true,"inputs":[],"outputs":[{"name":"str1","type":"string"},{"name":"str2","type":"string"}]}, + {"type":"function","name":"collidingOutputs","constant":true,"inputs":[],"outputs":[{"name":"str","type":"string"},{"name":"Str","type":"string"}]}, {"type":"function","name":"anonOutputs","constant":true,"inputs":[],"outputs":[{"name":"","type":"string"},{"name":"","type":"string"}]}, {"type":"function","name":"mixedOutputs","constant":true,"inputs":[],"outputs":[{"name":"","type":"string"},{"name":"str","type":"string"}]} ] @@ -140,6 +141,7 @@ var bindTests = []struct { str1, err = b.NamedOutput(nil) str1, err = b.AnonOutput(nil) res, _ := b.NamedOutputs(nil) + str1, str2, err = b.CollidingOutputs(nil) str1, str2, err = b.AnonOutputs(nil) str1, str2, err = b.MixedOutputs(nil) @@ -447,6 +449,66 @@ var bindTests = []struct { } `, }, + { + `Underscorer`, + ` + contract Underscorer { + function UnderscoredOutput() constant returns (int _int, string _string) { + return (314, "pi"); + } + function LowerLowerCollision() constant returns (int _res, int res) { + return (1, 2); + } + function LowerUpperCollision() constant returns (int _res, int Res) { + return (1, 2); + } + function UpperLowerCollision() constant returns (int _Res, int res) { + return (1, 2); + } + function UpperUpperCollision() constant returns (int _Res, int Res) { + return (1, 2); + } + function PurelyUnderscoredOutput() constant returns (int _, int res) { + return (1, 2); + } + function AllPurelyUnderscoredOutput() constant returns (int _, int __) { + return (1, 2); + } + } + `, `6060604052341561000f57600080fd5b6103498061001e6000396000f300606060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806303a592131461008857806367e6633d146100b85780639df484851461014d578063af7486ab1461017d578063b564b34d146101ad578063e02ab24d146101dd578063e409ca451461020d575b600080fd5b341561009357600080fd5b61009b61023d565b604051808381526020018281526020019250505060405180910390f35b34156100c357600080fd5b6100cb610252565b6040518083815260200180602001828103825283818151815260200191508051906020019080838360005b838110156101115780820151818401526020810190506100f6565b50505050905090810190601f16801561013e5780820380516001836020036101000a031916815260200191505b50935050505060405180910390f35b341561015857600080fd5b6101606102a0565b604051808381526020018281526020019250505060405180910390f35b341561018857600080fd5b6101906102b5565b604051808381526020018281526020019250505060405180910390f35b34156101b857600080fd5b6101c06102ca565b604051808381526020018281526020019250505060405180910390f35b34156101e857600080fd5b6101f06102df565b604051808381526020018281526020019250505060405180910390f35b341561021857600080fd5b6102206102f4565b604051808381526020018281526020019250505060405180910390f35b60008060016002819150809050915091509091565b600061025c610309565b61013a8090506040805190810160405280600281526020017f7069000000000000000000000000000000000000000000000000000000000000815250915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b60008060016002819150809050915091509091565b6020604051908101604052806000815250905600a165627a7a72305820c11dcfa136fc7d182ee4d34f0b12d988496228f7e2d02d2b5376d996ca1743d00029`, + `[{"constant":true,"inputs":[],"name":"LowerUpperCollision","outputs":[{"name":"_res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UnderscoredOutput","outputs":[{"name":"_int","type":"int256"},{"name":"_string","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperLowerCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"AllPurelyUnderscoredOutput","outputs":[{"name":"_","type":"int256"},{"name":"__","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"UpperUpperCollision","outputs":[{"name":"_Res","type":"int256"},{"name":"Res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"LowerLowerCollision","outputs":[{"name":"_res","type":"int256"},{"name":"res","type":"int256"}],"payable":false,"stateMutability":"view","type":"function"}]`, + ` + // Generate a new random account and a funded simulator + key, _ := crypto.GenerateKey() + auth := bind.NewKeyedTransactor(key) + sim := backends.NewSimulatedBackend(core.GenesisAlloc{auth.From: {Balance: big.NewInt(10000000000)}}) + + // Deploy a underscorer tester contract and execute a structured call on it + _, _, underscorer, err := DeployUnderscorer(auth, sim) + if err != nil { + t.Fatalf("Failed to deploy underscorer contract: %v", err) + } + sim.Commit() + + // Verify that underscored return values correctly parse into structs + if res, err := underscorer.UnderscoredOutput(nil); err != nil { + t.Errorf("Failed to call constant function: %v", err) + } else if res.Int.Cmp(big.NewInt(314)) != 0 || res.String != "pi" { + t.Errorf("Invalid result, want: {314, \"pi\"}, got: %+v", res) + } + // Verify that underscored and non-underscored name collisions force tuple outputs + var a, b *big.Int + + a, b, _ = underscorer.LowerLowerCollision(nil) + a, b, _ = underscorer.LowerUpperCollision(nil) + a, b, _ = underscorer.UpperLowerCollision(nil) + a, b, _ = underscorer.UpperUpperCollision(nil) + a, b, _ = underscorer.PurelyUnderscoredOutput(nil) + a, b, _ = underscorer.AllPurelyUnderscoredOutput(nil) + + fmt.Println(a, b, err) + `, + }, } // Tests that packages generated by the binder can be successfully compiled and diff --git a/accounts/abi/unpack_test.go b/accounts/abi/unpack_test.go index 3910950732..4d7fe638c4 100644 --- a/accounts/abi/unpack_test.go +++ b/accounts/abi/unpack_test.go @@ -259,6 +259,51 @@ var unpackTests = []unpackTest{ enc: "000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", want: [3]*big.Int{big.NewInt(1), big.NewInt(2), big.NewInt(3)}, }, + // struct outputs + { + def: `[{"name":"int1","type":"int256"},{"name":"int2","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + Int1 *big.Int + Int2 *big.Int + }{big.NewInt(1), big.NewInt(2)}, + }, + { + def: `[{"name":"int","type":"int256"},{"name":"Int","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + Int1 *big.Int + Int2 *big.Int + }{}, + err: "abi: multiple outputs mapping to the same struct field 'Int'", + }, + { + def: `[{"name":"int","type":"int256"},{"name":"_int","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + Int1 *big.Int + Int2 *big.Int + }{}, + err: "abi: multiple outputs mapping to the same struct field 'Int'", + }, + { + def: `[{"name":"Int","type":"int256"},{"name":"_int","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + Int1 *big.Int + Int2 *big.Int + }{}, + err: "abi: multiple outputs mapping to the same struct field 'Int'", + }, + { + def: `[{"name":"Int","type":"int256"},{"name":"_","type":"int256"}]`, + enc: "00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002", + want: struct { + Int1 *big.Int + Int2 *big.Int + }{}, + err: "abi: purely underscored output cannot unpack to struct", + }, } func TestUnpack(t *testing.T) { From 908faf8cd715c873e4b5fdbb7af8d4f496702d84 Mon Sep 17 00:00:00 2001 From: sunxiaojun2014 Date: Sun, 31 Dec 2017 19:38:39 +0800 Subject: [PATCH 06/25] consensus/ethash: fix overdue link (#15786) --- consensus/ethash/consensus.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 5fe67c8510..0a2f1520ec 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -381,7 +381,7 @@ func calcDifficultyByzantium(time uint64, parent *types.Header) *big.Int { // the difficulty that a new block should have when created at time given the // parent block's time and difficulty. The calculation uses the Homestead rules. func calcDifficultyHomestead(time uint64, parent *types.Header) *big.Int { - // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.mediawiki + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-2.md // algorithm: // diff = (parent_diff + // (parent_diff / 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)) From 6cd6b921ac57480d95af8b9bec2424e1f89fa196 Mon Sep 17 00:00:00 2001 From: Alex Wu Date: Tue, 2 Jan 2018 17:55:03 +0800 Subject: [PATCH 07/25] crypto: ensure private keys are < N (#15745) Fixes #15744 --- crypto/crypto.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/crypto/crypto.go b/crypto/crypto.go index e51726e624..1c4d5a2e02 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -97,6 +97,16 @@ func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) { return nil, fmt.Errorf("invalid length, need %d bits", priv.Params().BitSize) } priv.D = new(big.Int).SetBytes(d) + + // The priv.D must < N + if priv.D.Cmp(secp256k1_N) >= 0 { + return nil, fmt.Errorf("invalid private key, >=N") + } + // The priv.D must not be zero or negative. + if priv.D.Sign() <= 0 { + return nil, fmt.Errorf("invalid private key, zero or negative") + } + priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d) if priv.PublicKey.X == nil { return nil, errors.New("invalid private key") From b98aa3b4f169b1210e187d1ba6c402d052ad70c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 2 Jan 2018 12:13:24 +0200 Subject: [PATCH 08/25] whisper/whisper2: fix Go 1.10 vet issues on type mismatches (#15783) --- whisper/whisperv2/whisper.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/whisper/whisperv2/whisper.go b/whisper/whisperv2/whisper.go index 61c36918d4..e111a34146 100644 --- a/whisper/whisperv2/whisper.go +++ b/whisper/whisperv2/whisper.go @@ -262,7 +262,7 @@ func (self *Whisper) add(envelope *Envelope) error { // Insert the message into the tracked pool hash := envelope.Hash() if _, ok := self.messages[hash]; ok { - log.Trace(fmt.Sprintf("whisper envelope already cached: %x\n", envelope)) + log.Trace(fmt.Sprintf("whisper envelope already cached: %x\n", hash)) return nil } self.messages[hash] = envelope @@ -277,7 +277,7 @@ func (self *Whisper) add(envelope *Envelope) error { // Notify the local node of a message arrival go self.postEvent(envelope) } - log.Trace(fmt.Sprintf("cached whisper envelope %x\n", envelope)) + log.Trace(fmt.Sprintf("cached whisper envelope %x\n", hash)) return nil } From 6882943e3921b2c51d4ae079d9e5720aa7c90c7a Mon Sep 17 00:00:00 2001 From: Deepak Sharma Date: Tue, 2 Jan 2018 15:57:33 +0530 Subject: [PATCH 09/25] containers/docker: change docker images to go1.9 (#15789) --- containers/docker/develop-alpine/Dockerfile | 2 +- containers/docker/develop-ubuntu/Dockerfile | 6 ++++-- containers/docker/master-alpine/Dockerfile | 2 +- containers/docker/master-ubuntu/Dockerfile | 6 ++++-- 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/containers/docker/develop-alpine/Dockerfile b/containers/docker/develop-alpine/Dockerfile index d239129d53..1f3e1112ec 100644 --- a/containers/docker/develop-alpine/Dockerfile +++ b/containers/docker/develop-alpine/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.5 +FROM alpine:3.7 RUN \ apk add --update go git make gcc musl-dev linux-headers ca-certificates && \ diff --git a/containers/docker/develop-ubuntu/Dockerfile b/containers/docker/develop-ubuntu/Dockerfile index c79becb55a..8c4fe9f595 100644 --- a/containers/docker/develop-ubuntu/Dockerfile +++ b/containers/docker/develop-ubuntu/Dockerfile @@ -1,12 +1,14 @@ FROM ubuntu:xenial +ENV PATH=/usr/lib/go-1.9/bin:$PATH + RUN \ apt-get update && apt-get upgrade -q -y && \ - apt-get install -y --no-install-recommends golang git make gcc libc-dev ca-certificates && \ + apt-get install -y --no-install-recommends golang-1.9 git make gcc libc-dev ca-certificates && \ git clone --depth 1 https://github.com/ethereum/go-ethereum && \ (cd go-ethereum && make geth) && \ cp go-ethereum/build/bin/geth /geth && \ - apt-get remove -y golang git make gcc libc-dev && apt autoremove -y && apt-get clean && \ + apt-get remove -y golang-1.9 git make gcc libc-dev && apt autoremove -y && apt-get clean && \ rm -rf /go-ethereum EXPOSE 8545 diff --git a/containers/docker/master-alpine/Dockerfile b/containers/docker/master-alpine/Dockerfile index 44402361d7..c7b71c7263 100644 --- a/containers/docker/master-alpine/Dockerfile +++ b/containers/docker/master-alpine/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.5 +FROM alpine:3.7 RUN \ apk add --update go git make gcc musl-dev linux-headers ca-certificates && \ diff --git a/containers/docker/master-ubuntu/Dockerfile b/containers/docker/master-ubuntu/Dockerfile index cc4fad10c4..bba70abfdd 100644 --- a/containers/docker/master-ubuntu/Dockerfile +++ b/containers/docker/master-ubuntu/Dockerfile @@ -1,12 +1,14 @@ FROM ubuntu:xenial +ENV PATH=/usr/lib/go-1.9/bin:$PATH + RUN \ apt-get update && apt-get upgrade -q -y && \ - apt-get install -y --no-install-recommends golang git make gcc libc-dev ca-certificates && \ + apt-get install -y --no-install-recommends golang-1.9 git make gcc libc-dev ca-certificates && \ git clone --depth 1 --branch release/1.7 https://github.com/ethereum/go-ethereum && \ (cd go-ethereum && make geth) && \ cp go-ethereum/build/bin/geth /geth && \ - apt-get remove -y golang git make gcc libc-dev && apt autoremove -y && apt-get clean && \ + apt-get remove -y golang-1.9 git make gcc libc-dev && apt autoremove -y && apt-get clean && \ rm -rf /go-ethereum EXPOSE 8545 From 2fe07c203ee7ceae313cedc236d8ef7771768c1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 2 Jan 2018 12:28:07 +0200 Subject: [PATCH 10/25] build: fix version comparison for go1.10 and beyond (#15781) --- build/ci.go | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/build/ci.go b/build/ci.go index 987f0bb18a..37d8c09696 100644 --- a/build/ci.go +++ b/build/ci.go @@ -179,11 +179,17 @@ func doInstall(cmdline []string) { // Check Go version. People regularly open issues about compilation // failure with outdated Go. This should save them the trouble. - if runtime.Version() < "go1.7" && !strings.Contains(runtime.Version(), "devel") { - log.Println("You have Go version", runtime.Version()) - log.Println("go-ethereum requires at least Go version 1.7 and cannot") - log.Println("be compiled with an earlier version. Please upgrade your Go installation.") - os.Exit(1) + if !strings.Contains(runtime.Version(), "devel") { + // Figure out the minor version number since we can't textually compare (1.10 < 1.7) + var minor int + fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor) + + if minor < 7 { + log.Println("You have Go version", runtime.Version()) + log.Println("go-ethereum requires at least Go version 1.7 and cannot") + log.Println("be compiled with an earlier version. Please upgrade your Go installation.") + os.Exit(1) + } } // Compile packages given as arguments, or everything if there are no arguments. packages := []string{"./..."} @@ -257,7 +263,10 @@ func goToolArch(arch string, subcmd string, args ...string) *exec.Cmd { if subcmd == "build" || subcmd == "install" || subcmd == "test" { // Go CGO has a Windows linker error prior to 1.8 (https://github.com/golang/go/issues/8756). // Work around issue by allowing multiple definitions for <1.8 builds. - if runtime.GOOS == "windows" && runtime.Version() < "go1.8" { + var minor int + fmt.Sscanf(strings.TrimPrefix(runtime.Version(), "go1."), "%d", &minor) + + if runtime.GOOS == "windows" && minor < 8 { cmd.Args = append(cmd.Args, []string{"-ldflags", "-extldflags -Wl,--allow-multiple-definition"}...) } } From 9c42a41ed81c0f138236b4ee6490a63092bea3fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 2 Jan 2018 12:38:26 +0200 Subject: [PATCH 11/25] eth/downloader: avoid hidden reference to finished statesync request (#15545) --- eth/downloader/statesync.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/eth/downloader/statesync.go b/eth/downloader/statesync.go index a0b05c9be6..937828b949 100644 --- a/eth/downloader/statesync.go +++ b/eth/downloader/statesync.go @@ -132,7 +132,10 @@ func (d *Downloader) runStateSync(s *stateSync) *stateSync { // Send the next finished request to the current sync: case deliverReqCh <- deliverReq: - finished = append(finished[:0], finished[1:]...) + // Shift out the first request, but also set the emptied slot to nil for GC + copy(finished, finished[1:]) + finished[len(finished)-1] = nil + finished = finished[:len(finished)-1] // Handle incoming state packs: case pack := <-d.stateCh: From 3e0113fff4b83c2d398f5d5041ef8b3052c19819 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 2 Jan 2018 12:40:56 +0200 Subject: [PATCH 12/25] build: set CC through a command-line flag (#15784) This avoids setting CC for the go run invocation, which fails on go1.10. --- .travis.yml | 8 ++++---- build/ci.go | 14 +++++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index cc1b185fce..bc296bf2f1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -87,13 +87,13 @@ matrix: - sudo -E apt-get -yq --no-install-suggests --no-install-recommends --force-yes install gcc-arm-linux-gnueabi libc6-dev-armel-cross gcc-arm-linux-gnueabihf libc6-dev-armhf-cross gcc-aarch64-linux-gnu libc6-dev-arm64-cross - sudo ln -s /usr/include/asm-generic /usr/include/asm - - GOARM=5 CC=arm-linux-gnueabi-gcc go run build/ci.go install -arch arm + - GOARM=5 go run build/ci.go install -arch arm -cc arm-linux-gnueabi-gcc - GOARM=5 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds - - GOARM=6 CC=arm-linux-gnueabi-gcc go run build/ci.go install -arch arm + - GOARM=6 go run build/ci.go install -arch arm -cc arm-linux-gnueabi-gcc - GOARM=6 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds - - GOARM=7 CC=arm-linux-gnueabihf-gcc go run build/ci.go install -arch arm + - GOARM=7 go run build/ci.go install -arch arm -cc arm-linux-gnueabihf-gcc - GOARM=7 go run build/ci.go archive -arch arm -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds - - CC=aarch64-linux-gnu-gcc go run build/ci.go install -arch arm64 + - go run build/ci.go install -arch arm64 -cc aarch64-linux-gnu-gcc - go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds # This builder does the Linux Azure MIPS xgo uploads diff --git a/build/ci.go b/build/ci.go index 37d8c09696..1f98bb8438 100644 --- a/build/ci.go +++ b/build/ci.go @@ -23,7 +23,7 @@ Usage: go run build/ci.go Available commands are: - install [ -arch architecture ] [ packages... ] -- builds packages and executables + install [ -arch architecture ] [ -cc compiler ] [ packages... ] -- builds packages and executables test [ -coverage ] [ packages... ] -- runs the tests lint -- runs certain pre-selected linters archive [ -arch architecture ] [ -type zip|tar ] [ -signer key-envvar ] [ -upload dest ] -- archives build artefacts @@ -173,6 +173,7 @@ func main() { func doInstall(cmdline []string) { var ( arch = flag.String("arch", "", "Architecture to cross build for") + cc = flag.String("cc", "", "C compiler to cross build with") ) flag.CommandLine.Parse(cmdline) env := build.Env() @@ -213,7 +214,7 @@ func doInstall(cmdline []string) { } } // Seems we are cross compiling, work around forbidden GOBIN - goinstall := goToolArch(*arch, "install", buildFlags(env)...) + goinstall := goToolArch(*arch, *cc, "install", buildFlags(env)...) goinstall.Args = append(goinstall.Args, "-v") goinstall.Args = append(goinstall.Args, []string{"-buildmode", "archive"}...) goinstall.Args = append(goinstall.Args, packages...) @@ -227,7 +228,7 @@ func doInstall(cmdline []string) { } for name := range pkgs { if name == "main" { - gobuild := goToolArch(*arch, "build", buildFlags(env)...) + gobuild := goToolArch(*arch, *cc, "build", buildFlags(env)...) gobuild.Args = append(gobuild.Args, "-v") gobuild.Args = append(gobuild.Args, []string{"-o", executablePath(cmd.Name())}...) gobuild.Args = append(gobuild.Args, "."+string(filepath.Separator)+filepath.Join("cmd", cmd.Name())) @@ -255,10 +256,10 @@ func buildFlags(env build.Environment) (flags []string) { } func goTool(subcmd string, args ...string) *exec.Cmd { - return goToolArch(runtime.GOARCH, subcmd, args...) + return goToolArch(runtime.GOARCH, os.Getenv("CC"), subcmd, args...) } -func goToolArch(arch string, subcmd string, args ...string) *exec.Cmd { +func goToolArch(arch string, cc string, subcmd string, args ...string) *exec.Cmd { cmd := build.GoTool(subcmd, args...) if subcmd == "build" || subcmd == "install" || subcmd == "test" { // Go CGO has a Windows linker error prior to 1.8 (https://github.com/golang/go/issues/8756). @@ -277,6 +278,9 @@ func goToolArch(arch string, subcmd string, args ...string) *exec.Cmd { cmd.Env = append(cmd.Env, "CGO_ENABLED=1") cmd.Env = append(cmd.Env, "GOARCH="+arch) } + if cc != "" { + cmd.Env = append(cmd.Env, "CC="+cc) + } for _, e := range os.Environ() { if strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "GOBIN=") { continue From d2533d0efbb005a826f0950bbd1cb73a82fe90fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 2 Jan 2018 12:41:47 +0200 Subject: [PATCH 13/25] vendor: update github.com/rjeczalik/notify for go1.10 (#15785) --- vendor/github.com/rjeczalik/notify/README.md | 2 +- .../github.com/rjeczalik/notify/appveyor.yml | 2 +- vendor/github.com/rjeczalik/notify/debug.go | 50 +++++++++++- .../rjeczalik/notify/debug_debug.go | 36 +-------- .../rjeczalik/notify/debug_nodebug.go | 9 +++ vendor/github.com/rjeczalik/notify/doc.go | 7 +- vendor/github.com/rjeczalik/notify/event.go | 2 +- .../rjeczalik/notify/event_inotify.go | 40 +++++----- .../rjeczalik/notify/event_readdcw.go | 14 +++- vendor/github.com/rjeczalik/notify/node.go | 7 +- .../rjeczalik/notify/watcher_fen.go | 11 +-- .../rjeczalik/notify/watcher_fsevents.go | 8 -- .../rjeczalik/notify/watcher_fsevents_cgo.go | 6 +- .../notify/watcher_fsevents_go1.10.go | 9 +++ .../notify/watcher_fsevents_go1.9.go | 14 ++++ .../rjeczalik/notify/watcher_inotify.go | 79 +++++++++++-------- .../rjeczalik/notify/watcher_kqueue.go | 14 ++-- .../rjeczalik/notify/watcher_readdcw.go | 50 +++++++----- .../rjeczalik/notify/watcher_trigger.go | 21 ++++- vendor/vendor.json | 6 +- 20 files changed, 229 insertions(+), 158 deletions(-) create mode 100644 vendor/github.com/rjeczalik/notify/debug_nodebug.go create mode 100644 vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.10.go create mode 100644 vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.9.go diff --git a/vendor/github.com/rjeczalik/notify/README.md b/vendor/github.com/rjeczalik/notify/README.md index a728d1dd04..02a5f32908 100644 --- a/vendor/github.com/rjeczalik/notify/README.md +++ b/vendor/github.com/rjeczalik/notify/README.md @@ -18,4 +18,4 @@ Filesystem event notification library on steroids. (under active development) - [github.com/rjeczalik/cmd/notify](https://godoc.org/github.com/rjeczalik/cmd/notify) - [github.com/cortesi/devd](https://github.com/cortesi/devd) - [github.com/cortesi/modd](https://github.com/cortesi/modd) - +- [github.com/syncthing/syncthing-inotify](https://github.com/syncthing/syncthing-inotify) diff --git a/vendor/github.com/rjeczalik/notify/appveyor.yml b/vendor/github.com/rjeczalik/notify/appveyor.yml index 8e762d05cb..a495bd7c73 100644 --- a/vendor/github.com/rjeczalik/notify/appveyor.yml +++ b/vendor/github.com/rjeczalik/notify/appveyor.yml @@ -16,7 +16,7 @@ install: build_script: - go tool vet -all . - go build ./... - - go test -v -race ./... + - go test -v -timeout 60s -race ./... test: off diff --git a/vendor/github.com/rjeczalik/notify/debug.go b/vendor/github.com/rjeczalik/notify/debug.go index bd9bc468df..2a3eb33700 100644 --- a/vendor/github.com/rjeczalik/notify/debug.go +++ b/vendor/github.com/rjeczalik/notify/debug.go @@ -2,10 +2,52 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. -// +build !debug - package notify -func dbgprint(...interface{}) {} +import ( + "log" + "os" + "runtime" + "strings" +) -func dbgprintf(string, ...interface{}) {} +var dbgprint func(...interface{}) + +var dbgprintf func(string, ...interface{}) + +var dbgcallstack func(max int) []string + +func init() { + if _, ok := os.LookupEnv("NOTIFY_DEBUG"); ok || debugTag { + log.SetOutput(os.Stdout) + log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds) + dbgprint = func(v ...interface{}) { + v = append([]interface{}{"[D] "}, v...) + log.Println(v...) + } + dbgprintf = func(format string, v ...interface{}) { + format = "[D] " + format + log.Printf(format, v...) + } + dbgcallstack = func(max int) []string { + pc, stack := make([]uintptr, max), make([]string, 0, max) + runtime.Callers(2, pc) + for _, pc := range pc { + if f := runtime.FuncForPC(pc); f != nil { + fname := f.Name() + idx := strings.LastIndex(fname, string(os.PathSeparator)) + if idx != -1 { + stack = append(stack, fname[idx+1:]) + } else { + stack = append(stack, fname) + } + } + } + return stack + } + return + } + dbgprint = func(v ...interface{}) {} + dbgprintf = func(format string, v ...interface{}) {} + dbgcallstack = func(max int) []string { return nil } +} diff --git a/vendor/github.com/rjeczalik/notify/debug_debug.go b/vendor/github.com/rjeczalik/notify/debug_debug.go index f0622917f5..6fca891ab3 100644 --- a/vendor/github.com/rjeczalik/notify/debug_debug.go +++ b/vendor/github.com/rjeczalik/notify/debug_debug.go @@ -6,38 +6,4 @@ package notify -import ( - "fmt" - "os" - "runtime" - "strings" -) - -func dbgprint(v ...interface{}) { - fmt.Printf("[D] ") - fmt.Print(v...) - fmt.Printf("\n\n") -} - -func dbgprintf(format string, v ...interface{}) { - fmt.Printf("[D] ") - fmt.Printf(format, v...) - fmt.Printf("\n\n") -} - -func dbgcallstack(max int) []string { - pc, stack := make([]uintptr, max), make([]string, 0, max) - runtime.Callers(2, pc) - for _, pc := range pc { - if f := runtime.FuncForPC(pc); f != nil { - fname := f.Name() - idx := strings.LastIndex(fname, string(os.PathSeparator)) - if idx != -1 { - stack = append(stack, fname[idx+1:]) - } else { - stack = append(stack, fname) - } - } - } - return stack -} +var debugTag bool = true diff --git a/vendor/github.com/rjeczalik/notify/debug_nodebug.go b/vendor/github.com/rjeczalik/notify/debug_nodebug.go new file mode 100644 index 0000000000..be391a2769 --- /dev/null +++ b/vendor/github.com/rjeczalik/notify/debug_nodebug.go @@ -0,0 +1,9 @@ +// Copyright (c) 2014-2015 The Notify Authors. All rights reserved. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +// +build !debug + +package notify + +var debugTag bool = false diff --git a/vendor/github.com/rjeczalik/notify/doc.go b/vendor/github.com/rjeczalik/notify/doc.go index 8a99ddda62..60543c0838 100644 --- a/vendor/github.com/rjeczalik/notify/doc.go +++ b/vendor/github.com/rjeczalik/notify/doc.go @@ -12,11 +12,14 @@ // source file. // // On top of filesystem watchers notify maintains a watchpoint tree, which provides -// strategy for creating and closing filesystem watches and dispatching filesystem +// a strategy for creating and closing filesystem watches and dispatching filesystem // events to user channels. // // An event set is just an event list joint using bitwise OR operator // into a single event value. +// Both the platform-independent (see Constants) and specific events can be used. +// Refer to the event_*.go source files for information about the available +// events. // // A filesystem watch or just a watch is platform-specific entity which represents // a single path registered for notifications for specific event set. Setting a watch @@ -35,6 +38,6 @@ // A watchpoint is a list of user channel and event set pairs for particular // path (watchpoint tree's node). A single watchpoint can contain multiple // different user channels registered to listen for one or more events. A single -// user channel can be registered in one or more watchpoints, recurisve and +// user channel can be registered in one or more watchpoints, recursive and // non-recursive ones as well. package notify diff --git a/vendor/github.com/rjeczalik/notify/event.go b/vendor/github.com/rjeczalik/notify/event.go index e045edcecc..c128841972 100644 --- a/vendor/github.com/rjeczalik/notify/event.go +++ b/vendor/github.com/rjeczalik/notify/event.go @@ -73,7 +73,7 @@ func (e Event) String() string { // // https://developer.apple.com/library/mac/documentation/Darwin/Reference/FSEvents_Ref/index.html#//apple_ref/doc/constant_group/FSEventStreamEventFlags // -// Under Linux (inotify) Sys() always returns a non-nil *syscall.InotifyEvent +// Under Linux (inotify) Sys() always returns a non-nil *unix.InotifyEvent // value, defined as: // // type InotifyEvent struct { diff --git a/vendor/github.com/rjeczalik/notify/event_inotify.go b/vendor/github.com/rjeczalik/notify/event_inotify.go index 82954a9b38..1f32bb73e0 100644 --- a/vendor/github.com/rjeczalik/notify/event_inotify.go +++ b/vendor/github.com/rjeczalik/notify/event_inotify.go @@ -6,7 +6,7 @@ package notify -import "syscall" +import "golang.org/x/sys/unix" // Platform independent event values. const ( @@ -25,18 +25,18 @@ const ( // Inotify specific masks are legal, implemented events that are guaranteed to // work with notify package on linux-based systems. const ( - InAccess = Event(syscall.IN_ACCESS) // File was accessed - InModify = Event(syscall.IN_MODIFY) // File was modified - InAttrib = Event(syscall.IN_ATTRIB) // Metadata changed - InCloseWrite = Event(syscall.IN_CLOSE_WRITE) // Writtable file was closed - InCloseNowrite = Event(syscall.IN_CLOSE_NOWRITE) // Unwrittable file closed - InOpen = Event(syscall.IN_OPEN) // File was opened - InMovedFrom = Event(syscall.IN_MOVED_FROM) // File was moved from X - InMovedTo = Event(syscall.IN_MOVED_TO) // File was moved to Y - InCreate = Event(syscall.IN_CREATE) // Subfile was created - InDelete = Event(syscall.IN_DELETE) // Subfile was deleted - InDeleteSelf = Event(syscall.IN_DELETE_SELF) // Self was deleted - InMoveSelf = Event(syscall.IN_MOVE_SELF) // Self was moved + InAccess = Event(unix.IN_ACCESS) // File was accessed + InModify = Event(unix.IN_MODIFY) // File was modified + InAttrib = Event(unix.IN_ATTRIB) // Metadata changed + InCloseWrite = Event(unix.IN_CLOSE_WRITE) // Writtable file was closed + InCloseNowrite = Event(unix.IN_CLOSE_NOWRITE) // Unwrittable file closed + InOpen = Event(unix.IN_OPEN) // File was opened + InMovedFrom = Event(unix.IN_MOVED_FROM) // File was moved from X + InMovedTo = Event(unix.IN_MOVED_TO) // File was moved to Y + InCreate = Event(unix.IN_CREATE) // Subfile was created + InDelete = Event(unix.IN_DELETE) // Subfile was deleted + InDeleteSelf = Event(unix.IN_DELETE_SELF) // Self was deleted + InMoveSelf = Event(unix.IN_MOVE_SELF) // Self was moved ) var osestr = map[Event]string{ @@ -56,15 +56,15 @@ var osestr = map[Event]string{ // Inotify behavior events are not **currently** supported by notify package. const ( - inDontFollow = Event(syscall.IN_DONT_FOLLOW) - inExclUnlink = Event(syscall.IN_EXCL_UNLINK) - inMaskAdd = Event(syscall.IN_MASK_ADD) - inOneshot = Event(syscall.IN_ONESHOT) - inOnlydir = Event(syscall.IN_ONLYDIR) + inDontFollow = Event(unix.IN_DONT_FOLLOW) + inExclUnlink = Event(unix.IN_EXCL_UNLINK) + inMaskAdd = Event(unix.IN_MASK_ADD) + inOneshot = Event(unix.IN_ONESHOT) + inOnlydir = Event(unix.IN_ONLYDIR) ) type event struct { - sys syscall.InotifyEvent + sys unix.InotifyEvent path string event Event } @@ -72,4 +72,4 @@ type event struct { func (e *event) Event() Event { return e.event } func (e *event) Path() string { return e.path } func (e *event) Sys() interface{} { return &e.sys } -func (e *event) isDir() (bool, error) { return e.sys.Mask&syscall.IN_ISDIR != 0, nil } +func (e *event) isDir() (bool, error) { return e.sys.Mask&unix.IN_ISDIR != 0, nil } diff --git a/vendor/github.com/rjeczalik/notify/event_readdcw.go b/vendor/github.com/rjeczalik/notify/event_readdcw.go index 11ead9e297..f7b82de0c4 100644 --- a/vendor/github.com/rjeczalik/notify/event_readdcw.go +++ b/vendor/github.com/rjeczalik/notify/event_readdcw.go @@ -27,7 +27,11 @@ const ( dirmarker ) -// ReadDirectoryChangesW filters. +// ReadDirectoryChangesW filters +// On Windows the following events can be passed to Watch. A different set of +// events (see actions below) are received on the channel passed to Watch. +// For more information refer to +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365465(v=vs.85).aspx const ( FileNotifyChangeFileName = Event(syscall.FILE_NOTIFY_CHANGE_FILE_NAME) FileNotifyChangeDirName = Event(syscall.FILE_NOTIFY_CHANGE_DIR_NAME) @@ -48,7 +52,13 @@ const ( // this flag should be declared in: http://golang.org/src/pkg/syscall/ztypes_windows.go const syscallFileNotifyChangeSecurity = 0x00000100 -// ReadDirectoryChangesW actions. +// ReadDirectoryChangesW actions +// The following events are returned on the channel passed to Watch, but cannot +// be passed to Watch itself (see filters above). You can find a table showing +// the relation between actions and filteres at +// https://github.com/rjeczalik/notify/issues/10#issuecomment-66179535 +// The msdn documentation on actions is part of +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364391(v=vs.85).aspx const ( FileActionAdded = Event(syscall.FILE_ACTION_ADDED) << 12 FileActionRemoved = Event(syscall.FILE_ACTION_REMOVED) << 12 diff --git a/vendor/github.com/rjeczalik/notify/node.go b/vendor/github.com/rjeczalik/notify/node.go index 29c1bb20af..aced8b9c44 100644 --- a/vendor/github.com/rjeczalik/notify/node.go +++ b/vendor/github.com/rjeczalik/notify/node.go @@ -6,7 +6,6 @@ package notify import ( "errors" - "fmt" "io/ioutil" "os" "path/filepath" @@ -71,7 +70,11 @@ Traverse: case errSkip: continue Traverse default: - return fmt.Errorf("error while traversing %q: %v", nd.Name, err) + return &os.PathError{ + Op: "error while traversing", + Path: nd.Name, + Err: err, + } } // TODO(rjeczalik): tolerate open failures - add failed names to // AddDirError and notify users which names are not added to the tree. diff --git a/vendor/github.com/rjeczalik/notify/watcher_fen.go b/vendor/github.com/rjeczalik/notify/watcher_fen.go index dd069f2a26..dfe77f2f1d 100644 --- a/vendor/github.com/rjeczalik/notify/watcher_fen.go +++ b/vendor/github.com/rjeczalik/notify/watcher_fen.go @@ -33,14 +33,7 @@ type fen struct { // watched is a data structure representing watched file/directory. type watched struct { - // p is a path to watched file/directory - p string - // fi provides information about watched file/dir - fi os.FileInfo - // eDir represents events watched directly - eDir Event - // eNonDir represents events watched indirectly - eNonDir Event + trgWatched } // Stop implements trigger. @@ -55,7 +48,7 @@ func (f *fen) Close() (err error) { // NewWatched implements trigger. func (*fen) NewWatched(p string, fi os.FileInfo) (*watched, error) { - return &watched{p: p, fi: fi}, nil + return &watched{trgWatched{p: p, fi: fi}}, nil } // Record implements trigger. diff --git a/vendor/github.com/rjeczalik/notify/watcher_fsevents.go b/vendor/github.com/rjeczalik/notify/watcher_fsevents.go index 9062c17c7f..7d9b97b65d 100644 --- a/vendor/github.com/rjeczalik/notify/watcher_fsevents.go +++ b/vendor/github.com/rjeczalik/notify/watcher_fsevents.go @@ -12,8 +12,6 @@ import ( "sync/atomic" ) -// TODO(rjeczalik): get rid of calls to canonical, it's tree responsibility - const ( failure = uint32(FSEventsMustScanSubDirs | FSEventsUserDropped | FSEventsKernelDropped) filter = uint32(FSEventsCreated | FSEventsRemoved | FSEventsRenamed | @@ -189,9 +187,6 @@ func newWatcher(c chan<- EventInfo) watcher { } func (fse *fsevents) watch(path string, event Event, isrec int32) (err error) { - if path, err = canonical(path); err != nil { - return err - } if _, ok := fse.watches[path]; ok { return errAlreadyWatched } @@ -211,9 +206,6 @@ func (fse *fsevents) watch(path string, event Event, isrec int32) (err error) { } func (fse *fsevents) unwatch(path string) (err error) { - if path, err = canonical(path); err != nil { - return - } w, ok := fse.watches[path] if !ok { return errNotWatched diff --git a/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go b/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go index 5be64632e8..fb70de6af0 100644 --- a/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go +++ b/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go @@ -48,7 +48,7 @@ var wg sync.WaitGroup // used to wait until the runloop starts // started and is ready via the wg. It also serves purpose of a dummy source, // thanks to it the runloop does not return as it also has at least one source // registered. -var source = C.CFRunLoopSourceCreate(nil, 0, &C.CFRunLoopSourceContext{ +var source = C.CFRunLoopSourceCreate(refZero, 0, &C.CFRunLoopSourceContext{ perform: (C.CFRunLoopPerformCallBack)(C.gosource), }) @@ -159,8 +159,8 @@ func (s *stream) Start() error { return nil } wg.Wait() - p := C.CFStringCreateWithCStringNoCopy(nil, C.CString(s.path), C.kCFStringEncodingUTF8, nil) - path := C.CFArrayCreate(nil, (*unsafe.Pointer)(unsafe.Pointer(&p)), 1, nil) + p := C.CFStringCreateWithCStringNoCopy(refZero, C.CString(s.path), C.kCFStringEncodingUTF8, refZero) + path := C.CFArrayCreate(refZero, (*unsafe.Pointer)(unsafe.Pointer(&p)), 1, nil) ctx := C.FSEventStreamContext{} ref := C.EventStreamCreate(&ctx, C.uintptr_t(s.info), path, C.FSEventStreamEventId(atomic.LoadUint64(&since)), latency, flags) if ref == nilstream { diff --git a/vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.10.go b/vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.10.go new file mode 100644 index 0000000000..0edd3782f5 --- /dev/null +++ b/vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.10.go @@ -0,0 +1,9 @@ +// Copyright (c) 2017 The Notify Authors. All rights reserved. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +// +build darwin,!kqueue,go1.10 + +package notify + +const refZero = 0 diff --git a/vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.9.go b/vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.9.go new file mode 100644 index 0000000000..b81c3c1859 --- /dev/null +++ b/vendor/github.com/rjeczalik/notify/watcher_fsevents_go1.9.go @@ -0,0 +1,14 @@ +// Copyright (c) 2017 The Notify Authors. All rights reserved. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +// +build darwin,!kqueue,cgo,!go1.10 + +package notify + +/* +#include +*/ +import "C" + +var refZero = (*C.struct___CFAllocator)(nil) diff --git a/vendor/github.com/rjeczalik/notify/watcher_inotify.go b/vendor/github.com/rjeczalik/notify/watcher_inotify.go index 3ceaa8f3ab..d082baca0f 100644 --- a/vendor/github.com/rjeczalik/notify/watcher_inotify.go +++ b/vendor/github.com/rjeczalik/notify/watcher_inotify.go @@ -13,14 +13,15 @@ import ( "runtime" "sync" "sync/atomic" - "syscall" "unsafe" + + "golang.org/x/sys/unix" ) // eventBufferSize defines the size of the buffer given to read(2) function. One // should not depend on this value, since it was arbitrary chosen and may be // changed in the future. -const eventBufferSize = 64 * (syscall.SizeofInotifyEvent + syscall.PathMax + 1) +const eventBufferSize = 64 * (unix.SizeofInotifyEvent + unix.PathMax + 1) // consumersCount defines the number of consumers in producer-consumer based // implementation. Each consumer is run in a separate goroutine and has read @@ -43,7 +44,7 @@ type inotify struct { fd int32 // inotify file descriptor pipefd []int // pipe's read and write descriptors epfd int // epoll descriptor - epes []syscall.EpollEvent // epoll events + epes []unix.EpollEvent // epoll events buffer [eventBufferSize]byte // inotify event buffer wg sync.WaitGroup // wait group used to close main loop c chan<- EventInfo // event dispatcher channel @@ -56,13 +57,13 @@ func newWatcher(c chan<- EventInfo) watcher { fd: invalidDescriptor, pipefd: []int{invalidDescriptor, invalidDescriptor}, epfd: invalidDescriptor, - epes: make([]syscall.EpollEvent, 0), + epes: make([]unix.EpollEvent, 0), c: c, } runtime.SetFinalizer(i, func(i *inotify) { i.epollclose() if i.fd != invalidDescriptor { - syscall.Close(int(i.fd)) + unix.Close(int(i.fd)) } }) return i @@ -82,13 +83,13 @@ func (i *inotify) Rewatch(path string, _, newevent Event) error { // one. If called for the first time, this function initializes inotify filesystem // monitor and starts producer-consumers goroutines. func (i *inotify) watch(path string, e Event) (err error) { - if e&^(All|Event(syscall.IN_ALL_EVENTS)) != 0 { + if e&^(All|Event(unix.IN_ALL_EVENTS)) != 0 { return errors.New("notify: unknown event") } if err = i.lazyinit(); err != nil { return } - iwd, err := syscall.InotifyAddWatch(int(i.fd), path, encode(e)) + iwd, err := unix.InotifyAddWatch(int(i.fd), path, encode(e)) if err != nil { return } @@ -119,13 +120,13 @@ func (i *inotify) lazyinit() error { i.Lock() defer i.Unlock() if atomic.LoadInt32(&i.fd) == invalidDescriptor { - fd, err := syscall.InotifyInit() + fd, err := unix.InotifyInit1(unix.IN_CLOEXEC) if err != nil { return err } i.fd = int32(fd) if err = i.epollinit(); err != nil { - _, _ = i.epollclose(), syscall.Close(int(fd)) // Ignore errors. + _, _ = i.epollclose(), unix.Close(int(fd)) // Ignore errors. i.fd = invalidDescriptor return err } @@ -145,33 +146,33 @@ func (i *inotify) lazyinit() error { // with inotify event queue and the read end of the pipe are added to epoll set. // Note that `fd` member must be set before this function is called. func (i *inotify) epollinit() (err error) { - if i.epfd, err = syscall.EpollCreate1(0); err != nil { + if i.epfd, err = unix.EpollCreate1(0); err != nil { return } - if err = syscall.Pipe(i.pipefd); err != nil { + if err = unix.Pipe(i.pipefd); err != nil { return } - i.epes = []syscall.EpollEvent{ - {Events: syscall.EPOLLIN, Fd: i.fd}, - {Events: syscall.EPOLLIN, Fd: int32(i.pipefd[0])}, + i.epes = []unix.EpollEvent{ + {Events: unix.EPOLLIN, Fd: i.fd}, + {Events: unix.EPOLLIN, Fd: int32(i.pipefd[0])}, } - if err = syscall.EpollCtl(i.epfd, syscall.EPOLL_CTL_ADD, int(i.fd), &i.epes[0]); err != nil { + if err = unix.EpollCtl(i.epfd, unix.EPOLL_CTL_ADD, int(i.fd), &i.epes[0]); err != nil { return } - return syscall.EpollCtl(i.epfd, syscall.EPOLL_CTL_ADD, i.pipefd[0], &i.epes[1]) + return unix.EpollCtl(i.epfd, unix.EPOLL_CTL_ADD, i.pipefd[0], &i.epes[1]) } // epollclose closes the file descriptor created by the call to epoll_create(2) // and two file descriptors opened by pipe(2) function. func (i *inotify) epollclose() (err error) { if i.epfd != invalidDescriptor { - if err = syscall.Close(i.epfd); err == nil { + if err = unix.Close(i.epfd); err == nil { i.epfd = invalidDescriptor } } for n, fd := range i.pipefd { if fd != invalidDescriptor { - switch e := syscall.Close(fd); { + switch e := unix.Close(fd); { case e != nil && err == nil: err = e case e == nil: @@ -187,10 +188,10 @@ func (i *inotify) epollclose() (err error) { // one of the event's consumers. If pipe fd became ready, loop function closes // all file descriptors opened by lazyinit method and returns afterwards. func (i *inotify) loop(esch chan<- []*event) { - epes := make([]syscall.EpollEvent, 1) + epes := make([]unix.EpollEvent, 1) fd := atomic.LoadInt32(&i.fd) for { - switch _, err := syscall.EpollWait(i.epfd, epes, -1); err { + switch _, err := unix.EpollWait(i.epfd, epes, -1); err { case nil: switch epes[0].Fd { case fd: @@ -199,17 +200,17 @@ func (i *inotify) loop(esch chan<- []*event) { case int32(i.pipefd[0]): i.Lock() defer i.Unlock() - if err = syscall.Close(int(fd)); err != nil && err != syscall.EINTR { + if err = unix.Close(int(fd)); err != nil && err != unix.EINTR { panic("notify: close(2) error " + err.Error()) } atomic.StoreInt32(&i.fd, invalidDescriptor) - if err = i.epollclose(); err != nil && err != syscall.EINTR { + if err = i.epollclose(); err != nil && err != unix.EINTR { panic("notify: epollclose error " + err.Error()) } close(esch) return } - case syscall.EINTR: + case unix.EINTR: continue default: // We should never reach this line. panic("notify: epoll_wait(2) error " + err.Error()) @@ -220,22 +221,22 @@ func (i *inotify) loop(esch chan<- []*event) { // read reads events from an inotify file descriptor. It does not handle errors // returned from read(2) function since they are not critical to watcher logic. func (i *inotify) read() (es []*event) { - n, err := syscall.Read(int(i.fd), i.buffer[:]) - if err != nil || n < syscall.SizeofInotifyEvent { + n, err := unix.Read(int(i.fd), i.buffer[:]) + if err != nil || n < unix.SizeofInotifyEvent { return } - var sys *syscall.InotifyEvent - nmin := n - syscall.SizeofInotifyEvent + var sys *unix.InotifyEvent + nmin := n - unix.SizeofInotifyEvent for pos, path := 0, ""; pos <= nmin; { - sys = (*syscall.InotifyEvent)(unsafe.Pointer(&i.buffer[pos])) - pos += syscall.SizeofInotifyEvent + sys = (*unix.InotifyEvent)(unsafe.Pointer(&i.buffer[pos])) + pos += unix.SizeofInotifyEvent if path = ""; sys.Len > 0 { endpos := pos + int(sys.Len) path = string(bytes.TrimRight(i.buffer[pos:endpos], "\x00")) pos = endpos } es = append(es, &event{ - sys: syscall.InotifyEvent{ + sys: unix.InotifyEvent{ Wd: sys.Wd, Mask: sys.Mask, Cookie: sys.Cookie, @@ -268,7 +269,7 @@ func (i *inotify) transform(es []*event) []*event { var multi []*event i.RLock() for idx, e := range es { - if e.sys.Mask&(syscall.IN_IGNORED|syscall.IN_Q_OVERFLOW) != 0 { + if e.sys.Mask&(unix.IN_IGNORED|unix.IN_Q_OVERFLOW) != 0 { es[idx] = nil continue } @@ -317,7 +318,7 @@ func encode(e Event) uint32 { // can be nil when the event should not be passed on. func decode(mask Event, e *event) (syse *event) { if sysmask := uint32(mask) & e.sys.Mask; sysmask != 0 { - syse = &event{sys: syscall.InotifyEvent{ + syse = &event{sys: unix.InotifyEvent{ Wd: e.sys.Wd, Mask: e.sys.Mask, Cookie: e.sys.Cookie, @@ -357,7 +358,7 @@ func (i *inotify) Unwatch(path string) (err error) { return errors.New("notify: path " + path + " is already watched") } fd := atomic.LoadInt32(&i.fd) - if _, err = syscall.InotifyRmWatch(int(fd), uint32(iwd)); err != nil { + if err = removeInotifyWatch(fd, iwd); err != nil { return } i.Lock() @@ -377,12 +378,12 @@ func (i *inotify) Close() (err error) { return nil } for iwd := range i.m { - if _, e := syscall.InotifyRmWatch(int(i.fd), uint32(iwd)); e != nil && err == nil { + if e := removeInotifyWatch(i.fd, iwd); e != nil && err == nil { err = e } delete(i.m, iwd) } - switch _, errwrite := syscall.Write(i.pipefd[1], []byte{0x00}); { + switch _, errwrite := unix.Write(i.pipefd[1], []byte{0x00}); { case errwrite != nil && err == nil: err = errwrite fallthrough @@ -394,3 +395,11 @@ func (i *inotify) Close() (err error) { } return } + +// if path was removed, notify already removed the watch and returns EINVAL error +func removeInotifyWatch(fd int32, iwd int32) (err error) { + if _, err = unix.InotifyRmWatch(int(fd), uint32(iwd)); err != nil && err != unix.EINVAL { + return + } + return nil +} diff --git a/vendor/github.com/rjeczalik/notify/watcher_kqueue.go b/vendor/github.com/rjeczalik/notify/watcher_kqueue.go index 6d500b700d..22e3c2c4a4 100644 --- a/vendor/github.com/rjeczalik/notify/watcher_kqueue.go +++ b/vendor/github.com/rjeczalik/notify/watcher_kqueue.go @@ -36,16 +36,9 @@ type kq struct { // watched is a data structure representing watched file/directory. type watched struct { - // p is a path to watched file/directory. - p string + trgWatched // fd is a file descriptor for watched file/directory. fd int - // fi provides information about watched file/dir. - fi os.FileInfo - // eDir represents events watched directly. - eDir Event - // eNonDir represents events watched indirectly. - eNonDir Event } // Stop implements trigger. @@ -66,7 +59,10 @@ func (*kq) NewWatched(p string, fi os.FileInfo) (*watched, error) { if err != nil { return nil, err } - return &watched{fd: fd, p: p, fi: fi}, nil + return &watched{ + trgWatched: trgWatched{p: p, fi: fi}, + fd: fd, + }, nil } // Record implements trigger. diff --git a/vendor/github.com/rjeczalik/notify/watcher_readdcw.go b/vendor/github.com/rjeczalik/notify/watcher_readdcw.go index 5923bfddae..1494fcd799 100644 --- a/vendor/github.com/rjeczalik/notify/watcher_readdcw.go +++ b/vendor/github.com/rjeczalik/notify/watcher_readdcw.go @@ -284,16 +284,18 @@ func (r *readdcw) watch(path string, event Event, recursive bool) (err error) { return } r.Lock() + defer r.Unlock() if wd, ok = r.m[path]; ok { - r.Unlock() + dbgprint("watch: exists already") return } if wd, err = newWatched(r.cph, uint32(event), recursive, path); err != nil { - r.Unlock() return } r.m[path] = wd - r.Unlock() + dbgprint("watch: new watch added") + } else { + dbgprint("watch: exists already") } return nil } @@ -337,33 +339,32 @@ func (r *readdcw) loop() { continue } overEx := (*overlappedEx)(unsafe.Pointer(overlapped)) - if n == 0 { - r.loopstate(overEx) - } else { + if n != 0 { r.loopevent(n, overEx) if err = overEx.parent.readDirChanges(); err != nil { // TODO: error handling } } + r.loopstate(overEx) } } // TODO(pknap) : doc func (r *readdcw) loopstate(overEx *overlappedEx) { - filter := atomic.LoadUint32(&overEx.parent.parent.filter) + r.Lock() + defer r.Unlock() + filter := overEx.parent.parent.filter if filter&onlyMachineStates == 0 { return } if overEx.parent.parent.count--; overEx.parent.parent.count == 0 { switch filter & onlyMachineStates { case stateRewatch: - r.Lock() + dbgprint("loopstate rewatch") overEx.parent.parent.recreate(r.cph) - r.Unlock() case stateUnwatch: - r.Lock() + dbgprint("loopstate unwatch") delete(r.m, syscall.UTF16ToString(overEx.parent.pathw)) - r.Unlock() case stateCPClose: default: panic(`notify: windows loopstate logic error`) @@ -450,8 +451,8 @@ func (r *readdcw) rewatch(path string, oldevent, newevent uint32, recursive bool } var wd *watched r.Lock() - if wd, err = r.nonStateWatched(path); err != nil { - r.Unlock() + defer r.Unlock() + if wd, err = r.nonStateWatchedLocked(path); err != nil { return } if wd.filter&(onlyNotifyChanges|onlyNGlobalEvents) != oldevent { @@ -462,21 +463,19 @@ func (r *readdcw) rewatch(path string, oldevent, newevent uint32, recursive bool if err = wd.closeHandle(); err != nil { wd.filter = oldevent wd.recursive = recursive - r.Unlock() return } - r.Unlock() return } // TODO : pknap -func (r *readdcw) nonStateWatched(path string) (wd *watched, err error) { +func (r *readdcw) nonStateWatchedLocked(path string) (wd *watched, err error) { wd, ok := r.m[path] if !ok || wd == nil { err = errors.New(`notify: ` + path + ` path is unwatched`) return } - if filter := atomic.LoadUint32(&wd.filter); filter&onlyMachineStates != 0 { + if wd.filter&onlyMachineStates != 0 { err = errors.New(`notify: another re/unwatching operation in progress`) return } @@ -497,17 +496,26 @@ func (r *readdcw) RecursiveUnwatch(path string) error { func (r *readdcw) unwatch(path string) (err error) { var wd *watched r.Lock() - if wd, err = r.nonStateWatched(path); err != nil { - r.Unlock() + defer r.Unlock() + if wd, err = r.nonStateWatchedLocked(path); err != nil { return } wd.filter |= stateUnwatch if err = wd.closeHandle(); err != nil { wd.filter &^= stateUnwatch - r.Unlock() return } - r.Unlock() + if _, attrErr := syscall.GetFileAttributes(&wd.pathw[0]); attrErr != nil { + for _, g := range wd.digrip { + if g != nil { + dbgprint("unwatch: posting") + if err = syscall.PostQueuedCompletionStatus(r.cph, 0, 0, (*syscall.Overlapped)(unsafe.Pointer(g.ovlapped))); err != nil { + wd.filter &^= stateUnwatch + return + } + } + } + } return } diff --git a/vendor/github.com/rjeczalik/notify/watcher_trigger.go b/vendor/github.com/rjeczalik/notify/watcher_trigger.go index d079d59b0a..78151f909b 100644 --- a/vendor/github.com/rjeczalik/notify/watcher_trigger.go +++ b/vendor/github.com/rjeczalik/notify/watcher_trigger.go @@ -23,6 +23,7 @@ package notify import ( + "fmt" "os" "path/filepath" "strings" @@ -56,6 +57,19 @@ type trigger interface { IsStop(n interface{}, err error) bool } +// trgWatched is a the base data structure representing watched file/directory. +// The platform specific full data structure (watched) must embed this type. +type trgWatched struct { + // p is a path to watched file/directory. + p string + // fi provides information about watched file/dir. + fi os.FileInfo + // eDir represents events watched directly. + eDir Event + // eNonDir represents events watched indirectly. + eNonDir Event +} + // encode Event to native representation. Implementation is to be provided by // platform specific implementation. var encode func(Event, bool) int64 @@ -117,6 +131,9 @@ func (t *trg) Close() (err error) { dbgprintf("trg: closing native watch failed: %q\n", e) err = nonil(err, e) } + if remaining := len(t.pthLkp); remaining != 0 { + err = nonil(err, fmt.Errorf("Not all watches were removed: len(t.pthLkp) == %v", len(t.pthLkp))) + } t.Unlock() return } @@ -175,7 +192,7 @@ func decode(o int64, w Event) (e Event) { func (t *trg) watch(p string, e Event, fi os.FileInfo) error { if err := t.singlewatch(p, e, dir, fi); err != nil { if err != errAlreadyWatched { - return nil + return err } } if fi.IsDir() { @@ -361,7 +378,7 @@ func (t *trg) singleunwatch(p string, direct mode) error { } if w.eNonDir|w.eDir != 0 { mod := dir - if w.eNonDir == 0 { + if w.eNonDir != 0 { mod = ndir } if err := t.singlewatch(p, w.eNonDir|w.eDir, mod, diff --git a/vendor/vendor.json b/vendor/vendor.json index ddcff21fc1..17844bd8dd 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -286,10 +286,10 @@ "revisionTime": "2016-11-28T21:05:44Z" }, { - "checksumSHA1": "yOMpVYuaPAtsMIo9DvQP8WZqxQs=", + "checksumSHA1": "tnQdt7bxmueZFl0EPrW9YrWiqGg=", "path": "github.com/rjeczalik/notify", - "revision": "9d5aa0c3b735c3340018a4627446c3ea5a04a097", - "revisionTime": "2017-01-28T20:05:44Z" + "revision": "e1801ee34d54c4bf45126ef51fe9750b4e42bee8", + "revisionTime": "2017-12-10T15:45:11Z" }, { "checksumSHA1": "5uqO4ITTDMklKi3uNaE/D9LQ5nM=", From 413cc5b0c80733478f1b94a5e9a509fc7bd3fa4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Tue, 2 Jan 2018 13:48:19 +0200 Subject: [PATCH 14/25] cmd/geth: remove trailing newline in license command (#15782) --- cmd/geth/misccmd.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/geth/misccmd.go b/cmd/geth/misccmd.go index 2e68dcda32..aa9b1ee568 100644 --- a/cmd/geth/misccmd.go +++ b/cmd/geth/misccmd.go @@ -134,7 +134,6 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License -along with geth. If not, see . -`) +along with geth. If not, see .`) return nil } From c495bca4adef24811e92f9dfa5149b32ac81ef65 Mon Sep 17 00:00:00 2001 From: cdetrio Date: Tue, 2 Jan 2018 06:49:17 -0500 Subject: [PATCH 15/25] eth: enable preimage recording when tracing (#15787) --- eth/api_tracer.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/eth/api_tracer.go b/eth/api_tracer.go index 0d0e2a73c3..8ad664e06a 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -667,12 +667,15 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v tracer = vm.NewStructLogger(config.LogConfig) } // Run the transaction with tracing enabled. - vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{Debug: true, Tracer: tracer}) + vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{Debug: true, Tracer: tracer, EnablePreimageRecording: true}) ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) if err != nil { return nil, fmt.Errorf("tracing failed: %v", err) } + if err := core.WritePreimages(api.eth.ChainDb(), vmctx.BlockNumber.Uint64(), statedb.Preimages()); err != nil { + return nil, fmt.Errorf("Error writing preimage from trace: %v", err) + } // Depending on the tracer type, format and return the output switch tracer := tracer.(type) { case *vm.StructLogger: From 5866626b0896bafb74e140bc44ddd24ff9006d91 Mon Sep 17 00:00:00 2001 From: ferhat elmas Date: Tue, 2 Jan 2018 12:50:46 +0100 Subject: [PATCH 16/25] core, p2p/discv5: use time.NewTicker instead of time.Tick (#15747) --- core/blockchain.go | 5 +++-- p2p/discv5/database.go | 6 +++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 325753c7a7..812f9e5621 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1196,10 +1196,11 @@ func (bc *BlockChain) PostChainEvents(events []interface{}, logs []*types.Log) { } func (bc *BlockChain) update() { - futureTimer := time.Tick(5 * time.Second) + futureTimer := time.NewTicker(5 * time.Second) + defer futureTimer.Stop() for { select { - case <-futureTimer: + case <-futureTimer.C: bc.procFutureBlocks() case <-bc.quit: return diff --git a/p2p/discv5/database.go b/p2p/discv5/database.go index a3b044ec18..3c2d5744c3 100644 --- a/p2p/discv5/database.go +++ b/p2p/discv5/database.go @@ -239,14 +239,14 @@ func (db *nodeDB) ensureExpirer() { // expirer should be started in a go routine, and is responsible for looping ad // infinitum and dropping stale data from the database. func (db *nodeDB) expirer() { - tick := time.Tick(nodeDBCleanupCycle) + tick := time.NewTicker(nodeDBCleanupCycle) + defer tick.Stop() for { select { - case <-tick: + case <-tick.C: if err := db.expireNodes(); err != nil { log.Error(fmt.Sprintf("Failed to expire nodedb items: %v", err)) } - case <-db.quit: return } From 72e70bcec2e288e2f5d375290d194fd5832842e2 Mon Sep 17 00:00:00 2001 From: Richard Hart Date: Tue, 2 Jan 2018 07:00:13 -0500 Subject: [PATCH 17/25] console: remove comment about 'invalid' input (#15735) All inputs are saved into history, including 'invalid' inputs. --- console/prompter.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/console/prompter.go b/console/prompter.go index ea03694d41..c477b48178 100644 --- a/console/prompter.go +++ b/console/prompter.go @@ -155,8 +155,7 @@ func (p *terminalPrompter) SetHistory(history []string) { p.State.ReadHistory(strings.NewReader(strings.Join(history, "\n"))) } -// AppendHistory appends an entry to the scrollback history. It should be called -// if and only if the prompt to append was a valid command. +// AppendHistory appends an entry to the scrollback history. func (p *terminalPrompter) AppendHistory(command string) { p.State.AppendHistory(command) } From 85a1eda59e44a32b6c8267889efedca33d3e703b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 3 Jan 2018 09:53:09 +0100 Subject: [PATCH 18/25] eth: uncaptialize tracer preimage error message (#15792) * eth: uncaptialize tracer preimage error message * eth: improve very important error message --- eth/api_tracer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eth/api_tracer.go b/eth/api_tracer.go index 8ad664e06a..26e47dcb6c 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -674,7 +674,7 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v return nil, fmt.Errorf("tracing failed: %v", err) } if err := core.WritePreimages(api.eth.ChainDb(), vmctx.BlockNumber.Uint64(), statedb.Preimages()); err != nil { - return nil, fmt.Errorf("Error writing preimage from trace: %v", err) + return nil, fmt.Errorf("can't write preimage: %v", err) } // Depending on the tracer type, format and return the output switch tracer := tracer.(type) { From 9d48dbf5c2d0401042134d94997be1850bf8499b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 3 Jan 2018 11:58:25 +0100 Subject: [PATCH 19/25] eth: revert tracer preimage recording (#15800) This reverts commits 85a1eda59e (#15792) and c495bca4ad (#15787) because they introduce database writes during tracing. --- eth/api_tracer.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/eth/api_tracer.go b/eth/api_tracer.go index 26e47dcb6c..0d0e2a73c3 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -667,15 +667,12 @@ func (api *PrivateDebugAPI) traceTx(ctx context.Context, message core.Message, v tracer = vm.NewStructLogger(config.LogConfig) } // Run the transaction with tracing enabled. - vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{Debug: true, Tracer: tracer, EnablePreimageRecording: true}) + vmenv := vm.NewEVM(vmctx, statedb, api.config, vm.Config{Debug: true, Tracer: tracer}) ret, gas, failed, err := core.ApplyMessage(vmenv, message, new(core.GasPool).AddGas(message.Gas())) if err != nil { return nil, fmt.Errorf("tracing failed: %v", err) } - if err := core.WritePreimages(api.eth.ChainDb(), vmctx.BlockNumber.Uint64(), statedb.Preimages()); err != nil { - return nil, fmt.Errorf("can't write preimage: %v", err) - } // Depending on the tracer type, format and return the output switch tracer := tracer.(type) { case *vm.StructLogger: From b8caba97099ee5eed33c3b80dd4ea540722e7d8f Mon Sep 17 00:00:00 2001 From: Furkan KAMACI Date: Wed, 3 Jan 2018 15:14:47 +0300 Subject: [PATCH 20/25] various: remove redundant parentheses (#15793) --- accounts/abi/argument.go | 2 +- cmd/swarm/config.go | 2 +- common/bitutil/bitutil.go | 8 ++++---- crypto/ecies/ecies.go | 2 +- eth/handler.go | 4 ++-- les/handler.go | 4 ++-- les/serverpool.go | 2 +- swarm/storage/chunker_test.go | 8 ++++---- swarm/storage/pyramid.go | 2 +- trie/trie.go | 2 +- whisper/whisperv5/filter_test.go | 4 ++-- whisper/whisperv6/filter_test.go | 4 ++-- 12 files changed, 22 insertions(+), 22 deletions(-) diff --git a/accounts/abi/argument.go b/accounts/abi/argument.go index 4540c342f6..04ca6150ad 100644 --- a/accounts/abi/argument.go +++ b/accounts/abi/argument.go @@ -202,7 +202,7 @@ func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) { inputOffset := 0 for _, abiArg := range abiArgs { if abiArg.Type.T == ArrayTy { - inputOffset += (32 * abiArg.Type.Size) + inputOffset += 32 * abiArg.Type.Size } else { inputOffset += 32 } diff --git a/cmd/swarm/config.go b/cmd/swarm/config.go index 33235ca06e..29b5faefa8 100644 --- a/cmd/swarm/config.go +++ b/cmd/swarm/config.go @@ -315,7 +315,7 @@ func checkDeprecated(ctx *cli.Context) { func printConfig(config *bzzapi.Config) string { out, err := tomlSettings.Marshal(&config) if err != nil { - return (fmt.Sprintf("Something is not right with the configuration: %v", err)) + return fmt.Sprintf("Something is not right with the configuration: %v", err) } return string(out) } diff --git a/common/bitutil/bitutil.go b/common/bitutil/bitutil.go index 117616543d..cd3e72169f 100644 --- a/common/bitutil/bitutil.go +++ b/common/bitutil/bitutil.go @@ -40,7 +40,7 @@ func fastXORBytes(dst, a, b []byte) int { dw[i] = aw[i] ^ bw[i] } } - for i := (n - n%wordSize); i < n; i++ { + for i := n - n%wordSize; i < n; i++ { dst[i] = a[i] ^ b[i] } return n @@ -84,7 +84,7 @@ func fastANDBytes(dst, a, b []byte) int { dw[i] = aw[i] & bw[i] } } - for i := (n - n%wordSize); i < n; i++ { + for i := n - n%wordSize; i < n; i++ { dst[i] = a[i] & b[i] } return n @@ -128,7 +128,7 @@ func fastORBytes(dst, a, b []byte) int { dw[i] = aw[i] | bw[i] } } - for i := (n - n%wordSize); i < n; i++ { + for i := n - n%wordSize; i < n; i++ { dst[i] = a[i] | b[i] } return n @@ -168,7 +168,7 @@ func fastTestBytes(p []byte) bool { } } } - for i := (n - n%wordSize); i < n; i++ { + for i := n - n%wordSize; i < n; i++ { if p[i] != 0 { return true } diff --git a/crypto/ecies/ecies.go b/crypto/ecies/ecies.go index 1d5f96ed27..2ed91c895d 100644 --- a/crypto/ecies/ecies.go +++ b/crypto/ecies/ecies.go @@ -314,7 +314,7 @@ func (prv *PrivateKey) Decrypt(rand io.Reader, c, s1, s2 []byte) (m []byte, err switch c[0] { case 2, 3, 4: - rLen = ((prv.PublicKey.Curve.Params().BitSize + 7) / 4) + rLen = (prv.PublicKey.Curve.Params().BitSize + 7) / 4 if len(c) < (rLen + hLen + 1) { err = ErrInvalidMessage return diff --git a/eth/handler.go b/eth/handler.go index 31c3116873..074cffd96f 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -394,14 +394,14 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { case query.Reverse: // Number based traversal towards the genesis block if query.Origin.Number >= query.Skip+1 { - query.Origin.Number -= (query.Skip + 1) + query.Origin.Number -= query.Skip + 1 } else { unknown = true } case !query.Reverse: // Number based traversal towards the leaf block - query.Origin.Number += (query.Skip + 1) + query.Origin.Number += query.Skip + 1 } } return p.SendBlockHeaders(headers) diff --git a/les/handler.go b/les/handler.go index f8cf63952a..e310942ba0 100644 --- a/les/handler.go +++ b/les/handler.go @@ -454,14 +454,14 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { case query.Reverse: // Number based traversal towards the genesis block if query.Origin.Number >= query.Skip+1 { - query.Origin.Number -= (query.Skip + 1) + query.Origin.Number -= query.Skip + 1 } else { unknown = true } case !query.Reverse: // Number based traversal towards the leaf block - query.Origin.Number += (query.Skip + 1) + query.Origin.Number += query.Skip + 1 } } diff --git a/les/serverpool.go b/les/serverpool.go index dc1ea6bf02..a84c29c3ac 100644 --- a/les/serverpool.go +++ b/les/serverpool.go @@ -618,7 +618,7 @@ func (e *knownEntry) Weight() int64 { if e.state != psNotConnected || !e.known || e.delayedRetry { return 0 } - return int64(1000000000 * e.connectStats.recentAvg() * math.Exp(-float64(e.lastConnected.fails)*failDropLn-e.responseStats.recentAvg()/float64(responseScoreTC)-e.delayStats.recentAvg()/float64(delayScoreTC)) * math.Pow((1-e.timeoutStats.recentAvg()), timeoutPow)) + return int64(1000000000 * e.connectStats.recentAvg() * math.Exp(-float64(e.lastConnected.fails)*failDropLn-e.responseStats.recentAvg()/float64(responseScoreTC)-e.delayStats.recentAvg()/float64(delayScoreTC)) * math.Pow(1-e.timeoutStats.recentAvg(), timeoutPow)) } // poolEntryAddress is a separate object because currently it is necessary to remember diff --git a/swarm/storage/chunker_test.go b/swarm/storage/chunker_test.go index 6178a7bb1c..6b828970b6 100644 --- a/swarm/storage/chunker_test.go +++ b/swarm/storage/chunker_test.go @@ -60,7 +60,7 @@ func (self *chunkerTester) Split(chunker Splitter, data io.Reader, size int64, c for { select { case <-timeout: - return errors.New(("Split timeout error")) + return errors.New("Split timeout error") case <-quitC: return nil case chunk := <-chunkC: @@ -97,7 +97,7 @@ func (self *chunkerTester) Append(chunker Splitter, rootKey Key, data io.Reader, for { select { case <-timeout: - return errors.New(("Append timeout error")) + return errors.New("Append timeout error") case <-quitC: return nil case chunk := <-chunkC: @@ -146,7 +146,7 @@ func (self *chunkerTester) Join(chunker Chunker, key Key, c int, chunkC chan *Ch for { select { case <-timeout: - return errors.New(("Join timeout error")) + return errors.New("Join timeout error") case chunk, ok := <-chunkC: if !ok { close(quitC) @@ -155,7 +155,7 @@ func (self *chunkerTester) Join(chunker Chunker, key Key, c int, chunkC chan *Ch // this just mocks the behaviour of a chunk store retrieval stored, success := self.chunks[chunk.Key.String()] if !success { - return errors.New(("Not found")) + return errors.New("Not found") } chunk.SData = stored.SData chunk.Size = int64(binary.LittleEndian.Uint64(chunk.SData[0:8])) diff --git a/swarm/storage/pyramid.go b/swarm/storage/pyramid.go index f2e85cb5b0..19d493405a 100644 --- a/swarm/storage/pyramid.go +++ b/swarm/storage/pyramid.go @@ -338,7 +338,7 @@ func (self *PyramidChunker) loadTree(chunkLevel [][]*TreeEntry, key Key, chunkC chunkLevel[depth-1] = append(chunkLevel[depth-1], newEntry) // Add the rest of the tree - for lvl := (depth - 1); lvl >= 1; lvl-- { + for lvl := depth - 1; lvl >= 1; lvl-- { //TODO(jmozah): instead of loading finished branches and then trim in the end, //avoid loading them in the first place diff --git a/trie/trie.go b/trie/trie.go index c211e75549..7c1b5e1b61 100644 --- a/trie/trie.go +++ b/trie/trie.go @@ -489,7 +489,7 @@ func (t *Trie) Commit() (root common.Hash, err error) { func (t *Trie) CommitTo(db DatabaseWriter) (root common.Hash, err error) { hash, cached, err := t.hashRoot(db) if err != nil { - return (common.Hash{}), err + return common.Hash{}, err } t.root = cached t.cachegen++ diff --git a/whisper/whisperv5/filter_test.go b/whisper/whisperv5/filter_test.go index bd35e7f20f..72568b94e6 100644 --- a/whisper/whisperv5/filter_test.go +++ b/whisper/whisperv5/filter_test.go @@ -88,7 +88,7 @@ func generateTestCases(t *testing.T, SizeTestFilters int) []FilterTestCase { for i := 0; i < SizeTestFilters; i++ { f, _ := generateFilter(t, true) cases[i].f = f - cases[i].alive = (mrand.Int()&int(1) == 0) + cases[i].alive = mrand.Int()&int(1) == 0 } return cases } @@ -122,7 +122,7 @@ func TestInstallFilters(t *testing.T) { for i, testCase := range tst { fil := filters.Get(testCase.id) - exist := (fil != nil) + exist := fil != nil if exist != testCase.alive { t.Fatalf("seed %d: failed alive: %d, %v, %v", seed, i, exist, testCase.alive) } diff --git a/whisper/whisperv6/filter_test.go b/whisper/whisperv6/filter_test.go index dd0de0f6ec..e2877b233c 100644 --- a/whisper/whisperv6/filter_test.go +++ b/whisper/whisperv6/filter_test.go @@ -88,7 +88,7 @@ func generateTestCases(t *testing.T, SizeTestFilters int) []FilterTestCase { for i := 0; i < SizeTestFilters; i++ { f, _ := generateFilter(t, true) cases[i].f = f - cases[i].alive = (mrand.Int()&int(1) == 0) + cases[i].alive = mrand.Int()&int(1) == 0 } return cases } @@ -122,7 +122,7 @@ func TestInstallFilters(t *testing.T) { for i, testCase := range tst { fil := filters.Get(testCase.id) - exist := (fil != nil) + exist := fil != nil if exist != testCase.alive { t.Fatalf("seed %d: failed alive: %d, %v, %v", seed, i, exist, testCase.alive) } From 6f69cdd109b1dd692b8dfb15e7c53d2051fbc946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 13 Nov 2017 13:47:27 +0200 Subject: [PATCH 21/25] all: switch gas limits from big.Int to uint64 --- accounts/abi/bind/backend.go | 2 +- accounts/abi/bind/backends/simulated.go | 28 +-- accounts/abi/bind/base.go | 4 +- accounts/abi/bind/bind_test.go | 1 - accounts/abi/bind/util_test.go | 6 +- accounts/usbwallet/trezor.go | 2 +- cmd/faucet/faucet.go | 2 +- cmd/puppeth/genesis.go | 38 ++-- cmd/utils/flags.go | 4 +- consensus/ethash/algorithm_test.go | 4 +- consensus/ethash/consensus.go | 24 +-- contracts/chequebook/cheque.go | 4 +- contracts/ens/ens.go | 5 +- contracts/ens/ens_test.go | 2 +- core/bench_test.go | 9 +- core/block_validator.go | 36 ++-- core/blockchain.go | 8 +- core/blockchain_test.go | 40 ++-- core/chain_makers.go | 3 +- core/chain_makers_test.go | 6 +- core/database_util_test.go | 14 +- core/evm.go | 2 +- core/gaspool.go | 29 +-- core/gen_genesis.go | 2 + core/genesis.go | 4 +- core/state/journal.go | 2 +- core/state/statedb.go | 17 +- core/state/statedb_test.go | 4 +- core/state_processor.go | 34 ++-- core/state_transition.go | 131 ++++++------- core/tx_list.go | 13 +- core/tx_list_test.go | 3 +- core/tx_pool.go | 11 +- core/tx_pool_test.go | 234 ++++++++++++------------ core/types.go | 6 +- core/types/block.go | 18 +- core/types/block_test.go | 6 +- core/types/gen_header_json.go | 16 +- core/types/gen_receipt_json.go | 17 +- core/types/gen_tx_json.go | 8 +- core/types/receipt.go | 27 ++- core/types/transaction.go | 45 +++-- core/types/transaction_signing_test.go | 8 +- core/types/transaction_test.go | 10 +- core/vm/evm.go | 2 +- core/vm/gas_table.go | 6 +- core/vm/instructions.go | 2 +- core/vm/interface.go | 4 +- core/vm/noop.go | 4 +- core/vm/runtime/env.go | 4 +- eth/bind.go | 10 +- eth/downloader/downloader_test.go | 2 +- eth/fetcher/fetcher_test.go | 2 +- eth/filters/filter_system_test.go | 10 +- eth/filters/filter_test.go | 10 +- eth/handler_test.go | 14 +- eth/helper_test.go | 2 +- eth/tracers/tracers_test.go | 4 +- ethclient/ethclient.go | 12 +- ethstats/ethstats.go | 8 +- interfaces.go | 4 +- internal/ethapi/api.go | 63 +++---- internal/ethapi/backend.go | 3 +- les/handler_test.go | 8 +- les/helper_test.go | 14 +- les/odr_test.go | 8 +- light/lightchain.go | 2 +- light/odr_test.go | 18 +- light/txpool.go | 9 +- light/txpool_test.go | 2 +- miner/worker.go | 3 +- mobile/bind.go | 4 +- mobile/ethclient.go | 4 +- mobile/ethereum.go | 5 +- mobile/types.go | 28 +-- params/protocol_params.go | 20 +- tests/block_test_util.go | 20 +- tests/gen_btheader.go | 16 +- tests/gen_stenv.go | 8 +- tests/gen_tttransaction.go | 8 +- tests/state_test_util.go | 8 +- tests/transaction_test_util.go | 8 +- 82 files changed, 606 insertions(+), 642 deletions(-) diff --git a/accounts/abi/bind/backend.go b/accounts/abi/bind/backend.go index 25b61928e1..a7ca7bfc00 100644 --- a/accounts/abi/bind/backend.go +++ b/accounts/abi/bind/backend.go @@ -85,7 +85,7 @@ type ContractTransactor interface { // There is no guarantee that this is the true gas limit requirement as other // transactions may be added or removed by miners, but it should provide a basis // for setting a reasonable default. - EstimateGas(ctx context.Context, call ethereum.CallMsg) (usedGas *big.Int, err error) + EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) // SendTransaction injects the transaction into the pending pool for execution. SendTransaction(ctx context.Context, tx *types.Transaction) error } diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 2cf6b9f781..81c32e4211 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -200,7 +200,7 @@ func (b *SimulatedBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error // EstimateGas executes the requested code against the currently pending block/state and // returns the used amount of gas. -func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (*big.Int, error) { +func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { b.mu.Lock() defer b.mu.Unlock() @@ -210,16 +210,16 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs hi uint64 cap uint64 ) - if call.Gas != nil && call.Gas.Uint64() >= params.TxGas { - hi = call.Gas.Uint64() + if call.Gas >= params.TxGas { + hi = call.Gas } else { - hi = b.pendingBlock.GasLimit().Uint64() + hi = b.pendingBlock.GasLimit() } cap = hi // Create a helper to check if a gas allowance results in an executable transaction executable := func(gas uint64) bool { - call.Gas = new(big.Int).SetUint64(gas) + call.Gas = gas snapshot := b.pendingState.Snapshot() _, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState) @@ -242,21 +242,21 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs // Reject the transaction as invalid if it still fails at the highest allowance if hi == cap { if !executable(hi) { - return nil, errGasEstimationFailed + return 0, errGasEstimationFailed } } - return new(big.Int).SetUint64(hi), nil + return hi, nil } // callContract implemens common code between normal and pending contract calls. // state is modified during execution, make sure to copy it if necessary. -func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, *big.Int, bool, error) { +func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, uint64, bool, error) { // Ensure message is initialized properly. if call.GasPrice == nil { call.GasPrice = big.NewInt(1) } - if call.Gas == nil || call.Gas.Sign() == 0 { - call.Gas = big.NewInt(50000000) + if call.Gas == 0 { + call.Gas = 50000000 } if call.Value == nil { call.Value = new(big.Int) @@ -271,9 +271,9 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM // Create a new environment which holds all relevant information // about the transaction and calling mechanisms. vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{}) - gaspool := new(core.GasPool).AddGas(math.MaxBig256) - ret, gasUsed, _, failed, err := core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() - return ret, gasUsed, failed, err + gaspool := new(core.GasPool).AddGas(math.MaxUint64) + + return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb() } // SendTransaction updates the pending block to include the given transaction. @@ -328,6 +328,6 @@ func (m callmsg) Nonce() uint64 { return 0 } func (m callmsg) CheckNonce() bool { return false } func (m callmsg) To() *common.Address { return m.CallMsg.To } func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice } -func (m callmsg) Gas() *big.Int { return m.CallMsg.Gas } +func (m callmsg) Gas() uint64 { return m.CallMsg.Gas } func (m callmsg) Value() *big.Int { return m.CallMsg.Value } func (m callmsg) Data() []byte { return m.CallMsg.Data } diff --git a/accounts/abi/bind/base.go b/accounts/abi/bind/base.go index b40bd65e80..2bd683f22f 100644 --- a/accounts/abi/bind/base.go +++ b/accounts/abi/bind/base.go @@ -50,7 +50,7 @@ type TransactOpts struct { Value *big.Int // Funds to transfer along along the transaction (nil = 0 = no funds) GasPrice *big.Int // Gas price to use for the transaction execution (nil = gas price oracle) - GasLimit *big.Int // Gas limit to set for the transaction execution (nil = estimate + 10%) + GasLimit uint64 // Gas limit to set for the transaction execution (0 = estimate) Context context.Context // Network context to support cancellation and timeouts (nil = no timeout) } @@ -189,7 +189,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i } } gasLimit := opts.GasLimit - if gasLimit == nil { + if gasLimit == 0 { // Gas estimation cannot succeed without code for method invocations if contract != nil { if code, err := c.transactor.PendingCodeAt(ensureContext(opts.Context), c.address); err != nil { diff --git a/accounts/abi/bind/bind_test.go b/accounts/abi/bind/bind_test.go index 896441d79c..b56477e0c7 100644 --- a/accounts/abi/bind/bind_test.go +++ b/accounts/abi/bind/bind_test.go @@ -399,7 +399,6 @@ var bindTests = []struct { sim.Commit() // Set the field with automatic estimation and check that it succeeds - auth.GasLimit = nil if _, err := limiter.SetField(auth, "automatic"); err != nil { t.Fatalf("Failed to call automatically gased transaction: %v", err) } diff --git a/accounts/abi/bind/util_test.go b/accounts/abi/bind/util_test.go index d24aa721e5..49e6dc813a 100644 --- a/accounts/abi/bind/util_test.go +++ b/accounts/abi/bind/util_test.go @@ -34,18 +34,18 @@ var testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d var waitDeployedTests = map[string]struct { code string - gas *big.Int + gas uint64 wantAddress common.Address wantErr error }{ "successful deploy": { code: `6060604052600a8060106000396000f360606040526008565b00`, - gas: big.NewInt(3000000), + gas: 3000000, wantAddress: common.HexToAddress("0x3a220f351252089d385b29beca14e27f204c296a"), }, "empty code": { code: ``, - gas: big.NewInt(300000), + gas: 300000, wantErr: bind.ErrNoCodeAfterDeploy, wantAddress: common.HexToAddress("0x3a220f351252089d385b29beca14e27f204c296a"), }, diff --git a/accounts/usbwallet/trezor.go b/accounts/usbwallet/trezor.go index 159cb2ea97..b84a955992 100644 --- a/accounts/usbwallet/trezor.go +++ b/accounts/usbwallet/trezor.go @@ -180,7 +180,7 @@ func (w *trezorDriver) trezorSign(derivationPath []uint32, tx *types.Transaction AddressN: derivationPath, Nonce: new(big.Int).SetUint64(tx.Nonce()).Bytes(), GasPrice: tx.GasPrice().Bytes(), - GasLimit: tx.Gas().Bytes(), + GasLimit: new(big.Int).SetUint64(tx.Gas()).Bytes(), Value: tx.Value().Bytes(), DataLength: &length, } diff --git a/cmd/faucet/faucet.go b/cmd/faucet/faucet.go index 75ec124c11..051f9254ce 100644 --- a/cmd/faucet/faucet.go +++ b/cmd/faucet/faucet.go @@ -473,7 +473,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) { amount = new(big.Int).Mul(amount, new(big.Int).Exp(big.NewInt(5), big.NewInt(int64(msg.Tier)), nil)) amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil)) - tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, big.NewInt(21000), f.price, nil) + tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil) signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainId) if err != nil { f.lock.Unlock() diff --git a/cmd/puppeth/genesis.go b/cmd/puppeth/genesis.go index 5e36f7fce5..f747f47395 100644 --- a/cmd/puppeth/genesis.go +++ b/cmd/puppeth/genesis.go @@ -44,7 +44,7 @@ type cppEthereumGenesisSpec struct { MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"` MinGasLimit hexutil.Uint64 `json:"minGasLimit"` MaxGasLimit hexutil.Uint64 `json:"maxGasLimit"` - GasLimitBoundDivisor *hexutil.Big `json:"gasLimitBoundDivisor"` + GasLimitBoundDivisor hexutil.Uint64 `json:"gasLimitBoundDivisor"` MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"` DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"` DurationLimit *hexutil.Big `json:"durationLimit"` @@ -107,11 +107,11 @@ func newCppEthereumGenesisSpec(network string, genesis *core.Genesis) (*cppEther spec.Params.ChainID = (hexutil.Uint64)(genesis.Config.ChainId.Uint64()) spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize) - spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit.Uint64()) + spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit) spec.Params.MaxGasLimit = (hexutil.Uint64)(math.MaxUint64) spec.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty) spec.Params.DifficultyBoundDivisor = (*hexutil.Big)(params.DifficultyBoundDivisor) - spec.Params.GasLimitBoundDivisor = (*hexutil.Big)(params.GasLimitBoundDivisor) + spec.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor) spec.Params.DurationLimit = (*hexutil.Big)(params.DurationLimit) spec.Params.BlockReward = (*hexutil.Big)(ethash.FrontierBlockReward) @@ -168,26 +168,26 @@ type parityChainSpec struct { Engine struct { Ethash struct { Params struct { - MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"` - DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"` - GasLimitBoundDivisor *hexutil.Big `json:"gasLimitBoundDivisor"` - DurationLimit *hexutil.Big `json:"durationLimit"` - BlockReward *hexutil.Big `json:"blockReward"` - HomesteadTransition uint64 `json:"homesteadTransition"` - EIP150Transition uint64 `json:"eip150Transition"` - EIP160Transition uint64 `json:"eip160Transition"` - EIP161abcTransition uint64 `json:"eip161abcTransition"` - EIP161dTransition uint64 `json:"eip161dTransition"` - EIP649Reward *hexutil.Big `json:"eip649Reward"` - EIP100bTransition uint64 `json:"eip100bTransition"` - EIP649Transition uint64 `json:"eip649Transition"` + MinimumDifficulty *hexutil.Big `json:"minimumDifficulty"` + DifficultyBoundDivisor *hexutil.Big `json:"difficultyBoundDivisor"` + GasLimitBoundDivisor hexutil.Uint64 `json:"gasLimitBoundDivisor"` + DurationLimit *hexutil.Big `json:"durationLimit"` + BlockReward *hexutil.Big `json:"blockReward"` + HomesteadTransition uint64 `json:"homesteadTransition"` + EIP150Transition uint64 `json:"eip150Transition"` + EIP160Transition uint64 `json:"eip160Transition"` + EIP161abcTransition uint64 `json:"eip161abcTransition"` + EIP161dTransition uint64 `json:"eip161dTransition"` + EIP649Reward *hexutil.Big `json:"eip649Reward"` + EIP100bTransition uint64 `json:"eip100bTransition"` + EIP649Transition uint64 `json:"eip649Transition"` } `json:"params"` } `json:"Ethash"` } `json:"engine"` Params struct { MaximumExtraDataSize hexutil.Uint64 `json:"maximumExtraDataSize"` - MinGasLimit *hexutil.Big `json:"minGasLimit"` + MinGasLimit hexutil.Uint64 `json:"minGasLimit"` NetworkID hexutil.Uint64 `json:"networkID"` MaxCodeSize uint64 `json:"maxCodeSize"` EIP155Transition uint64 `json:"eip155Transition"` @@ -270,7 +270,7 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin } spec.Engine.Ethash.Params.MinimumDifficulty = (*hexutil.Big)(params.MinimumDifficulty) spec.Engine.Ethash.Params.DifficultyBoundDivisor = (*hexutil.Big)(params.DifficultyBoundDivisor) - spec.Engine.Ethash.Params.GasLimitBoundDivisor = (*hexutil.Big)(params.GasLimitBoundDivisor) + spec.Engine.Ethash.Params.GasLimitBoundDivisor = (hexutil.Uint64)(params.GasLimitBoundDivisor) spec.Engine.Ethash.Params.DurationLimit = (*hexutil.Big)(params.DurationLimit) spec.Engine.Ethash.Params.BlockReward = (*hexutil.Big)(ethash.FrontierBlockReward) spec.Engine.Ethash.Params.HomesteadTransition = genesis.Config.HomesteadBlock.Uint64() @@ -283,7 +283,7 @@ func newParityChainSpec(network string, genesis *core.Genesis, bootnodes []strin spec.Engine.Ethash.Params.EIP649Transition = genesis.Config.ByzantiumBlock.Uint64() spec.Params.MaximumExtraDataSize = (hexutil.Uint64)(params.MaximumExtraDataSize) - spec.Params.MinGasLimit = (*hexutil.Big)(params.MinGasLimit) + spec.Params.MinGasLimit = (hexutil.Uint64)(params.MinGasLimit) spec.Params.NetworkID = (hexutil.Uint64)(genesis.Config.ChainId.Uint64()) spec.Params.MaxCodeSize = params.MaxCodeSize spec.Params.EIP155Transition = genesis.Config.EIP155Block.Uint64() diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 30edf199c9..734cf6f369 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -313,7 +313,7 @@ var ( TargetGasLimitFlag = cli.Uint64Flag{ Name: "targetgaslimit", Usage: "Target gas limit sets the artificial target gas floor for the blocks to mine", - Value: params.GenesisGasLimit.Uint64(), + Value: params.GenesisGasLimit, } EtherbaseFlag = cli.StringFlag{ Name: "etherbase", @@ -1138,7 +1138,7 @@ func RegisterEthStatsService(stack *node.Node, url string) { // SetupNetwork configures the system for either the main net or some test network. func SetupNetwork(ctx *cli.Context) { // TODO(fjl): move target gas limit into config - params.TargetGasLimit = new(big.Int).SetUint64(ctx.GlobalUint64(TargetGasLimitFlag.Name)) + params.TargetGasLimit = ctx.GlobalUint64(TargetGasLimitFlag.Name) } // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. diff --git a/consensus/ethash/algorithm_test.go b/consensus/ethash/algorithm_test.go index 7765ff9fe6..a54f3b582c 100644 --- a/consensus/ethash/algorithm_test.go +++ b/consensus/ethash/algorithm_test.go @@ -688,8 +688,8 @@ func TestConcurrentDiskCacheGeneration(t *testing.T) { TxHash: common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), ReceiptHash: common.HexToHash("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"), Difficulty: big.NewInt(167925187834220), - GasLimit: big.NewInt(4015682), - GasUsed: big.NewInt(0), + GasLimit: 4015682, + GasUsed: 0, Time: big.NewInt(1488928920), Extra: []byte("www.bw.com"), MixDigest: common.HexToHash("0x3e140b0784516af5e5ec6730f2fb20cca22f32be399b9e4ad77d32541f798cd0"), diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index 0a2f1520ec..0af68c31ab 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -246,24 +246,24 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent * return fmt.Errorf("invalid difficulty: have %v, want %v", header.Difficulty, expected) } // Verify that the gas limit is <= 2^63-1 - if header.GasLimit.Cmp(math.MaxBig63) > 0 { - return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, math.MaxBig63) + cap := uint64(0x7fffffffffffffff) + if header.GasLimit > cap { + return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) } // Verify that the gasUsed is <= gasLimit - if header.GasUsed.Cmp(header.GasLimit) > 0 { - return fmt.Errorf("invalid gasUsed: have %v, gasLimit %v", header.GasUsed, header.GasLimit) + if header.GasUsed > header.GasLimit { + return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) } // Verify that the gas limit remains within allowed bounds - diff := new(big.Int).Set(parent.GasLimit) - diff = diff.Sub(diff, header.GasLimit) - diff.Abs(diff) + diff := int64(parent.GasLimit) - int64(header.GasLimit) + if diff < 0 { + diff *= -1 + } + limit := parent.GasLimit / params.GasLimitBoundDivisor - limit := new(big.Int).Set(parent.GasLimit) - limit = limit.Div(limit, params.GasLimitBoundDivisor) - - if diff.Cmp(limit) >= 0 || header.GasLimit.Cmp(params.MinGasLimit) < 0 { - return fmt.Errorf("invalid gas limit: have %v, want %v += %v", header.GasLimit, parent.GasLimit, limit) + if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit { + return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit) } // Verify that the block number is parent's +1 if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { diff --git a/contracts/chequebook/cheque.go b/contracts/chequebook/cheque.go index 09daa92484..f6335adc65 100644 --- a/contracts/chequebook/cheque.go +++ b/contracts/chequebook/cheque.go @@ -56,8 +56,8 @@ import ( // * watching incoming ether var ( - gasToCash = big.NewInt(2000000) // gas cost of a cash transaction using chequebook - // gasToDeploy = big.NewInt(3000000) + gasToCash = uint64(2000000) // gas cost of a cash transaction using chequebook + // gasToDeploy = uint64(3000000) ) // Backend wraps all methods required for chequebook operation. diff --git a/contracts/ens/ens.go b/contracts/ens/ens.go index c292a1714a..60c3c83ab0 100644 --- a/contracts/ens/ens.go +++ b/contracts/ens/ens.go @@ -19,7 +19,6 @@ package ens //go:generate abigen --sol contract/ens.sol --pkg contract --out contract/ens.go import ( - "math/big" "strings" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -163,7 +162,7 @@ func (self *ENS) Register(name string) (*types.Transaction, error) { } opts := self.TransactOpts - opts.GasLimit = big.NewInt(200000) + opts.GasLimit = 200000 return registrar.Contract.Register(&opts, label, self.TransactOpts.From) } @@ -178,6 +177,6 @@ func (self *ENS) SetContentHash(name string, hash common.Hash) (*types.Transacti } opts := self.TransactOpts - opts.GasLimit = big.NewInt(200000) + opts.GasLimit = 200000 return resolver.Contract.SetContent(&opts, node, hash) } diff --git a/contracts/ens/ens_test.go b/contracts/ens/ens_test.go index 5faa9b1ad4..9ab1375813 100644 --- a/contracts/ens/ens_test.go +++ b/contracts/ens/ens_test.go @@ -37,7 +37,7 @@ func TestENS(t *testing.T) { contractBackend := backends.NewSimulatedBackend(core.GenesisAlloc{addr: {Balance: big.NewInt(1000000000)}}) transactOpts := bind.NewKeyedTransactor(key) // Workaround for bug estimating gas in the call to Register - transactOpts.GasLimit = big.NewInt(1000000) + transactOpts.GasLimit = 1000000 ens, err := DeployENS(transactOpts, contractBackend) if err != nil { diff --git a/core/bench_test.go b/core/bench_test.go index 9c7cd81c4a..f976331d17 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -84,7 +84,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { return func(i int, gen *BlockGen) { toaddr := common.Address{} data := make([]byte, nbytes) - gas := IntrinsicGas(data, false, false) + gas, _ := IntrinsicGas(data, false, false) tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data), types.HomesteadSigner{}, benchRootKey) gen.AddTx(tx) } @@ -93,7 +93,6 @@ func genValueTx(nbytes int) func(int, *BlockGen) { var ( ringKeys = make([]*ecdsa.PrivateKey, 1000) ringAddrs = make([]common.Address, len(ringKeys)) - bigTxGas = new(big.Int).SetUint64(params.TxGas) ) func init() { @@ -113,8 +112,8 @@ func genTxRing(naccounts int) func(int, *BlockGen) { return func(i int, gen *BlockGen) { gas := CalcGasLimit(gen.PrevBlock(i - 1)) for { - gas.Sub(gas, bigTxGas) - if gas.Cmp(bigTxGas) < 0 { + gas -= params.TxGas + if gas < params.TxGas { break } to := (from + 1) % naccounts @@ -122,7 +121,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) { gen.TxNonce(ringAddrs[from]), ringAddrs[to], benchRootFunds, - bigTxGas, + params.TxGas, nil, nil, ) diff --git a/core/block_validator.go b/core/block_validator.go index e9cfd04827..143728bb84 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -18,9 +18,7 @@ package core import ( "fmt" - "math/big" - "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" @@ -76,10 +74,10 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error { // transition, such as amount of used gas, the receipt roots and the state root // itself. ValidateState returns a database batch if the validation was a success // otherwise nil and an error is returned. -func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas *big.Int) error { +func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *state.StateDB, receipts types.Receipts, usedGas uint64) error { header := block.Header() - if block.GasUsed().Cmp(usedGas) != 0 { - return fmt.Errorf("invalid gas used (remote: %v local: %v)", block.GasUsed(), usedGas) + if block.GasUsed() != usedGas { + return fmt.Errorf("invalid gas used (remote: %d local: %d)", block.GasUsed(), usedGas) } // Validate the received block's bloom with the one derived from the generated receipts. // For valid blocks this should always validate to true. @@ -101,17 +99,13 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat } // CalcGasLimit computes the gas limit of the next block after parent. -// The result may be modified by the caller. // This is miner strategy, not consensus protocol. -func CalcGasLimit(parent *types.Block) *big.Int { +func CalcGasLimit(parent *types.Block) uint64 { // contrib = (parentGasUsed * 3 / 2) / 1024 - contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3)) - contrib = contrib.Div(contrib, big.NewInt(2)) - contrib = contrib.Div(contrib, params.GasLimitBoundDivisor) + contrib := (parent.GasUsed() + parent.GasUsed()/2) / params.GasLimitBoundDivisor // decay = parentGasLimit / 1024 -1 - decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor) - decay.Sub(decay, big.NewInt(1)) + decay := parent.GasLimit()/params.GasLimitBoundDivisor - 1 /* strategy: gasLimit of block-to-mine is set based on parent's @@ -120,15 +114,17 @@ func CalcGasLimit(parent *types.Block) *big.Int { at that usage) the amount increased/decreased depends on how far away from parentGasLimit * (2/3) parentGasUsed is. */ - gl := new(big.Int).Sub(parent.GasLimit(), decay) - gl = gl.Add(gl, contrib) - gl.Set(math.BigMax(gl, params.MinGasLimit)) - + limit := parent.GasLimit() - decay + contrib + if limit < params.MinGasLimit { + limit = params.MinGasLimit + } // however, if we're now below the target (TargetGasLimit) we increase the // limit as much as we can (parentGasLimit / 1024 -1) - if gl.Cmp(params.TargetGasLimit) < 0 { - gl.Add(parent.GasLimit(), decay) - gl.Set(math.BigMin(gl, params.TargetGasLimit)) + if limit < params.TargetGasLimit { + limit = parent.GasLimit() + decay + if limit > params.TargetGasLimit { + limit = params.TargetGasLimit + } } - return gl + return limit } diff --git a/core/blockchain.go b/core/blockchain.go index 812f9e5621..737fbe3eee 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -305,7 +305,7 @@ func (bc *BlockChain) FastSyncCommitHead(hash common.Hash) error { } // GasLimit returns the gas limit of the current HEAD block. -func (bc *BlockChain) GasLimit() *big.Int { +func (bc *BlockChain) GasLimit() uint64 { bc.mu.RLock() defer bc.mu.RUnlock() @@ -677,9 +677,9 @@ func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts ty } // The used gas can be calculated based on previous receipts if j == 0 { - receipts[j].GasUsed = new(big.Int).Set(receipts[j].CumulativeGasUsed) + receipts[j].GasUsed = receipts[j].CumulativeGasUsed } else { - receipts[j].GasUsed = new(big.Int).Sub(receipts[j].CumulativeGasUsed, receipts[j-1].CumulativeGasUsed) + receipts[j].GasUsed = receipts[j].CumulativeGasUsed - receipts[j-1].CumulativeGasUsed } // The derived log fields can simply be set from the block and transaction for k := 0; k < len(receipts[j].Logs); k++ { @@ -1002,7 +1002,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks) (int, []interface{}, []*ty events = append(events, ChainSideEvent{block}) } stats.processed++ - stats.usedGas += usedGas.Uint64() + stats.usedGas += usedGas stats.report(chain, i) } // Append a single chain head event if we've progressed the chain diff --git a/core/blockchain_test.go b/core/blockchain_test.go index cb2e471040..26c816027f 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -340,11 +340,11 @@ func testBrokenChain(t *testing.T, full bool) { type bproc struct{} func (bproc) ValidateBody(*types.Block) error { return nil } -func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error { +func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error { return nil } -func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) { - return nil, nil, new(big.Int), nil +func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) { + return nil, nil, 0, nil } func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header { @@ -506,8 +506,8 @@ func testReorgBadHashes(t *testing.T, full bool) { if ncm.CurrentBlock().Hash() != blocks[2].Header().Hash() { t.Errorf("last block hash mismatch: have: %x, want %x", ncm.CurrentBlock().Hash(), blocks[2].Header().Hash()) } - if blocks[2].Header().GasLimit.Cmp(ncm.GasLimit()) != 0 { - t.Errorf("last block gasLimit mismatch: have: %x, want %x", ncm.GasLimit(), blocks[2].Header().GasLimit) + if blocks[2].Header().GasLimit != ncm.GasLimit() { + t.Errorf("last block gasLimit mismatch: have: %d, want %d", ncm.GasLimit(), blocks[2].Header().GasLimit) } } else { if ncm.CurrentHeader().Hash() != headers[2].Hash() { @@ -594,7 +594,7 @@ func TestFastVsFullChains(t *testing.T) { // If the block number is multiple of 3, send a few bonus transactions to the miner if i%3 == 2 { for j := 0; j < i%4+1; j++ { - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), bigTxGas, nil, nil), signer, key) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil), signer, key) if err != nil { panic(err) } @@ -767,8 +767,8 @@ func TestChainTxReorgs(t *testing.T) { // Create two transactions shared between the chains: // - postponed: transaction included at a later block in the forked chain // - swapped: transaction included at the same block number in the forked chain - postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), bigTxGas, nil, nil), signer, key1) - swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), bigTxGas, nil, nil), signer, key1) + postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1) + swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil), signer, key1) // Create two transactions that will be dropped by the forked chain: // - pastDrop: transaction dropped retroactively from a past block @@ -784,13 +784,13 @@ func TestChainTxReorgs(t *testing.T) { chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, gen *BlockGen) { switch i { case 0: - pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2) + pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2) gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork case 2: - freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2) + freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key2) gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point gen.AddTx(swapped) // This transaction will be swapped out at the exact height @@ -809,18 +809,18 @@ func TestChainTxReorgs(t *testing.T) { chain, _ = GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) { switch i { case 0: - pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3) + pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3) gen.AddTx(pastAdd) // This transaction needs to be injected during reorg case 2: gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain - freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3) + freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3) gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time case 3: - futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3) + futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key3) gen.AddTx(futureAdd) // This transaction will be added after a full reorg } }) @@ -877,7 +877,7 @@ func TestLogReorgs(t *testing.T) { blockchain.SubscribeRemovedLogsEvent(rmLogsCh) chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) { if i == 1 { - tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code), signer, key1) + tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code), signer, key1) if err != nil { t.Fatalf("failed to create tx: %v", err) } @@ -926,7 +926,7 @@ func TestReorgSideEvent(t *testing.T) { } replacementBlocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, gen *BlockGen) { - tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1) + tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), nil), signer, key1) if i == 2 { gen.OffsetTime(-9) } @@ -1051,7 +1051,7 @@ func TestEIP155Transition(t *testing.T) { tx *types.Transaction err error basicTx = func(signer types.Signer) (*types.Transaction, error) { - return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) + return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil), signer, key) } ) switch i { @@ -1114,7 +1114,7 @@ func TestEIP155Transition(t *testing.T) { tx *types.Transaction err error basicTx = func(signer types.Signer) (*types.Transaction, error) { - return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) + return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), 21000, new(big.Int), nil), signer, key) } ) switch i { @@ -1162,11 +1162,11 @@ func TestEIP161AccountRemoval(t *testing.T) { ) switch i { case 0: - tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) + tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil), signer, key) case 1: - tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) + tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil), signer, key) case 2: - tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) + tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), 21000, new(big.Int), nil), signer, key) } if err != nil { t.Fatal(err) diff --git a/core/chain_makers.go b/core/chain_makers.go index 0e5e3791e5..5e264a9942 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -86,7 +86,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { b.SetCoinbase(common.Address{}) } b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs)) - receipt, _, err := ApplyTransaction(b.config, nil, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{}) + receipt, _, err := ApplyTransaction(b.config, nil, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{}) if err != nil { panic(err) } @@ -232,7 +232,6 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S UncleHash: parent.UncleHash(), }), GasLimit: CalcGasLimit(parent), - GasUsed: new(big.Int), Number: new(big.Int).Add(parent.Number(), common.Big1), Time: time, } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 011efe3424..a3b80da299 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -54,13 +54,13 @@ func ExampleGenerateChain() { switch i { case 0: // In block 1, addr1 sends addr2 some ether. - tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), bigTxGas, nil, nil), signer, key1) + tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1) gen.AddTx(tx) case 1: // In block 2, addr1 sends some more ether to addr2. // addr2 passes it on to addr3. - tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key1) - tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key2) + tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1) + tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2) gen.AddTx(tx1) gen.AddTx(tx2) case 2: diff --git a/core/database_util_test.go b/core/database_util_test.go index 36f43cf50a..ab4e45a478 100644 --- a/core/database_util_test.go +++ b/core/database_util_test.go @@ -290,9 +290,9 @@ func TestHeadStorage(t *testing.T) { func TestLookupStorage(t *testing.T) { db, _ := ethdb.NewMemDatabase() - tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), big.NewInt(1111), big.NewInt(11111), []byte{0x11, 0x11, 0x11}) - tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), big.NewInt(2222), big.NewInt(22222), []byte{0x22, 0x22, 0x22}) - tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), big.NewInt(3333), big.NewInt(33333), []byte{0x33, 0x33, 0x33}) + tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11}) + tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22}) + tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33}) txs := []*types.Transaction{tx1, tx2, tx3} block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil) @@ -337,25 +337,25 @@ func TestBlockReceiptStorage(t *testing.T) { receipt1 := &types.Receipt{ Status: types.ReceiptStatusFailed, - CumulativeGasUsed: big.NewInt(1), + CumulativeGasUsed: 1, Logs: []*types.Log{ {Address: common.BytesToAddress([]byte{0x11})}, {Address: common.BytesToAddress([]byte{0x01, 0x11})}, }, TxHash: common.BytesToHash([]byte{0x11, 0x11}), ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}), - GasUsed: big.NewInt(111111), + GasUsed: 111111, } receipt2 := &types.Receipt{ PostState: common.Hash{2}.Bytes(), - CumulativeGasUsed: big.NewInt(2), + CumulativeGasUsed: 2, Logs: []*types.Log{ {Address: common.BytesToAddress([]byte{0x22})}, {Address: common.BytesToAddress([]byte{0x02, 0x22})}, }, TxHash: common.BytesToHash([]byte{0x22, 0x22}), ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}), - GasUsed: big.NewInt(222222), + GasUsed: 222222, } receipts := []*types.Receipt{receipt1, receipt2} diff --git a/core/evm.go b/core/evm.go index 4912aa6505..55db53927b 100644 --- a/core/evm.go +++ b/core/evm.go @@ -53,7 +53,7 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author BlockNumber: new(big.Int).Set(header.Number), Time: new(big.Int).Set(header.Time), Difficulty: new(big.Int).Set(header.Difficulty), - GasLimit: new(big.Int).Set(header.GasLimit), + GasLimit: header.GasLimit, GasPrice: new(big.Int).Set(msg.GasPrice()), } } diff --git a/core/gaspool.go b/core/gaspool.go index ef99908cfe..c3ee5c198f 100644 --- a/core/gaspool.go +++ b/core/gaspool.go @@ -16,31 +16,34 @@ package core -import "math/big" +import ( + "fmt" + "math" +) -// GasPool tracks the amount of gas available during -// execution of the transactions in a block. -// The zero value is a pool with zero gas available. -type GasPool big.Int +// GasPool tracks the amount of gas available during execution of the transactions +// in a block. The zero value is a pool with zero gas available. +type GasPool uint64 // AddGas makes gas available for execution. -func (gp *GasPool) AddGas(amount *big.Int) *GasPool { - i := (*big.Int)(gp) - i.Add(i, amount) +func (gp *GasPool) AddGas(amount uint64) *GasPool { + if uint64(*gp) > math.MaxUint64-amount { + panic("gas pool pushed above uint64") + } + *(*uint64)(gp) += amount return gp } // SubGas deducts the given amount from the pool if enough gas is // available and returns an error otherwise. -func (gp *GasPool) SubGas(amount *big.Int) error { - i := (*big.Int)(gp) - if i.Cmp(amount) < 0 { +func (gp *GasPool) SubGas(amount uint64) error { + if uint64(*gp) < amount { return ErrGasLimitReached } - i.Sub(i, amount) + *(*uint64)(gp) -= amount return nil } func (gp *GasPool) String() string { - return (*big.Int)(gp).String() + return fmt.Sprintf("%d", *gp) } diff --git a/core/gen_genesis.go b/core/gen_genesis.go index 4d75704a6d..6f941e35a7 100644 --- a/core/gen_genesis.go +++ b/core/gen_genesis.go @@ -13,6 +13,8 @@ import ( "github.com/ethereum/go-ethereum/params" ) +var _ = (*genesisSpecMarshaling)(nil) + func (g Genesis) MarshalJSON() ([]byte, error) { type Genesis struct { Config *params.ChainConfig `json:"config"` diff --git a/core/genesis.go b/core/genesis.go index df491ce0f4..e22985b800 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -239,8 +239,8 @@ func (g *Genesis) ToBlock() (*types.Block, *state.StateDB) { Time: new(big.Int).SetUint64(g.Timestamp), ParentHash: g.ParentHash, Extra: g.ExtraData, - GasLimit: new(big.Int).SetUint64(g.GasLimit), - GasUsed: new(big.Int).SetUint64(g.GasUsed), + GasLimit: g.GasLimit, + GasUsed: g.GasUsed, Difficulty: g.Difficulty, MixDigest: g.Mixhash, Coinbase: g.Coinbase, diff --git a/core/state/journal.go b/core/state/journal.go index ddc819fe5f..a89bb3d13a 100644 --- a/core/state/journal.go +++ b/core/state/journal.go @@ -62,7 +62,7 @@ type ( // Changes to other state values. refundChange struct { - prev *big.Int + prev uint64 } addLogChange struct { txhash common.Hash diff --git a/core/state/statedb.go b/core/state/statedb.go index de9fb367d9..8e29104d59 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -57,7 +57,7 @@ type StateDB struct { dbErr error // The refund counter, also used by state transitioning. - refund *big.Int + refund uint64 thash, bhash common.Hash txIndex int @@ -86,7 +86,6 @@ func New(root common.Hash, db Database) (*StateDB, error) { trie: tr, stateObjects: make(map[common.Address]*stateObject), stateObjectsDirty: make(map[common.Address]struct{}), - refund: new(big.Int), logs: make(map[common.Hash][]*types.Log), preimages: make(map[common.Hash][]byte), }, nil @@ -161,9 +160,9 @@ func (self *StateDB) Preimages() map[common.Hash][]byte { return self.preimages } -func (self *StateDB) AddRefund(gas *big.Int) { - self.journal = append(self.journal, refundChange{prev: new(big.Int).Set(self.refund)}) - self.refund.Add(self.refund, gas) +func (self *StateDB) AddRefund(gas uint64) { + self.journal = append(self.journal, refundChange{prev: self.refund}) + self.refund += gas } // Exist reports whether the given account address exists in the state. @@ -456,7 +455,7 @@ func (self *StateDB) Copy() *StateDB { trie: self.db.CopyTrie(self.trie), stateObjects: make(map[common.Address]*stateObject, len(self.stateObjectsDirty)), stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)), - refund: new(big.Int).Set(self.refund), + refund: self.refund, logs: make(map[common.Hash][]*types.Log, len(self.logs)), logSize: self.logSize, preimages: make(map[common.Hash][]byte), @@ -506,9 +505,7 @@ func (self *StateDB) RevertToSnapshot(revid int) { } // GetRefund returns the current value of the refund counter. -// The return value must not be modified by the caller and will become -// invalid at the next call to AddRefund. -func (self *StateDB) GetRefund() *big.Int { +func (self *StateDB) GetRefund() uint64 { return self.refund } @@ -568,7 +565,7 @@ func (s *StateDB) DeleteSuicides() { func (s *StateDB) clearJournalAndRefund() { s.journal = nil s.validRevisions = s.validRevisions[:0] - s.refund = new(big.Int) + s.refund = 0 } // CommitTo writes the state to the given database. diff --git a/core/state/statedb_test.go b/core/state/statedb_test.go index e9944cd745..5c80e3aa56 100644 --- a/core/state/statedb_test.go +++ b/core/state/statedb_test.go @@ -263,7 +263,7 @@ func newTestAction(addr common.Address, r *rand.Rand) testAction { { name: "AddRefund", fn: func(a testAction, s *StateDB) { - s.AddRefund(big.NewInt(a.args[0])) + s.AddRefund(uint64(a.args[0])) }, args: make([]int64, 1), noAddr: true, @@ -396,7 +396,7 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error { } } - if state.GetRefund().Cmp(checkstate.GetRefund()) != 0 { + if state.GetRefund() != checkstate.GetRefund() { return fmt.Errorf("got GetRefund() == %d, want GetRefund() == %d", state.GetRefund(), checkstate.GetRefund()) } diff --git a/core/state_processor.go b/core/state_processor.go index 689c83785f..4dc58b9dea 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -17,8 +17,6 @@ package core import ( - "math/big" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" @@ -55,13 +53,13 @@ func NewStateProcessor(config *params.ChainConfig, bc *BlockChain, engine consen // Process returns the receipts and logs accumulated during the process and // returns the amount of gas that was used in the process. If any of the // transactions failed to execute due to insufficient gas it will return an error. -func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) { +func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) { var ( - receipts types.Receipts - totalUsedGas = big.NewInt(0) - header = block.Header() - allLogs []*types.Log - gp = new(GasPool).AddGas(block.GasLimit()) + receipts types.Receipts + usedGas = new(uint64) + header = block.Header() + allLogs []*types.Log + gp = new(GasPool).AddGas(block.GasLimit()) ) // Mutate the the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { @@ -70,9 +68,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Iterate over and process the individual transactions for i, tx := range block.Transactions() { statedb.Prepare(tx.Hash(), block.Hash(), i) - receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, totalUsedGas, cfg) + receipt, _, err := ApplyTransaction(p.config, p.bc, nil, gp, statedb, header, tx, usedGas, cfg) if err != nil { - return nil, nil, nil, err + return nil, nil, 0, err } receipts = append(receipts, receipt) allLogs = append(allLogs, receipt.Logs...) @@ -80,17 +78,17 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.engine.Finalize(p.bc, header, statedb, block.Transactions(), block.Uncles(), receipts) - return receipts, allLogs, totalUsedGas, nil + return receipts, allLogs, *usedGas, nil } // ApplyTransaction attempts to apply a transaction to the given state database // and uses the input parameters for its environment. It returns the receipt // for the transaction, gas used and an error if the transaction failed, // indicating the block was invalid. -func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, *big.Int, error) { +func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common.Address, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *uint64, cfg vm.Config) (*types.Receipt, uint64, error) { msg, err := tx.AsMessage(types.MakeSigner(config, header.Number)) if err != nil { - return nil, nil, err + return nil, 0, err } // Create a new context to be used in the EVM environment context := NewEVMContext(msg, header, bc, author) @@ -100,9 +98,8 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common // Apply the transaction to the current state (included in the env) _, gas, failed, err := ApplyMessage(vmenv, msg, gp) if err != nil { - return nil, nil, err + return nil, 0, err } - // Update the state with pending changes var root []byte if config.IsByzantium(header.Number) { @@ -110,18 +107,17 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common } else { root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() } - usedGas.Add(usedGas, gas) + *usedGas += gas // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx // based on the eip phase, we're passing wether the root touch-delete accounts. - receipt := types.NewReceipt(root, failed, usedGas) + receipt := types.NewReceipt(root, failed, *usedGas) receipt.TxHash = tx.Hash() - receipt.GasUsed = new(big.Int).Set(gas) + receipt.GasUsed = gas // if the transaction created a contract, store the creation address in the receipt. if msg.To() == nil { receipt.ContractAddress = crypto.CreateAddress(vmenv.Context.Origin, tx.Nonce()) } - // Set the receipt logs and create a bloom for filtering receipt.Logs = statedb.GetLogs(tx.Hash()) receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) diff --git a/core/state_transition.go b/core/state_transition.go index e7a0685893..390473fffd 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -18,17 +18,16 @@ package core import ( "errors" + "math" "math/big" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" ) var ( - Big0 = big.NewInt(0) errInsufficientBalanceForGas = errors.New("insufficient balance to pay for gas") ) @@ -54,7 +53,7 @@ type StateTransition struct { msg Message gas uint64 gasPrice *big.Int - initialGas *big.Int + initialGas uint64 value *big.Int data []byte state vm.StateDB @@ -68,7 +67,7 @@ type Message interface { To() *common.Address GasPrice() *big.Int - Gas() *big.Int + Gas() uint64 Value() *big.Int Nonce() uint64 @@ -76,45 +75,49 @@ type Message interface { Data() []byte } -// IntrinsicGas computes the 'intrinsic gas' for a message -// with the given data. -// -// TODO convert to uint64 -func IntrinsicGas(data []byte, contractCreation, homestead bool) *big.Int { - igas := new(big.Int) +// IntrinsicGas computes the 'intrinsic gas' for a message with the given data. +func IntrinsicGas(data []byte, contractCreation, homestead bool) (uint64, error) { + // Set the starting gas for the raw transaction + var gas uint64 if contractCreation && homestead { - igas.SetUint64(params.TxGasContractCreation) + gas = params.TxGasContractCreation } else { - igas.SetUint64(params.TxGas) + gas = params.TxGas } + // Bump the required gas by the amount of transactional data if len(data) > 0 { - var nz int64 + // Zero and non-zero bytes are priced differently + var nz uint64 for _, byt := range data { if byt != 0 { nz++ } } - m := big.NewInt(nz) - m.Mul(m, new(big.Int).SetUint64(params.TxDataNonZeroGas)) - igas.Add(igas, m) - m.SetInt64(int64(len(data)) - nz) - m.Mul(m, new(big.Int).SetUint64(params.TxDataZeroGas)) - igas.Add(igas, m) + // Make sure we don't exceed uint64 for all data combinations + if (math.MaxUint64-gas)/params.TxDataNonZeroGas < nz { + return 0, vm.ErrOutOfGas + } + gas += nz * params.TxDataNonZeroGas + + z := uint64(len(data)) - nz + if (math.MaxUint64-gas)/params.TxDataZeroGas < z { + return 0, vm.ErrOutOfGas + } + gas += z * params.TxDataZeroGas } - return igas + return gas, nil } // NewStateTransition initialises and returns a new state transition object. func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition { return &StateTransition{ - gp: gp, - evm: evm, - msg: msg, - gasPrice: msg.GasPrice(), - initialGas: new(big.Int), - value: msg.Value(), - data: msg.Data(), - state: evm.StateDB, + gp: gp, + evm: evm, + msg: msg, + gasPrice: msg.GasPrice(), + value: msg.Value(), + data: msg.Data(), + state: evm.StateDB, } } @@ -125,11 +128,8 @@ func NewStateTransition(evm *vm.EVM, msg Message, gp *GasPool) *StateTransition // the gas used (which includes gas refunds) and an error if it failed. An error always // indicates a core error meaning that the message would always fail for that particular // state and would never be accepted within a block. -func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, *big.Int, bool, error) { - st := NewStateTransition(evm, msg, gp) - - ret, _, gasUsed, failed, err := st.TransitionDb() - return ret, gasUsed, failed, err +func ApplyMessage(evm *vm.EVM, msg Message, gp *GasPool) ([]byte, uint64, bool, error) { + return NewStateTransition(evm, msg, gp).TransitionDb() } func (st *StateTransition) from() vm.AccountRef { @@ -166,26 +166,20 @@ func (st *StateTransition) useGas(amount uint64) error { } func (st *StateTransition) buyGas() error { - mgas := st.msg.Gas() - if mgas.BitLen() > 64 { - return vm.ErrOutOfGas - } - - mgval := new(big.Int).Mul(mgas, st.gasPrice) - var ( state = st.state sender = st.from() ) + mgval := new(big.Int).Mul(new(big.Int).SetUint64(st.msg.Gas()), st.gasPrice) if state.GetBalance(sender.Address()).Cmp(mgval) < 0 { return errInsufficientBalanceForGas } - if err := st.gp.SubGas(mgas); err != nil { + if err := st.gp.SubGas(st.msg.Gas()); err != nil { return err } - st.gas += mgas.Uint64() + st.gas += st.msg.Gas() - st.initialGas.Set(mgas) + st.initialGas = st.msg.Gas() state.SubBalance(sender.Address(), mgval) return nil } @@ -206,10 +200,10 @@ func (st *StateTransition) preCheck() error { return st.buyGas() } -// TransitionDb will transition the state by applying the current message and returning the result -// including the required gas for the operation as well as the used gas. It returns an error if it +// TransitionDb will transition the state by applying the current message and +// returning the result including the the used gas. It returns an error if it // failed. An error indicates a consensus issue. -func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big.Int, failed bool, err error) { +func (st *StateTransition) TransitionDb() (ret []byte, usedGas uint64, failed bool, err error) { if err = st.preCheck(); err != nil { return } @@ -220,13 +214,9 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big contractCreation := msg.To() == nil // Pay intrinsic gas - // TODO convert to uint64 - intrinsicGas := IntrinsicGas(st.data, contractCreation, homestead) - if intrinsicGas.BitLen() > 64 { - return nil, nil, nil, false, vm.ErrOutOfGas - } - if err = st.useGas(intrinsicGas.Uint64()); err != nil { - return nil, nil, nil, false, err + gas, err := IntrinsicGas(st.data, contractCreation, homestead) + if err = st.useGas(gas); err != nil { + return nil, 0, false, err } var ( @@ -249,36 +239,35 @@ func (st *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *big // sufficient balance to make the transfer happen. The first // balance transfer may never fail. if vmerr == vm.ErrInsufficientBalance { - return nil, nil, nil, false, vmerr + return nil, 0, false, vmerr } } - requiredGas = new(big.Int).Set(st.gasUsed()) - st.refundGas() - st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(st.gasUsed(), st.gasPrice)) + st.state.AddBalance(st.evm.Coinbase, new(big.Int).Mul(new(big.Int).SetUint64(st.gasUsed()), st.gasPrice)) - return ret, requiredGas, st.gasUsed(), vmerr != nil, err + return ret, st.gasUsed(), vmerr != nil, err } func (st *StateTransition) refundGas() { - // Return eth for remaining gas to the sender account, - // exchanged at the original rate. - sender := st.from() // err already checked + // Apply refund counter, capped to half of the used gas. + refund := st.gasUsed() / 2 + if refund > st.state.GetRefund() { + refund = st.state.GetRefund() + } + st.gas += refund + + // Return ETH for remaining gas, exchanged at the original rate. + sender := st.from() + remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice) st.state.AddBalance(sender.Address(), remaining) - // Apply refund counter, capped to half of the used gas. - uhalf := remaining.Div(st.gasUsed(), common.Big2) - refund := math.BigMin(uhalf, st.state.GetRefund()) - st.gas += refund.Uint64() - - st.state.AddBalance(sender.Address(), refund.Mul(refund, st.gasPrice)) - // Also return remaining gas to the block gas counter so it is // available for the next transaction. - st.gp.AddGas(new(big.Int).SetUint64(st.gas)) + st.gp.AddGas(st.gas) } -func (st *StateTransition) gasUsed() *big.Int { - return new(big.Int).Sub(st.initialGas, new(big.Int).SetUint64(st.gas)) +// gasUsed returns the amount of gas used up by the state transition. +func (st *StateTransition) gasUsed() uint64 { + return st.initialGas - st.gas } diff --git a/core/tx_list.go b/core/tx_list.go index 838433b897..55fc42617d 100644 --- a/core/tx_list.go +++ b/core/tx_list.go @@ -224,7 +224,7 @@ type txList struct { txs *txSortedMap // Heap indexed sorted hash map of the transactions costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance) - gascap *big.Int // Gas limit of the highest spending transaction (reset only if exceeds block limit) + gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit) } // newTxList create a new transaction list for maintaining nonce-indexable fast, @@ -234,7 +234,6 @@ func newTxList(strict bool) *txList { strict: strict, txs: newTxSortedMap(), costcap: new(big.Int), - gascap: new(big.Int), } } @@ -266,7 +265,7 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 { l.costcap = cost } - if gas := tx.Gas(); l.gascap.Cmp(gas) < 0 { + if gas := tx.Gas(); l.gascap < gas { l.gascap = gas } return true, old @@ -288,16 +287,16 @@ func (l *txList) Forward(threshold uint64) types.Transactions { // a point in calculating all the costs or if the balance covers all. If the threshold // is lower than the costgas cap, the caps will be reset to a new high after removing // the newly invalidated transactions. -func (l *txList) Filter(costLimit, gasLimit *big.Int) (types.Transactions, types.Transactions) { +func (l *txList) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions, types.Transactions) { // If all transactions are below the threshold, short circuit - if l.costcap.Cmp(costLimit) <= 0 && l.gascap.Cmp(gasLimit) <= 0 { + if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit { return nil, nil } l.costcap = new(big.Int).Set(costLimit) // Lower the caps to the thresholds - l.gascap = new(big.Int).Set(gasLimit) + l.gascap = gasLimit // Filter out all the transactions above the account's funds - removed := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Cost().Cmp(costLimit) > 0 || tx.Gas().Cmp(gasLimit) > 0 }) + removed := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Cost().Cmp(costLimit) > 0 || tx.Gas() > gasLimit }) // If the list was strict, filter anything above the lowest nonce var invalids types.Transactions diff --git a/core/tx_list_test.go b/core/tx_list_test.go index b4f0b5228b..d579f501af 100644 --- a/core/tx_list_test.go +++ b/core/tx_list_test.go @@ -17,7 +17,6 @@ package core import ( - "math/big" "math/rand" "testing" @@ -33,7 +32,7 @@ func TestStrictTxListAdd(t *testing.T) { txs := make(types.Transactions, 1024) for i := 0; i < len(txs); i++ { - txs[i] = transaction(uint64(i), new(big.Int), key) + txs[i] = transaction(uint64(i), 0, key) } // Insert the transactions in a random order list := newTxList(true) diff --git a/core/tx_pool.go b/core/tx_pool.go index dade5d09f8..dc3ddc4232 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -197,7 +197,7 @@ type TxPool struct { currentState *state.StateDB // Current state in the blockchain head pendingState *state.ManagedState // Pending state tracking virtual nonces - currentMaxGas *big.Int // Current gas limit for transaction caps + currentMaxGas uint64 // Current gas limit for transaction caps locals *accountSet // Set of local transaction to exempt from eviction rules journal *txJournal // Journal of local transaction to back up to disk @@ -564,7 +564,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { return ErrNegativeValue } // Ensure the transaction doesn't exceed the current block limit gas. - if pool.currentMaxGas.Cmp(tx.Gas()) < 0 { + if pool.currentMaxGas < tx.Gas() { return ErrGasLimit } // Make sure the transaction is signed properly @@ -586,8 +586,11 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { if pool.currentState.GetBalance(from).Cmp(tx.Cost()) < 0 { return ErrInsufficientFunds } - intrGas := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) - if tx.Gas().Cmp(intrGas) < 0 { + intrGas, err := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) + if err != nil { + return err + } + if tx.Gas() < intrGas { return ErrIntrinsicGas } return nil diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 1f193a06c8..cd11f2ba29 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -46,7 +46,7 @@ func init() { type testBlockChain struct { statedb *state.StateDB - gasLimit *big.Int + gasLimit uint64 chainHeadFeed *event.Feed } @@ -68,11 +68,11 @@ func (bc *testBlockChain) SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) even return bc.chainHeadFeed.Subscribe(ch) } -func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction { +func transaction(nonce uint64, gaslimit uint64, key *ecdsa.PrivateKey) *types.Transaction { return pricedTransaction(nonce, gaslimit, big.NewInt(1), key) } -func pricedTransaction(nonce uint64, gaslimit, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction { +func pricedTransaction(nonce uint64, gaslimit uint64, gasprice *big.Int, key *ecdsa.PrivateKey) *types.Transaction { tx, _ := types.SignTx(types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, gasprice, nil), types.HomesteadSigner{}, key) return tx } @@ -80,7 +80,7 @@ func pricedTransaction(nonce uint64, gaslimit, gasprice *big.Int, key *ecdsa.Pri func setupTxPool() (*TxPool, *ecdsa.PrivateKey) { db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} key, _ := crypto.GenerateKey() pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) @@ -184,10 +184,10 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) { // setup pool with 2 transaction in it statedb.SetBalance(address, new(big.Int).SetUint64(params.Ether)) - blockchain := &testChain{&testBlockChain{statedb, big.NewInt(1000000000), new(event.Feed)}, address, &trigger} + blockchain := &testChain{&testBlockChain{statedb, 1000000000, new(event.Feed)}, address, &trigger} - tx0 := transaction(0, big.NewInt(100000), key) - tx1 := transaction(1, big.NewInt(100000), key) + tx0 := transaction(0, 100000, key) + tx1 := transaction(1, 100000, key) pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -230,7 +230,7 @@ func TestInvalidTransactions(t *testing.T) { pool, key := setupTxPool() defer pool.Stop() - tx := transaction(0, big.NewInt(100), key) + tx := transaction(0, 100, key) from, _ := deriveSender(tx) pool.currentState.AddBalance(from, big.NewInt(1)) @@ -238,7 +238,7 @@ func TestInvalidTransactions(t *testing.T) { t.Error("expected", ErrInsufficientFunds) } - balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(tx.Gas(), tx.GasPrice())) + balance := new(big.Int).Add(tx.Value(), new(big.Int).Mul(new(big.Int).SetUint64(tx.Gas()), tx.GasPrice())) pool.currentState.AddBalance(from, balance) if err := pool.AddRemote(tx); err != ErrIntrinsicGas { t.Error("expected", ErrIntrinsicGas, "got", err) @@ -246,12 +246,12 @@ func TestInvalidTransactions(t *testing.T) { pool.currentState.SetNonce(from, 1) pool.currentState.AddBalance(from, big.NewInt(0xffffffffffffff)) - tx = transaction(0, big.NewInt(100000), key) + tx = transaction(0, 100000, key) if err := pool.AddRemote(tx); err != ErrNonceTooLow { t.Error("expected", ErrNonceTooLow) } - tx = transaction(1, big.NewInt(100000), key) + tx = transaction(1, 100000, key) pool.gasPrice = big.NewInt(1000) if err := pool.AddRemote(tx); err != ErrUnderpriced { t.Error("expected", ErrUnderpriced, "got", err) @@ -267,7 +267,7 @@ func TestTransactionQueue(t *testing.T) { pool, key := setupTxPool() defer pool.Stop() - tx := transaction(0, big.NewInt(100), key) + tx := transaction(0, 100, key) from, _ := deriveSender(tx) pool.currentState.AddBalance(from, big.NewInt(1000)) pool.lockedReset(nil, nil) @@ -278,7 +278,7 @@ func TestTransactionQueue(t *testing.T) { t.Error("expected valid txs to be 1 is", len(pool.pending)) } - tx = transaction(1, big.NewInt(100), key) + tx = transaction(1, 100, key) from, _ = deriveSender(tx) pool.currentState.SetNonce(from, 2) pool.enqueueTx(tx.Hash(), tx) @@ -294,9 +294,9 @@ func TestTransactionQueue(t *testing.T) { pool, key = setupTxPool() defer pool.Stop() - tx1 := transaction(0, big.NewInt(100), key) - tx2 := transaction(10, big.NewInt(100), key) - tx3 := transaction(11, big.NewInt(100), key) + tx1 := transaction(0, 100, key) + tx2 := transaction(10, 100, key) + tx3 := transaction(11, 100, key) from, _ = deriveSender(tx1) pool.currentState.AddBalance(from, big.NewInt(1000)) pool.lockedReset(nil, nil) @@ -321,7 +321,7 @@ func TestTransactionNegativeValue(t *testing.T) { pool, key := setupTxPool() defer pool.Stop() - tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil), types.HomesteadSigner{}, key) + tx, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(-1), 100, big.NewInt(1), nil), types.HomesteadSigner{}, key) from, _ := deriveSender(tx) pool.currentState.AddBalance(from, big.NewInt(1)) if err := pool.AddRemote(tx); err != ErrNegativeValue { @@ -341,12 +341,12 @@ func TestTransactionChainFork(t *testing.T) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) statedb.AddBalance(addr, big.NewInt(100000000000000)) - pool.chain = &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} pool.lockedReset(nil, nil) } resetState() - tx := transaction(0, big.NewInt(100000), key) + tx := transaction(0, 100000, key) if _, err := pool.add(tx, false); err != nil { t.Error("didn't expect error", err) } @@ -371,15 +371,15 @@ func TestTransactionDoubleNonce(t *testing.T) { statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) statedb.AddBalance(addr, big.NewInt(100000000000000)) - pool.chain = &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + pool.chain = &testBlockChain{statedb, 1000000, new(event.Feed)} pool.lockedReset(nil, nil) } resetState() signer := types.HomesteadSigner{} - tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil), signer, key) - tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil), signer, key) - tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil), signer, key) + tx1, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 100000, big.NewInt(1), nil), signer, key) + tx2, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(2), nil), signer, key) + tx3, _ := types.SignTx(types.NewTransaction(0, common.Address{}, big.NewInt(100), 1000000, big.NewInt(1), nil), signer, key) // Add the first two transaction, ensure higher priced stays only if replace, err := pool.add(tx1, false); err != nil || replace { @@ -418,7 +418,7 @@ func TestTransactionMissingNonce(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) pool.currentState.AddBalance(addr, big.NewInt(100000000000000)) - tx := transaction(1, big.NewInt(100000), key) + tx := transaction(1, 100000, key) if _, err := pool.add(tx, false); err != nil { t.Error("didn't expect error", err) } @@ -445,7 +445,7 @@ func TestTransactionNonceRecovery(t *testing.T) { pool.currentState.AddBalance(addr, big.NewInt(100000000000000)) pool.lockedReset(nil, nil) - tx := transaction(n, big.NewInt(100000), key) + tx := transaction(n, 100000, key) if err := pool.AddRemote(tx); err != nil { t.Error(err) } @@ -466,17 +466,17 @@ func TestTransactionDropping(t *testing.T) { pool, key := setupTxPool() defer pool.Stop() - account, _ := deriveSender(transaction(0, big.NewInt(0), key)) + account, _ := deriveSender(transaction(0, 0, key)) pool.currentState.AddBalance(account, big.NewInt(1000)) // Add some pending and some queued transactions var ( - tx0 = transaction(0, big.NewInt(100), key) - tx1 = transaction(1, big.NewInt(200), key) - tx2 = transaction(2, big.NewInt(300), key) - tx10 = transaction(10, big.NewInt(100), key) - tx11 = transaction(11, big.NewInt(200), key) - tx12 = transaction(12, big.NewInt(300), key) + tx0 = transaction(0, 100, key) + tx1 = transaction(1, 200, key) + tx2 = transaction(2, 300, key) + tx10 = transaction(10, 100, key) + tx11 = transaction(11, 200, key) + tx12 = transaction(12, 300, key) ) pool.promoteTx(account, tx0.Hash(), tx0) pool.promoteTx(account, tx1.Hash(), tx1) @@ -531,7 +531,7 @@ func TestTransactionDropping(t *testing.T) { t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 4) } // Reduce the block gas limit, check that invalidated transactions are dropped - pool.chain.(*testBlockChain).gasLimit = big.NewInt(100) + pool.chain.(*testBlockChain).gasLimit = 100 pool.lockedReset(nil, nil) if _, ok := pool.pending[account].txs.items[tx0.Nonce()]; !ok { @@ -561,7 +561,7 @@ func TestTransactionPostponing(t *testing.T) { pool, key := setupTxPool() defer pool.Stop() - account, _ := deriveSender(transaction(0, big.NewInt(0), key)) + account, _ := deriveSender(transaction(0, 0, key)) pool.currentState.AddBalance(account, big.NewInt(1000)) // Add a batch consecutive pending transactions for validation @@ -569,9 +569,9 @@ func TestTransactionPostponing(t *testing.T) { for i := 0; i < 100; i++ { var tx *types.Transaction if i%2 == 0 { - tx = transaction(uint64(i), big.NewInt(100), key) + tx = transaction(uint64(i), 100, key) } else { - tx = transaction(uint64(i), big.NewInt(500), key) + tx = transaction(uint64(i), 500, key) } pool.promoteTx(account, tx.Hash(), tx) txns = append(txns, tx) @@ -638,7 +638,7 @@ func TestTransactionGapFilling(t *testing.T) { pool, key := setupTxPool() defer pool.Stop() - account, _ := deriveSender(transaction(0, big.NewInt(0), key)) + account, _ := deriveSender(transaction(0, 0, key)) pool.currentState.AddBalance(account, big.NewInt(1000000)) // Keep track of transaction events to ensure all executables get announced @@ -647,10 +647,10 @@ func TestTransactionGapFilling(t *testing.T) { defer sub.Unsubscribe() // Create a pending and a queued transaction with a nonce-gap in between - if err := pool.AddRemote(transaction(0, big.NewInt(100000), key)); err != nil { + if err := pool.AddRemote(transaction(0, 100000, key)); err != nil { t.Fatalf("failed to add pending transaction: %v", err) } - if err := pool.AddRemote(transaction(2, big.NewInt(100000), key)); err != nil { + if err := pool.AddRemote(transaction(2, 100000, key)); err != nil { t.Fatalf("failed to add queued transaction: %v", err) } pending, queued := pool.Stats() @@ -667,7 +667,7 @@ func TestTransactionGapFilling(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // Fill the nonce gap and ensure all transactions become pending - if err := pool.AddRemote(transaction(1, big.NewInt(100000), key)); err != nil { + if err := pool.AddRemote(transaction(1, 100000, key)); err != nil { t.Fatalf("failed to add gapped transaction: %v", err) } pending, queued = pool.Stats() @@ -694,12 +694,12 @@ func TestTransactionQueueAccountLimiting(t *testing.T) { pool, key := setupTxPool() defer pool.Stop() - account, _ := deriveSender(transaction(0, big.NewInt(0), key)) + account, _ := deriveSender(transaction(0, 0, key)) pool.currentState.AddBalance(account, big.NewInt(1000000)) // Keep queuing up transactions and make sure all above a limit are dropped for i := uint64(1); i <= testTxPoolConfig.AccountQueue+5; i++ { - if err := pool.AddRemote(transaction(i, big.NewInt(100000), key)); err != nil { + if err := pool.AddRemote(transaction(i, 100000, key)); err != nil { t.Fatalf("tx %d: failed to add transaction: %v", i, err) } if len(pool.pending) != 0 { @@ -738,7 +738,7 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { // Create the pool to test the limit enforcement with db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig config.NoLocals = nolocals @@ -763,7 +763,7 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { key := keys[rand.Intn(len(keys)-1)] // skip adding transactions with the local account addr := crypto.PubkeyToAddress(key.PublicKey) - txs = append(txs, transaction(nonces[addr]+1, big.NewInt(100000), key)) + txs = append(txs, transaction(nonces[addr]+1, 100000, key)) nonces[addr]++ } // Import the batch and verify that limits have been enforced @@ -782,7 +782,7 @@ func testTransactionQueueGlobalLimiting(t *testing.T, nolocals bool) { // Generate a batch of transactions from the local account and import them txs = txs[:0] for i := uint64(0); i < 3*config.GlobalQueue; i++ { - txs = append(txs, transaction(i+1, big.NewInt(100000), local)) + txs = append(txs, transaction(i+1, 100000, local)) } pool.AddLocals(txs) @@ -827,7 +827,7 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { // Create the pool to test the non-expiration enforcement db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig config.Lifetime = time.Second @@ -844,10 +844,10 @@ func testTransactionQueueTimeLimiting(t *testing.T, nolocals bool) { pool.currentState.AddBalance(crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000)) // Add the two transactions and ensure they both are queued up - if err := pool.AddLocal(pricedTransaction(1, big.NewInt(100000), big.NewInt(1), local)); err != nil { + if err := pool.AddLocal(pricedTransaction(1, 100000, big.NewInt(1), local)); err != nil { t.Fatalf("failed to add local transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(1, big.NewInt(100000), big.NewInt(1), remote)); err != nil { + if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(1), remote)); err != nil { t.Fatalf("failed to add remote transaction: %v", err) } pending, queued := pool.Stats() @@ -891,7 +891,7 @@ func TestTransactionPendingLimiting(t *testing.T) { pool, key := setupTxPool() defer pool.Stop() - account, _ := deriveSender(transaction(0, big.NewInt(0), key)) + account, _ := deriveSender(transaction(0, 0, key)) pool.currentState.AddBalance(account, big.NewInt(1000000)) // Keep track of transaction events to ensure all executables get announced @@ -901,7 +901,7 @@ func TestTransactionPendingLimiting(t *testing.T) { // Keep queuing up transactions and make sure all above a limit are dropped for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { - if err := pool.AddRemote(transaction(i, big.NewInt(100000), key)); err != nil { + if err := pool.AddRemote(transaction(i, 100000, key)); err != nil { t.Fatalf("tx %d: failed to add transaction: %v", i, err) } if pool.pending[account].Len() != int(i)+1 { @@ -934,11 +934,11 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { pool1, key1 := setupTxPool() defer pool1.Stop() - account1, _ := deriveSender(transaction(0, big.NewInt(0), key1)) + account1, _ := deriveSender(transaction(0, 0, key1)) pool1.currentState.AddBalance(account1, big.NewInt(1000000)) for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { - if err := pool1.AddRemote(transaction(origin+i, big.NewInt(100000), key1)); err != nil { + if err := pool1.AddRemote(transaction(origin+i, 100000, key1)); err != nil { t.Fatalf("tx %d: failed to add transaction: %v", i, err) } } @@ -946,12 +946,12 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) { pool2, key2 := setupTxPool() defer pool2.Stop() - account2, _ := deriveSender(transaction(0, big.NewInt(0), key2)) + account2, _ := deriveSender(transaction(0, 0, key2)) pool2.currentState.AddBalance(account2, big.NewInt(1000000)) txns := []*types.Transaction{} for i := uint64(0); i < testTxPoolConfig.AccountQueue+5; i++ { - txns = append(txns, transaction(origin+i, big.NewInt(100000), key2)) + txns = append(txns, transaction(origin+i, 100000, key2)) } pool2.AddRemotes(txns) @@ -982,7 +982,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) { // Create the pool to test the limit enforcement with db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig config.GlobalSlots = config.AccountSlots * 10 @@ -1003,7 +1003,7 @@ func TestTransactionPendingGlobalLimiting(t *testing.T) { for _, key := range keys { addr := crypto.PubkeyToAddress(key.PublicKey) for j := 0; j < int(config.GlobalSlots)/len(keys)*2; j++ { - txs = append(txs, transaction(nonces[addr], big.NewInt(100000), key)) + txs = append(txs, transaction(nonces[addr], 100000, key)) nonces[addr]++ } } @@ -1029,7 +1029,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) { // Create the pool to test the limit enforcement with db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig config.AccountSlots = 2 @@ -1046,7 +1046,7 @@ func TestTransactionCapClearsFromAll(t *testing.T) { txs := types.Transactions{} for j := 0; j < int(config.GlobalSlots)*2; j++ { - txs = append(txs, transaction(uint64(j), big.NewInt(100000), key)) + txs = append(txs, transaction(uint64(j), 100000, key)) } // Import the batch and verify that limits have been enforced pool.AddRemotes(txs) @@ -1064,7 +1064,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) { // Create the pool to test the limit enforcement with db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig config.GlobalSlots = 0 @@ -1085,7 +1085,7 @@ func TestTransactionPendingMinimumAllowance(t *testing.T) { for _, key := range keys { addr := crypto.PubkeyToAddress(key.PublicKey) for j := 0; j < int(config.AccountSlots)*2; j++ { - txs = append(txs, transaction(nonces[addr], big.NewInt(100000), key)) + txs = append(txs, transaction(nonces[addr], 100000, key)) nonces[addr]++ } } @@ -1113,7 +1113,7 @@ func TestTransactionPoolRepricing(t *testing.T) { // Create the pool to test the pricing enforcement with db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -1132,15 +1132,15 @@ func TestTransactionPoolRepricing(t *testing.T) { // Generate and queue a batch of transactions, both pending and queued txs := types.Transactions{} - txs = append(txs, pricedTransaction(0, big.NewInt(100000), big.NewInt(2), keys[0])) - txs = append(txs, pricedTransaction(1, big.NewInt(100000), big.NewInt(1), keys[0])) - txs = append(txs, pricedTransaction(2, big.NewInt(100000), big.NewInt(2), keys[0])) + txs = append(txs, pricedTransaction(0, 100000, big.NewInt(2), keys[0])) + txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[0])) + txs = append(txs, pricedTransaction(2, 100000, big.NewInt(2), keys[0])) - txs = append(txs, pricedTransaction(1, big.NewInt(100000), big.NewInt(2), keys[1])) - txs = append(txs, pricedTransaction(2, big.NewInt(100000), big.NewInt(1), keys[1])) - txs = append(txs, pricedTransaction(3, big.NewInt(100000), big.NewInt(2), keys[1])) + txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[1])) + txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[1])) + txs = append(txs, pricedTransaction(3, 100000, big.NewInt(2), keys[1])) - ltx := pricedTransaction(0, big.NewInt(100000), big.NewInt(1), keys[2]) + ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[2]) // Import the batch and that both pending and queued transactions match up pool.AddRemotes(txs) @@ -1176,10 +1176,10 @@ func TestTransactionPoolRepricing(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // Check that we can't add the old transactions back - if err := pool.AddRemote(pricedTransaction(1, big.NewInt(100000), big.NewInt(1), keys[0])); err != ErrUnderpriced { + if err := pool.AddRemote(pricedTransaction(1, 100000, big.NewInt(1), keys[0])); err != ErrUnderpriced { t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) } - if err := pool.AddRemote(pricedTransaction(2, big.NewInt(100000), big.NewInt(1), keys[1])); err != ErrUnderpriced { + if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced { t.Fatalf("adding underpriced queued transaction error mismatch: have %v, want %v", err, ErrUnderpriced) } if err := validateEvents(events, 0); err != nil { @@ -1189,7 +1189,7 @@ func TestTransactionPoolRepricing(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // However we can add local underpriced transactions - tx := pricedTransaction(1, big.NewInt(100000), big.NewInt(1), keys[2]) + tx := pricedTransaction(1, 100000, big.NewInt(1), keys[2]) if err := pool.AddLocal(tx); err != nil { t.Fatalf("failed to add underpriced local transaction: %v", err) } @@ -1212,7 +1212,7 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { // Create the pool to test the pricing enforcement with db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -1226,12 +1226,12 @@ func TestTransactionPoolRepricingKeepsLocals(t *testing.T) { // Create transaction (both pending and queued) with a linearly growing gasprice for i := uint64(0); i < 500; i++ { // Add pending - p_tx := pricedTransaction(i, big.NewInt(100000), big.NewInt(int64(i)), keys[2]) + p_tx := pricedTransaction(i, 100000, big.NewInt(int64(i)), keys[2]) if err := pool.AddLocal(p_tx); err != nil { t.Fatal(err) } // Add queued - q_tx := pricedTransaction(i+501, big.NewInt(100000), big.NewInt(int64(i)), keys[2]) + q_tx := pricedTransaction(i+501, 100000, big.NewInt(int64(i)), keys[2]) if err := pool.AddLocal(q_tx); err != nil { t.Fatal(err) } @@ -1275,7 +1275,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { // Create the pool to test the pricing enforcement with db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig config.GlobalSlots = 2 @@ -1298,12 +1298,12 @@ func TestTransactionPoolUnderpricing(t *testing.T) { // Generate and queue a batch of transactions, both pending and queued txs := types.Transactions{} - txs = append(txs, pricedTransaction(0, big.NewInt(100000), big.NewInt(1), keys[0])) - txs = append(txs, pricedTransaction(1, big.NewInt(100000), big.NewInt(2), keys[0])) + txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[0])) + txs = append(txs, pricedTransaction(1, 100000, big.NewInt(2), keys[0])) - txs = append(txs, pricedTransaction(1, big.NewInt(100000), big.NewInt(1), keys[1])) + txs = append(txs, pricedTransaction(1, 100000, big.NewInt(1), keys[1])) - ltx := pricedTransaction(0, big.NewInt(100000), big.NewInt(1), keys[2]) + ltx := pricedTransaction(0, 100000, big.NewInt(1), keys[2]) // Import the batch and that both pending and queued transactions match up pool.AddRemotes(txs) @@ -1323,17 +1323,17 @@ func TestTransactionPoolUnderpricing(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // Ensure that adding an underpriced transaction on block limit fails - if err := pool.AddRemote(pricedTransaction(0, big.NewInt(100000), big.NewInt(1), keys[1])); err != ErrUnderpriced { + if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), keys[1])); err != ErrUnderpriced { t.Fatalf("adding underpriced pending transaction error mismatch: have %v, want %v", err, ErrUnderpriced) } // Ensure that adding high priced transactions drops cheap ones, but not own - if err := pool.AddRemote(pricedTransaction(0, big.NewInt(100000), big.NewInt(3), keys[1])); err != nil { + if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(3), keys[1])); err != nil { t.Fatalf("failed to add well priced transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(2, big.NewInt(100000), big.NewInt(4), keys[1])); err != nil { + if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(4), keys[1])); err != nil { t.Fatalf("failed to add well priced transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(3, big.NewInt(100000), big.NewInt(5), keys[1])); err != nil { + if err := pool.AddRemote(pricedTransaction(3, 100000, big.NewInt(5), keys[1])); err != nil { t.Fatalf("failed to add well priced transaction: %v", err) } pending, queued = pool.Stats() @@ -1350,7 +1350,7 @@ func TestTransactionPoolUnderpricing(t *testing.T) { t.Fatalf("pool internal state corrupted: %v", err) } // Ensure that adding local transactions can push out even higher priced ones - tx := pricedTransaction(1, big.NewInt(100000), big.NewInt(0), keys[2]) + tx := pricedTransaction(1, 100000, big.NewInt(0), keys[2]) if err := pool.AddLocal(tx); err != nil { t.Fatalf("failed to add underpriced local transaction: %v", err) } @@ -1377,7 +1377,7 @@ func TestTransactionReplacement(t *testing.T) { // Create the pool to test the pricing enforcement with db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -1395,49 +1395,49 @@ func TestTransactionReplacement(t *testing.T) { price := int64(100) threshold := (price * (100 + int64(testTxPoolConfig.PriceBump))) / 100 - if err := pool.AddRemote(pricedTransaction(0, big.NewInt(100000), big.NewInt(1), key)); err != nil { + if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), key)); err != nil { t.Fatalf("failed to add original cheap pending transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(0, big.NewInt(100001), big.NewInt(1), key)); err != ErrReplaceUnderpriced { + if err := pool.AddRemote(pricedTransaction(0, 100001, big.NewInt(1), key)); err != ErrReplaceUnderpriced { t.Fatalf("original cheap pending transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) } - if err := pool.AddRemote(pricedTransaction(0, big.NewInt(100000), big.NewInt(2), key)); err != nil { + if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(2), key)); err != nil { t.Fatalf("failed to replace original cheap pending transaction: %v", err) } if err := validateEvents(events, 2); err != nil { t.Fatalf("cheap replacement event firing failed: %v", err) } - if err := pool.AddRemote(pricedTransaction(0, big.NewInt(100000), big.NewInt(price), key)); err != nil { + if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(price), key)); err != nil { t.Fatalf("failed to add original proper pending transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(0, big.NewInt(100001), big.NewInt(threshold-1), key)); err != ErrReplaceUnderpriced { + if err := pool.AddRemote(pricedTransaction(0, 100001, big.NewInt(threshold-1), key)); err != ErrReplaceUnderpriced { t.Fatalf("original proper pending transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) } - if err := pool.AddRemote(pricedTransaction(0, big.NewInt(100000), big.NewInt(threshold), key)); err != nil { + if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(threshold), key)); err != nil { t.Fatalf("failed to replace original proper pending transaction: %v", err) } if err := validateEvents(events, 2); err != nil { t.Fatalf("proper replacement event firing failed: %v", err) } // Add queued transactions, ensuring the minimum price bump is enforced for replacement (for ultra low prices too) - if err := pool.AddRemote(pricedTransaction(2, big.NewInt(100000), big.NewInt(1), key)); err != nil { + if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(1), key)); err != nil { t.Fatalf("failed to add original cheap queued transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(2, big.NewInt(100001), big.NewInt(1), key)); err != ErrReplaceUnderpriced { + if err := pool.AddRemote(pricedTransaction(2, 100001, big.NewInt(1), key)); err != ErrReplaceUnderpriced { t.Fatalf("original cheap queued transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) } - if err := pool.AddRemote(pricedTransaction(2, big.NewInt(100000), big.NewInt(2), key)); err != nil { + if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(2), key)); err != nil { t.Fatalf("failed to replace original cheap queued transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(2, big.NewInt(100000), big.NewInt(price), key)); err != nil { + if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(price), key)); err != nil { t.Fatalf("failed to add original proper queued transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(2, big.NewInt(100001), big.NewInt(threshold-1), key)); err != ErrReplaceUnderpriced { + if err := pool.AddRemote(pricedTransaction(2, 100001, big.NewInt(threshold-1), key)); err != ErrReplaceUnderpriced { t.Fatalf("original proper queued transaction replacement error mismatch: have %v, want %v", err, ErrReplaceUnderpriced) } - if err := pool.AddRemote(pricedTransaction(2, big.NewInt(100000), big.NewInt(threshold), key)); err != nil { + if err := pool.AddRemote(pricedTransaction(2, 100000, big.NewInt(threshold), key)); err != nil { t.Fatalf("failed to replace original proper queued transaction: %v", err) } @@ -1472,7 +1472,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { // Create the original pool to inject transaction into the journal db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} config := testTxPoolConfig config.NoLocals = nolocals @@ -1489,16 +1489,16 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { pool.currentState.AddBalance(crypto.PubkeyToAddress(remote.PublicKey), big.NewInt(1000000000)) // Add three local and a remote transactions and ensure they are queued up - if err := pool.AddLocal(pricedTransaction(0, big.NewInt(100000), big.NewInt(1), local)); err != nil { + if err := pool.AddLocal(pricedTransaction(0, 100000, big.NewInt(1), local)); err != nil { t.Fatalf("failed to add local transaction: %v", err) } - if err := pool.AddLocal(pricedTransaction(1, big.NewInt(100000), big.NewInt(1), local)); err != nil { + if err := pool.AddLocal(pricedTransaction(1, 100000, big.NewInt(1), local)); err != nil { t.Fatalf("failed to add local transaction: %v", err) } - if err := pool.AddLocal(pricedTransaction(2, big.NewInt(100000), big.NewInt(1), local)); err != nil { + if err := pool.AddLocal(pricedTransaction(2, 100000, big.NewInt(1), local)); err != nil { t.Fatalf("failed to add local transaction: %v", err) } - if err := pool.AddRemote(pricedTransaction(0, big.NewInt(100000), big.NewInt(1), remote)); err != nil { + if err := pool.AddRemote(pricedTransaction(0, 100000, big.NewInt(1), remote)); err != nil { t.Fatalf("failed to add remote transaction: %v", err) } pending, queued := pool.Stats() @@ -1514,7 +1514,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { // Terminate the old pool, bump the local nonce, create a new pool and ensure relevant transaction survive pool.Stop() statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) - blockchain = &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain = &testBlockChain{statedb, 1000000, new(event.Feed)} pool = NewTxPool(config, params.TestChainConfig, blockchain) @@ -1541,7 +1541,7 @@ func testTransactionJournaling(t *testing.T, nolocals bool) { pool.Stop() statedb.SetNonce(crypto.PubkeyToAddress(local.PublicKey), 1) - blockchain = &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain = &testBlockChain{statedb, 1000000, new(event.Feed)} pool = NewTxPool(config, params.TestChainConfig, blockchain) pending, queued = pool.Stats() @@ -1571,7 +1571,7 @@ func TestTransactionStatusCheck(t *testing.T) { // Create the pool to test the status retrievals with db, _ := ethdb.NewMemDatabase() statedb, _ := state.New(common.Hash{}, state.NewDatabase(db)) - blockchain := &testBlockChain{statedb, big.NewInt(1000000), new(event.Feed)} + blockchain := &testBlockChain{statedb, 1000000, new(event.Feed)} pool := NewTxPool(testTxPoolConfig, params.TestChainConfig, blockchain) defer pool.Stop() @@ -1585,10 +1585,10 @@ func TestTransactionStatusCheck(t *testing.T) { // Generate and queue a batch of transactions, both pending and queued txs := types.Transactions{} - txs = append(txs, pricedTransaction(0, big.NewInt(100000), big.NewInt(1), keys[0])) // Pending only - txs = append(txs, pricedTransaction(0, big.NewInt(100000), big.NewInt(1), keys[1])) // Pending and queued - txs = append(txs, pricedTransaction(2, big.NewInt(100000), big.NewInt(1), keys[1])) - txs = append(txs, pricedTransaction(2, big.NewInt(100000), big.NewInt(1), keys[2])) // Queued only + txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[0])) // Pending only + txs = append(txs, pricedTransaction(0, 100000, big.NewInt(1), keys[1])) // Pending and queued + txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[1])) + txs = append(txs, pricedTransaction(2, 100000, big.NewInt(1), keys[2])) // Queued only // Import the transaction and ensure they are correctly added pool.AddRemotes(txs) @@ -1631,11 +1631,11 @@ func benchmarkPendingDemotion(b *testing.B, size int) { pool, key := setupTxPool() defer pool.Stop() - account, _ := deriveSender(transaction(0, big.NewInt(0), key)) + account, _ := deriveSender(transaction(0, 0, key)) pool.currentState.AddBalance(account, big.NewInt(1000000)) for i := 0; i < size; i++ { - tx := transaction(uint64(i), big.NewInt(100000), key) + tx := transaction(uint64(i), 100000, key) pool.promoteTx(account, tx.Hash(), tx) } // Benchmark the speed of pool validation @@ -1656,11 +1656,11 @@ func benchmarkFuturePromotion(b *testing.B, size int) { pool, key := setupTxPool() defer pool.Stop() - account, _ := deriveSender(transaction(0, big.NewInt(0), key)) + account, _ := deriveSender(transaction(0, 0, key)) pool.currentState.AddBalance(account, big.NewInt(1000000)) for i := 0; i < size; i++ { - tx := transaction(uint64(1+i), big.NewInt(100000), key) + tx := transaction(uint64(1+i), 100000, key) pool.enqueueTx(tx.Hash(), tx) } // Benchmark the speed of pool validation @@ -1676,12 +1676,12 @@ func BenchmarkPoolInsert(b *testing.B) { pool, key := setupTxPool() defer pool.Stop() - account, _ := deriveSender(transaction(0, big.NewInt(0), key)) + account, _ := deriveSender(transaction(0, 0, key)) pool.currentState.AddBalance(account, big.NewInt(1000000)) txs := make(types.Transactions, b.N) for i := 0; i < b.N; i++ { - txs[i] = transaction(uint64(i), big.NewInt(100000), key) + txs[i] = transaction(uint64(i), 100000, key) } // Benchmark importing the transactions into the queue b.ResetTimer() @@ -1700,14 +1700,14 @@ func benchmarkPoolBatchInsert(b *testing.B, size int) { pool, key := setupTxPool() defer pool.Stop() - account, _ := deriveSender(transaction(0, big.NewInt(0), key)) + account, _ := deriveSender(transaction(0, 0, key)) pool.currentState.AddBalance(account, big.NewInt(1000000)) batches := make([]types.Transactions, b.N) for i := 0; i < b.N; i++ { batches[i] = make(types.Transactions, size) for j := 0; j < size; j++ { - batches[i][j] = transaction(uint64(size*i+j), big.NewInt(100000), key) + batches[i][j] = transaction(uint64(size*i+j), 100000, key) } } // Benchmark importing the transactions into the queue diff --git a/core/types.go b/core/types.go index 1cfbbab29b..d0bbaf0aa7 100644 --- a/core/types.go +++ b/core/types.go @@ -17,8 +17,6 @@ package core import ( - "math/big" - "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -34,7 +32,7 @@ type Validator interface { // ValidateState validates the given statedb and optionally the receipts and // gas used. - ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error + ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas uint64) error } // Processor is an interface for processing blocks using a given initial state. @@ -44,5 +42,5 @@ type Validator interface { // of gas used in the process and return an error if any of the internal rules // failed. type Processor interface { - Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) + Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error) } diff --git a/core/types/block.go b/core/types/block.go index 1d00d9f930..9be62b9e00 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -77,8 +77,8 @@ type Header struct { Bloom Bloom `json:"logsBloom" gencodec:"required"` Difficulty *big.Int `json:"difficulty" gencodec:"required"` Number *big.Int `json:"number" gencodec:"required"` - GasLimit *big.Int `json:"gasLimit" gencodec:"required"` - GasUsed *big.Int `json:"gasUsed" gencodec:"required"` + GasLimit uint64 `json:"gasLimit" gencodec:"required"` + GasUsed uint64 `json:"gasUsed" gencodec:"required"` Time *big.Int `json:"timestamp" gencodec:"required"` Extra []byte `json:"extraData" gencodec:"required"` MixDigest common.Hash `json:"mixHash" gencodec:"required"` @@ -89,8 +89,8 @@ type Header struct { type headerMarshaling struct { Difficulty *hexutil.Big Number *hexutil.Big - GasLimit *hexutil.Big - GasUsed *hexutil.Big + GasLimit *hexutil.Uint64 + GasUsed *hexutil.Uint64 Time *hexutil.Big Extra hexutil.Bytes Hash common.Hash `json:"hash"` // adds call to Hash() in MarshalJSON @@ -243,12 +243,6 @@ func CopyHeader(h *Header) *Header { if cpy.Number = new(big.Int); h.Number != nil { cpy.Number.Set(h.Number) } - if cpy.GasLimit = new(big.Int); h.GasLimit != nil { - cpy.GasLimit.Set(h.GasLimit) - } - if cpy.GasUsed = new(big.Int); h.GasUsed != nil { - cpy.GasUsed.Set(h.GasUsed) - } if len(h.Extra) > 0 { cpy.Extra = make([]byte, len(h.Extra)) copy(cpy.Extra, h.Extra) @@ -302,8 +296,8 @@ func (b *Block) Transaction(hash common.Hash) *Transaction { } func (b *Block) Number() *big.Int { return new(big.Int).Set(b.header.Number) } -func (b *Block) GasLimit() *big.Int { return new(big.Int).Set(b.header.GasLimit) } -func (b *Block) GasUsed() *big.Int { return new(big.Int).Set(b.header.GasUsed) } +func (b *Block) GasLimit() uint64 { return b.header.GasLimit } +func (b *Block) GasUsed() uint64 { return b.header.GasUsed } func (b *Block) Difficulty() *big.Int { return new(big.Int).Set(b.header.Difficulty) } func (b *Block) Time() *big.Int { return new(big.Int).Set(b.header.Time) } diff --git a/core/types/block_test.go b/core/types/block_test.go index 93435ca00c..a35fbc25b1 100644 --- a/core/types/block_test.go +++ b/core/types/block_test.go @@ -41,8 +41,8 @@ func TestBlockEncoding(t *testing.T) { } } check("Difficulty", block.Difficulty(), big.NewInt(131072)) - check("GasLimit", block.GasLimit(), big.NewInt(3141592)) - check("GasUsed", block.GasUsed(), big.NewInt(21000)) + check("GasLimit", block.GasLimit(), uint64(3141592)) + check("GasUsed", block.GasUsed(), uint64(21000)) check("Coinbase", block.Coinbase(), common.HexToAddress("8888f1f195afa192cfee860698584c030f4c9db1")) check("MixDigest", block.MixDigest(), common.HexToHash("bd4472abb6659ebe3ee06ee4d7b72a00a9f4d001caca51342001075469aff498")) check("Root", block.Root(), common.HexToHash("ef1552a40b7165c3cd773806b9e0c165b75356e0314bf0706f279c729f51e017")) @@ -51,7 +51,7 @@ func TestBlockEncoding(t *testing.T) { check("Time", block.Time(), big.NewInt(1426516743)) check("Size", block.Size(), common.StorageSize(len(blockEnc))) - tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil) + tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), 50000, big.NewInt(10), nil) tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b100")) fmt.Println(block.Transactions()[0].Hash()) diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index bcff7a940d..8af0591044 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -22,8 +22,8 @@ func (h Header) MarshalJSON() ([]byte, error) { Bloom Bloom `json:"logsBloom" gencodec:"required"` Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` Number *hexutil.Big `json:"number" gencodec:"required"` - GasLimit *hexutil.Big `json:"gasLimit" gencodec:"required"` - GasUsed *hexutil.Big `json:"gasUsed" gencodec:"required"` + GasLimit hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` Time *hexutil.Big `json:"timestamp" gencodec:"required"` Extra hexutil.Bytes `json:"extraData" gencodec:"required"` MixDigest common.Hash `json:"mixHash" gencodec:"required"` @@ -40,8 +40,8 @@ func (h Header) MarshalJSON() ([]byte, error) { enc.Bloom = h.Bloom enc.Difficulty = (*hexutil.Big)(h.Difficulty) enc.Number = (*hexutil.Big)(h.Number) - enc.GasLimit = (*hexutil.Big)(h.GasLimit) - enc.GasUsed = (*hexutil.Big)(h.GasUsed) + enc.GasLimit = hexutil.Uint64(h.GasLimit) + enc.GasUsed = hexutil.Uint64(h.GasUsed) enc.Time = (*hexutil.Big)(h.Time) enc.Extra = h.Extra enc.MixDigest = h.MixDigest @@ -61,8 +61,8 @@ func (h *Header) UnmarshalJSON(input []byte) error { Bloom *Bloom `json:"logsBloom" gencodec:"required"` Difficulty *hexutil.Big `json:"difficulty" gencodec:"required"` Number *hexutil.Big `json:"number" gencodec:"required"` - GasLimit *hexutil.Big `json:"gasLimit" gencodec:"required"` - GasUsed *hexutil.Big `json:"gasUsed" gencodec:"required"` + GasLimit *hexutil.Uint64 `json:"gasLimit" gencodec:"required"` + GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` Time *hexutil.Big `json:"timestamp" gencodec:"required"` Extra hexutil.Bytes `json:"extraData" gencodec:"required"` MixDigest *common.Hash `json:"mixHash" gencodec:"required"` @@ -111,11 +111,11 @@ func (h *Header) UnmarshalJSON(input []byte) error { if dec.GasLimit == nil { return errors.New("missing required field 'gasLimit' for Header") } - h.GasLimit = (*big.Int)(dec.GasLimit) + h.GasLimit = (uint64)(*dec.GasLimit) if dec.GasUsed == nil { return errors.New("missing required field 'gasUsed' for Header") } - h.GasUsed = (*big.Int)(dec.GasUsed) + h.GasUsed = (uint64)(*dec.GasUsed) if dec.Time == nil { return errors.New("missing required field 'timestamp' for Header") } diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go index b95d99c951..5209668746 100644 --- a/core/types/gen_receipt_json.go +++ b/core/types/gen_receipt_json.go @@ -5,7 +5,6 @@ package types import ( "encoding/json" "errors" - "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -15,22 +14,22 @@ func (r Receipt) MarshalJSON() ([]byte, error) { type Receipt struct { PostState hexutil.Bytes `json:"root"` Status hexutil.Uint `json:"status"` - CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"` + CumulativeGasUsed hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress common.Address `json:"contractAddress"` - GasUsed *hexutil.Big `json:"gasUsed" gencodec:"required"` + GasUsed hexutil.Uint64 `json:"gasUsed" gencodec:"required"` } var enc Receipt enc.PostState = r.PostState enc.Status = hexutil.Uint(r.Status) - enc.CumulativeGasUsed = (*hexutil.Big)(r.CumulativeGasUsed) + enc.CumulativeGasUsed = hexutil.Uint64(r.CumulativeGasUsed) enc.Bloom = r.Bloom enc.Logs = r.Logs enc.TxHash = r.TxHash enc.ContractAddress = r.ContractAddress - enc.GasUsed = (*hexutil.Big)(r.GasUsed) + enc.GasUsed = hexutil.Uint64(r.GasUsed) return json.Marshal(&enc) } @@ -38,12 +37,12 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { type Receipt struct { PostState hexutil.Bytes `json:"root"` Status *hexutil.Uint `json:"status"` - CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"` + CumulativeGasUsed *hexutil.Uint64 `json:"cumulativeGasUsed" gencodec:"required"` Bloom *Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` TxHash *common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress *common.Address `json:"contractAddress"` - GasUsed *hexutil.Big `json:"gasUsed" gencodec:"required"` + GasUsed *hexutil.Uint64 `json:"gasUsed" gencodec:"required"` } var dec Receipt if err := json.Unmarshal(input, &dec); err != nil { @@ -58,7 +57,7 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { if dec.CumulativeGasUsed == nil { return errors.New("missing required field 'cumulativeGasUsed' for Receipt") } - r.CumulativeGasUsed = (*big.Int)(dec.CumulativeGasUsed) + r.CumulativeGasUsed = uint64(*dec.CumulativeGasUsed) if dec.Bloom == nil { return errors.New("missing required field 'logsBloom' for Receipt") } @@ -77,6 +76,6 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { if dec.GasUsed == nil { return errors.New("missing required field 'gasUsed' for Receipt") } - r.GasUsed = (*big.Int)(dec.GasUsed) + r.GasUsed = uint64(*dec.GasUsed) return nil } diff --git a/core/types/gen_tx_json.go b/core/types/gen_tx_json.go index 4fb658e0d9..a82822c36f 100644 --- a/core/types/gen_tx_json.go +++ b/core/types/gen_tx_json.go @@ -15,7 +15,7 @@ func (t txdata) MarshalJSON() ([]byte, error) { type txdata struct { AccountNonce hexutil.Uint64 `json:"nonce" gencodec:"required"` Price *hexutil.Big `json:"gasPrice" gencodec:"required"` - GasLimit *hexutil.Big `json:"gas" gencodec:"required"` + GasLimit hexutil.Uint64 `json:"gas" gencodec:"required"` Recipient *common.Address `json:"to" rlp:"nil"` Amount *hexutil.Big `json:"value" gencodec:"required"` Payload hexutil.Bytes `json:"input" gencodec:"required"` @@ -27,7 +27,7 @@ func (t txdata) MarshalJSON() ([]byte, error) { var enc txdata enc.AccountNonce = hexutil.Uint64(t.AccountNonce) enc.Price = (*hexutil.Big)(t.Price) - enc.GasLimit = (*hexutil.Big)(t.GasLimit) + enc.GasLimit = hexutil.Uint64(t.GasLimit) enc.Recipient = t.Recipient enc.Amount = (*hexutil.Big)(t.Amount) enc.Payload = t.Payload @@ -42,7 +42,7 @@ func (t *txdata) UnmarshalJSON(input []byte) error { type txdata struct { AccountNonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` Price *hexutil.Big `json:"gasPrice" gencodec:"required"` - GasLimit *hexutil.Big `json:"gas" gencodec:"required"` + GasLimit *hexutil.Uint64 `json:"gas" gencodec:"required"` Recipient *common.Address `json:"to" rlp:"nil"` Amount *hexutil.Big `json:"value" gencodec:"required"` Payload hexutil.Bytes `json:"input" gencodec:"required"` @@ -66,7 +66,7 @@ func (t *txdata) UnmarshalJSON(input []byte) error { if dec.GasLimit == nil { return errors.New("missing required field 'gas' for txdata") } - t.GasLimit = (*big.Int)(dec.GasLimit) + t.GasLimit = uint64(*dec.GasLimit) if dec.Recipient != nil { t.Recipient = dec.Recipient } diff --git a/core/types/receipt.go b/core/types/receipt.go index bc3c996b4f..208d54aaa1 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -20,7 +20,6 @@ import ( "bytes" "fmt" "io" - "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" @@ -45,46 +44,46 @@ const ( // Receipt represents the results of a transaction. type Receipt struct { // Consensus fields - PostState []byte `json:"root"` - Status uint `json:"status"` - CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"` - Bloom Bloom `json:"logsBloom" gencodec:"required"` - Logs []*Log `json:"logs" gencodec:"required"` + PostState []byte `json:"root"` + Status uint `json:"status"` + CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"` + Bloom Bloom `json:"logsBloom" gencodec:"required"` + Logs []*Log `json:"logs" gencodec:"required"` // Implementation fields (don't reorder!) TxHash common.Hash `json:"transactionHash" gencodec:"required"` ContractAddress common.Address `json:"contractAddress"` - GasUsed *big.Int `json:"gasUsed" gencodec:"required"` + GasUsed uint64 `json:"gasUsed" gencodec:"required"` } type receiptMarshaling struct { PostState hexutil.Bytes Status hexutil.Uint - CumulativeGasUsed *hexutil.Big - GasUsed *hexutil.Big + CumulativeGasUsed hexutil.Uint64 + GasUsed hexutil.Uint64 } // receiptRLP is the consensus encoding of a receipt. type receiptRLP struct { PostStateOrStatus []byte - CumulativeGasUsed *big.Int + CumulativeGasUsed uint64 Bloom Bloom Logs []*Log } type receiptStorageRLP struct { PostStateOrStatus []byte - CumulativeGasUsed *big.Int + CumulativeGasUsed uint64 Bloom Bloom TxHash common.Hash ContractAddress common.Address Logs []*LogForStorage - GasUsed *big.Int + GasUsed uint64 } // NewReceipt creates a barebone transaction receipt, copying the init fields. -func NewReceipt(root []byte, failed bool, cumulativeGasUsed *big.Int) *Receipt { - r := &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)} +func NewReceipt(root []byte, failed bool, cumulativeGasUsed uint64) *Receipt { + r := &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: cumulativeGasUsed} if failed { r.Status = ReceiptStatusFailed } else { diff --git a/core/types/transaction.go b/core/types/transaction.go index ee4140ce45..a7ed211e42 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -57,7 +57,7 @@ type Transaction struct { type txdata struct { AccountNonce uint64 `json:"nonce" gencodec:"required"` Price *big.Int `json:"gasPrice" gencodec:"required"` - GasLimit *big.Int `json:"gas" gencodec:"required"` + GasLimit uint64 `json:"gas" gencodec:"required"` Recipient *common.Address `json:"to" rlp:"nil"` // nil means contract creation Amount *big.Int `json:"value" gencodec:"required"` Payload []byte `json:"input" gencodec:"required"` @@ -74,7 +74,7 @@ type txdata struct { type txdataMarshaling struct { AccountNonce hexutil.Uint64 Price *hexutil.Big - GasLimit *hexutil.Big + GasLimit hexutil.Uint64 Amount *hexutil.Big Payload hexutil.Bytes V *hexutil.Big @@ -82,15 +82,15 @@ type txdataMarshaling struct { S *hexutil.Big } -func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction { +func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction { return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data) } -func NewContractCreation(nonce uint64, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction { +func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction { return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data) } -func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction { +func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction { if len(data) > 0 { data = common.CopyBytes(data) } @@ -99,7 +99,7 @@ func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice Recipient: to, Payload: data, Amount: new(big.Int), - GasLimit: new(big.Int), + GasLimit: gasLimit, Price: new(big.Int), V: new(big.Int), R: new(big.Int), @@ -108,9 +108,6 @@ func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice if amount != nil { d.Amount.Set(amount) } - if gasLimit != nil { - d.GasLimit.Set(gasLimit) - } if gasPrice != nil { d.Price.Set(gasPrice) } @@ -182,7 +179,7 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { } func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) } -func (tx *Transaction) Gas() *big.Int { return new(big.Int).Set(tx.data.GasLimit) } +func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit } func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) } func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) } func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce } @@ -227,8 +224,8 @@ func (tx *Transaction) Size() common.StorageSize { func (tx *Transaction) AsMessage(s Signer) (Message, error) { msg := Message{ nonce: tx.data.AccountNonce, - price: new(big.Int).Set(tx.data.Price), - gasLimit: new(big.Int).Set(tx.data.GasLimit), + gasLimit: tx.data.GasLimit, + gasPrice: new(big.Int).Set(tx.data.Price), to: tx.data.Recipient, amount: tx.data.Amount, data: tx.data.Payload, @@ -254,7 +251,7 @@ func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, e // Cost returns amount + gasprice * gaslimit. func (tx *Transaction) Cost() *big.Int { - total := new(big.Int).Mul(tx.data.Price, tx.data.GasLimit) + total := new(big.Int).Mul(tx.data.Price, new(big.Int).SetUint64(tx.data.GasLimit)) total.Add(total, tx.data.Amount) return total } @@ -440,22 +437,24 @@ func (t *TransactionsByPriceAndNonce) Pop() { // // NOTE: In a future PR this will be removed. type Message struct { - to *common.Address - from common.Address - nonce uint64 - amount, price, gasLimit *big.Int - data []byte - checkNonce bool + to *common.Address + from common.Address + nonce uint64 + amount *big.Int + gasLimit uint64 + gasPrice *big.Int + data []byte + checkNonce bool } -func NewMessage(from common.Address, to *common.Address, nonce uint64, amount, gasLimit, price *big.Int, data []byte, checkNonce bool) Message { +func NewMessage(from common.Address, to *common.Address, nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, checkNonce bool) Message { return Message{ from: from, to: to, nonce: nonce, amount: amount, - price: price, gasLimit: gasLimit, + gasPrice: gasPrice, data: data, checkNonce: checkNonce, } @@ -463,9 +462,9 @@ func NewMessage(from common.Address, to *common.Address, nonce uint64, amount, g func (m Message) From() common.Address { return m.from } func (m Message) To() *common.Address { return m.to } -func (m Message) GasPrice() *big.Int { return m.price } +func (m Message) GasPrice() *big.Int { return m.gasPrice } func (m Message) Value() *big.Int { return m.amount } -func (m Message) Gas() *big.Int { return m.gasLimit } +func (m Message) Gas() uint64 { return m.gasLimit } func (m Message) Nonce() uint64 { return m.nonce } func (m Message) Data() []byte { return m.data } func (m Message) CheckNonce() bool { return m.checkNonce } diff --git a/core/types/transaction_signing_test.go b/core/types/transaction_signing_test.go index 7f799fb101..689fc38a9b 100644 --- a/core/types/transaction_signing_test.go +++ b/core/types/transaction_signing_test.go @@ -30,7 +30,7 @@ func TestEIP155Signing(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) signer := NewEIP155Signer(big.NewInt(18)) - tx, err := SignTx(NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil), signer, key) + tx, err := SignTx(NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil), signer, key) if err != nil { t.Fatal(err) } @@ -49,7 +49,7 @@ func TestEIP155ChainId(t *testing.T) { addr := crypto.PubkeyToAddress(key.PublicKey) signer := NewEIP155Signer(big.NewInt(18)) - tx, err := SignTx(NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil), signer, key) + tx, err := SignTx(NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil), signer, key) if err != nil { t.Fatal(err) } @@ -61,7 +61,7 @@ func TestEIP155ChainId(t *testing.T) { t.Error("expected chainId to be", signer.chainId, "got", tx.ChainId()) } - tx = NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil) + tx = NewTransaction(0, addr, new(big.Int), 0, new(big.Int), nil) tx, err = SignTx(tx, HomesteadSigner{}, key) if err != nil { t.Fatal(err) @@ -118,7 +118,7 @@ func TestEIP155SigningVitalik(t *testing.T) { func TestChainId(t *testing.T) { key, _ := defaultTestKey() - tx := NewTransaction(0, common.Address{}, new(big.Int), new(big.Int), new(big.Int), nil) + tx := NewTransaction(0, common.Address{}, new(big.Int), 0, new(big.Int), nil) var err error tx, err = SignTx(tx, NewEIP155Signer(big.NewInt(1)), key) diff --git a/core/types/transaction_test.go b/core/types/transaction_test.go index 82d74e3b34..d1861b14cd 100644 --- a/core/types/transaction_test.go +++ b/core/types/transaction_test.go @@ -34,7 +34,7 @@ var ( emptyTx = NewTransaction( 0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), - big.NewInt(0), big.NewInt(0), big.NewInt(0), + big.NewInt(0), 0, big.NewInt(0), nil, ) @@ -42,7 +42,7 @@ var ( 3, common.HexToAddress("b94f5374fce5edbc8e2a8697c15331677e6ebf0b"), big.NewInt(10), - big.NewInt(2000), + 2000, big.NewInt(1), common.FromHex("5544"), ).WithSignature( @@ -139,7 +139,7 @@ func TestTransactionPriceNonceSort(t *testing.T) { for start, key := range keys { addr := crypto.PubkeyToAddress(key.PublicKey) for i := 0; i < 25; i++ { - tx, _ := SignTx(NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(int64(start+i)), nil), signer, key) + tx, _ := SignTx(NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), 100, big.NewInt(int64(start+i)), nil), signer, key) groups[addr] = append(groups[addr], tx) } } @@ -204,9 +204,9 @@ func TestTransactionJSON(t *testing.T) { var tx *Transaction switch i % 2 { case 0: - tx = NewTransaction(i, common.Address{1}, common.Big0, common.Big1, common.Big2, []byte("abcdef")) + tx = NewTransaction(i, common.Address{1}, common.Big0, 1, common.Big2, []byte("abcdef")) case 1: - tx = NewContractCreation(i, common.Big0, common.Big1, common.Big2, []byte("abcdef")) + tx = NewContractCreation(i, common.Big0, 1, common.Big2, []byte("abcdef")) } tx, err := SignTx(tx, signer, key) diff --git a/core/vm/evm.go b/core/vm/evm.go index a3f3a97cbc..8796a633ec 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -69,7 +69,7 @@ type Context struct { // Block information Coinbase common.Address // Provides information for COINBASE - GasLimit *big.Int // Provides information for GASLIMIT + GasLimit uint64 // Provides information for GASLIMIT BlockNumber *big.Int // Provides information for NUMBER Time *big.Int // Provides information for TIME Difficulty *big.Int // Provides information for DIFFICULTY diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index ff109af57b..83adba428e 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -17,8 +17,6 @@ package vm import ( - "math/big" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/params" @@ -130,7 +128,7 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m // 0 => non 0 return params.SstoreSetGas, nil } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { - evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SstoreRefundGas)) + evm.StateDB.AddRefund(params.SstoreRefundGas) return params.SstoreClearGas, nil } else { @@ -405,7 +403,7 @@ func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, } if !evm.StateDB.HasSuicided(contract.Address()) { - evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SuicideRefundGas)) + evm.StateDB.AddRefund(params.SuicideRefundGas) } return gas, nil } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 1d1585fcac..7661725010 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -472,7 +472,7 @@ func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac } func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) { - stack.push(math.U256(new(big.Int).Set(evm.GasLimit))) + stack.push(math.U256(new(big.Int).SetUint64(evm.GasLimit))) return nil, nil } diff --git a/core/vm/interface.go b/core/vm/interface.go index c0c52732bb..1ef91cf1d6 100644 --- a/core/vm/interface.go +++ b/core/vm/interface.go @@ -39,8 +39,8 @@ type StateDB interface { SetCode(common.Address, []byte) GetCodeSize(common.Address) int - AddRefund(*big.Int) - GetRefund() *big.Int + AddRefund(uint64) + GetRefund() uint64 GetState(common.Address, common.Hash) common.Hash SetState(common.Address, common.Hash, common.Hash) diff --git a/core/vm/noop.go b/core/vm/noop.go index 2a04a95654..b71ead0d77 100644 --- a/core/vm/noop.go +++ b/core/vm/noop.go @@ -55,8 +55,8 @@ func (NoopStateDB) GetCodeHash(common.Address) common.Hash func (NoopStateDB) GetCode(common.Address) []byte { return nil } func (NoopStateDB) SetCode(common.Address, []byte) {} func (NoopStateDB) GetCodeSize(common.Address) int { return 0 } -func (NoopStateDB) AddRefund(*big.Int) {} -func (NoopStateDB) GetRefund() *big.Int { return nil } +func (NoopStateDB) AddRefund(uint64) {} +func (NoopStateDB) GetRefund() uint64 { return 0 } func (NoopStateDB) GetState(common.Address, common.Hash) common.Hash { return common.Hash{} } func (NoopStateDB) SetState(common.Address, common.Hash, common.Hash) {} func (NoopStateDB) Suicide(common.Address) bool { return false } diff --git a/core/vm/runtime/env.go b/core/vm/runtime/env.go index 818da1be26..31c9b9cf9d 100644 --- a/core/vm/runtime/env.go +++ b/core/vm/runtime/env.go @@ -17,8 +17,6 @@ package runtime import ( - "math/big" - "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/vm" @@ -35,7 +33,7 @@ func NewEnv(cfg *Config) *vm.EVM { BlockNumber: cfg.BlockNumber, Time: cfg.Time, Difficulty: cfg.Difficulty, - GasLimit: new(big.Int).SetUint64(cfg.GasLimit), + GasLimit: cfg.GasLimit, GasPrice: cfg.GasPrice, } diff --git a/eth/bind.go b/eth/bind.go index d09977dbc2..769a6c741c 100644 --- a/eth/bind.go +++ b/eth/bind.go @@ -83,9 +83,7 @@ func toCallArgs(msg ethereum.CallMsg) ethapi.CallArgs { To: msg.To, From: msg.From, Data: msg.Data, - } - if msg.Gas != nil { - args.Gas = hexutil.Big(*msg.Gas) + Gas: hexutil.Uint64(msg.Gas), } if msg.GasPrice != nil { args.GasPrice = hexutil.Big(*msg.GasPrice) @@ -124,9 +122,9 @@ func (b *ContractBackend) SuggestGasPrice(ctx context.Context) (*big.Int, error) // the backend blockchain. There is no guarantee that this is the true gas limit // requirement as other transactions may be added or removed by miners, but it // should provide a basis for setting a reasonable default. -func (b *ContractBackend) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (*big.Int, error) { - out, err := b.bcapi.EstimateGas(ctx, toCallArgs(msg)) - return out.ToInt(), err +func (b *ContractBackend) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) { + gas, err := b.bcapi.EstimateGas(ctx, toCallArgs(msg)) + return uint64(gas), err } // SendTransaction implements bind.ContractTransactor injects the transaction diff --git a/eth/downloader/downloader_test.go b/eth/downloader/downloader_test.go index e14264944b..ad5a62c481 100644 --- a/eth/downloader/downloader_test.go +++ b/eth/downloader/downloader_test.go @@ -118,7 +118,7 @@ func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, paren // If the block number is multiple of 3, send a bonus transaction to the miner if parent == dl.genesis && i%3 == 0 { signer := types.MakeSigner(params.TestChainConfig, block.Number()) - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), new(big.Int).SetUint64(params.TxGas), nil, nil), signer, testKey) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey) if err != nil { panic(err) } diff --git a/eth/fetcher/fetcher_test.go b/eth/fetcher/fetcher_test.go index e6a6394178..9d53b98b60 100644 --- a/eth/fetcher/fetcher_test.go +++ b/eth/fetcher/fetcher_test.go @@ -52,7 +52,7 @@ func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common // If the block number is multiple of 3, send a bonus transaction to the miner if parent == genesis && i%3 == 0 { signer := types.MakeSigner(params.TestChainConfig, block.Number()) - tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), new(big.Int).SetUint64(params.TxGas), nil, nil), signer, testKey) + tx, err := types.SignTx(types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil), signer, testKey) if err != nil { panic(err) } diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index a5025db3d1..dd6d4433d6 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -195,11 +195,11 @@ func TestPendingTxFilter(t *testing.T) { api = NewPublicFilterAPI(backend, false) transactions = []*types.Transaction{ - types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), - types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), - types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), - types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), - types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), new(big.Int), new(big.Int), nil), + types.NewTransaction(0, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), + types.NewTransaction(1, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), + types.NewTransaction(2, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), + types.NewTransaction(3, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), + types.NewTransaction(4, common.HexToAddress("0xb794f5ea0ba39494ce83a213fffba74279579268"), new(big.Int), 0, new(big.Int), nil), } hashes []common.Hash diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 729d0afc89..0018142c46 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -34,7 +34,7 @@ import ( ) func makeReceipt(addr common.Address) *types.Receipt { - receipt := types.NewReceipt(nil, false, new(big.Int)) + receipt := types.NewReceipt(nil, false, 0) receipt.Logs = []*types.Log{ {Address: addr}, } @@ -136,7 +136,7 @@ func TestFilters(t *testing.T) { chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 1000, func(i int, gen *core.BlockGen) { switch i { case 1: - receipt := types.NewReceipt(nil, false, new(big.Int)) + receipt := types.NewReceipt(nil, false, 0) receipt.Logs = []*types.Log{ { Address: addr, @@ -145,7 +145,7 @@ func TestFilters(t *testing.T) { } gen.AddUncheckedReceipt(receipt) case 2: - receipt := types.NewReceipt(nil, false, new(big.Int)) + receipt := types.NewReceipt(nil, false, 0) receipt.Logs = []*types.Log{ { Address: addr, @@ -154,7 +154,7 @@ func TestFilters(t *testing.T) { } gen.AddUncheckedReceipt(receipt) case 998: - receipt := types.NewReceipt(nil, false, new(big.Int)) + receipt := types.NewReceipt(nil, false, 0) receipt.Logs = []*types.Log{ { Address: addr, @@ -163,7 +163,7 @@ func TestFilters(t *testing.T) { } gen.AddUncheckedReceipt(receipt) case 999: - receipt := types.NewReceipt(nil, false, new(big.Int)) + receipt := types.NewReceipt(nil, false, 0) receipt.Logs = []*types.Log{ { Address: addr, diff --git a/eth/handler_test.go b/eth/handler_test.go index ebbd83c3ad..9a02eddfb2 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -37,8 +37,6 @@ import ( "github.com/ethereum/go-ethereum/params" ) -var bigTxGas = new(big.Int).SetUint64(params.TxGas) - // Tests that protocol versions and modes of operations are matched up properly. func TestProtocolCompatibility(t *testing.T) { // Define the compatibility chart @@ -315,13 +313,13 @@ func testGetNodeData(t *testing.T, protocol int) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) - tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: @@ -407,13 +405,13 @@ func testGetReceipt(t *testing.T, protocol int) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) - tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBank), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: diff --git a/eth/helper_test.go b/eth/helper_test.go index bfb003c8bd..d44574b86b 100644 --- a/eth/helper_test.go +++ b/eth/helper_test.go @@ -130,7 +130,7 @@ func (p *testTxPool) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscr // newTestTransaction create a new dummy transaction. func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction { - tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize)) + tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), 100000, big.NewInt(0), make([]byte, datasize)) tx, _ = types.SignTx(tx, types.HomesteadSigner{}, from) return tx } diff --git a/eth/tracers/tracers_test.go b/eth/tracers/tracers_test.go index 1392807978..bf8120228f 100644 --- a/eth/tracers/tracers_test.go +++ b/eth/tracers/tracers_test.go @@ -156,7 +156,7 @@ func TestCallTracer(t *testing.T) { BlockNumber: new(big.Int).SetUint64(uint64(test.Context.Number)), Time: new(big.Int).SetUint64(uint64(test.Context.Time)), Difficulty: (*big.Int)(test.Context.Difficulty), - GasLimit: new(big.Int).SetUint64(uint64(test.Context.GasLimit)), + GasLimit: uint64(test.Context.GasLimit), GasPrice: tx.GasPrice(), } db, _ := ethdb.NewMemDatabase() @@ -174,7 +174,7 @@ func TestCallTracer(t *testing.T) { t.Fatalf("failed to prepare transaction for tracing: %v", err) } st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas())) - if _, _, _, _, err = st.TransitionDb(); err != nil { + if _, _, _, err = st.TransitionDb(); err != nil { t.Fatalf("failed to execute transaction: %v", err) } // Retrieve the trace result and compare against the etalon diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 7f73ab113c..87a912901a 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -455,13 +455,13 @@ func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) { // the current pending state of the backend blockchain. There is no guarantee that this is // the true gas limit requirement as other transactions may be added or removed by miners, // but it should provide a basis for setting a reasonable default. -func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (*big.Int, error) { - var hex hexutil.Big +func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) { + var hex hexutil.Uint64 err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg)) if err != nil { - return nil, err + return 0, err } - return (*big.Int)(&hex), nil + return uint64(hex), nil } // SendTransaction injects a signed transaction into the pending pool for execution. @@ -487,8 +487,8 @@ func toCallArg(msg ethereum.CallMsg) interface{} { if msg.Value != nil { arg["value"] = (*hexutil.Big)(msg.Value) } - if msg.Gas != nil { - arg["gas"] = (*hexutil.Big)(msg.Gas) + if msg.Gas != 0 { + arg["gas"] = hexutil.Uint64(msg.Gas) } if msg.GasPrice != nil { arg["gasPrice"] = (*hexutil.Big)(msg.GasPrice) diff --git a/ethstats/ethstats.go b/ethstats/ethstats.go index 1e27a1e637..8204750be0 100644 --- a/ethstats/ethstats.go +++ b/ethstats/ethstats.go @@ -473,8 +473,8 @@ type blockStats struct { ParentHash common.Hash `json:"parentHash"` Timestamp *big.Int `json:"timestamp"` Miner common.Address `json:"miner"` - GasUsed *big.Int `json:"gasUsed"` - GasLimit *big.Int `json:"gasLimit"` + GasUsed uint64 `json:"gasUsed"` + GasLimit uint64 `json:"gasLimit"` Diff string `json:"difficulty"` TotalDiff string `json:"totalDifficulty"` Txs []txStats `json:"transactions"` @@ -559,8 +559,8 @@ func (s *Service) assembleBlockStats(block *types.Block) *blockStats { ParentHash: header.ParentHash, Timestamp: header.Time, Miner: author, - GasUsed: new(big.Int).Set(header.GasUsed), - GasLimit: new(big.Int).Set(header.GasLimit), + GasUsed: header.GasUsed, + GasLimit: header.GasLimit, Diff: header.Difficulty.String(), TotalDiff: td.String(), Txs: txs, diff --git a/interfaces.go b/interfaces.go index 67f236ef75..1ae1eba48a 100644 --- a/interfaces.go +++ b/interfaces.go @@ -115,7 +115,7 @@ type ChainSyncReader interface { type CallMsg struct { From common.Address // the sender of the 'transaction' To *common.Address // the destination contract (nil for contract creation) - Gas *big.Int // if nil, the call executes with near-infinite gas + Gas uint64 // if 0, the call executes with near-infinite gas GasPrice *big.Int // wei <-> gas exchange ratio Value *big.Int // amount of wei sent along with the call Data []byte // input data, usually an ABI-encoded contract method invocation @@ -200,7 +200,7 @@ type PendingContractCaller interface { // true gas limit requirement as other transactions may be added or removed by miners, but // it should provide a basis for setting a reasonable default. type GasEstimator interface { - EstimateGas(ctx context.Context, call CallMsg) (usedGas *big.Int, err error) + EstimateGas(ctx context.Context, call CallMsg) (uint64, error) } // A PendingStateEventer provides access to real time notifications about changes to the diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index d07b2e693a..55bd5aa1ba 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -45,7 +45,6 @@ import ( ) const ( - defaultGas = 90000 defaultGasPrice = 50 * params.Shannon ) @@ -575,18 +574,18 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A type CallArgs struct { From common.Address `json:"from"` To *common.Address `json:"to"` - Gas hexutil.Big `json:"gas"` + Gas hexutil.Uint64 `json:"gas"` GasPrice hexutil.Big `json:"gasPrice"` Value hexutil.Big `json:"value"` Data hexutil.Bytes `json:"data"` } -func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, *big.Int, bool, error) { +func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr rpc.BlockNumber, vmCfg vm.Config) ([]byte, uint64, bool, error) { defer func(start time.Time) { log.Debug("Executing EVM call finished", "runtime", time.Since(start)) }(time.Now()) state, header, err := s.b.StateAndHeaderByNumber(ctx, blockNr) if state == nil || err != nil { - return nil, common.Big0, false, err + return nil, 0, false, err } // Set sender address or use a default if none specified addr := args.From @@ -598,9 +597,9 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr } } // Set default gas & gas price if none were set - gas, gasPrice := args.Gas.ToInt(), args.GasPrice.ToInt() - if gas.Sign() == 0 { - gas = big.NewInt(50000000) + gas, gasPrice := uint64(args.Gas), args.GasPrice.ToInt() + if gas == 0 { + gas = 50000000 } if gasPrice.Sign() == 0 { gasPrice = new(big.Int).SetUint64(defaultGasPrice) @@ -624,7 +623,7 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr // Get a new instance of the EVM. evm, vmError, err := s.b.GetEVM(ctx, msg, state, header, vmCfg) if err != nil { - return nil, common.Big0, false, err + return nil, 0, false, err } // Wait for the context to be done and cancel the evm. Even if the // EVM has finished, cancelling may be done (repeatedly) @@ -635,10 +634,10 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr // Setup the gas pool (also for unmetered requests) // and apply the message. - gp := new(core.GasPool).AddGas(math.MaxBig256) + gp := new(core.GasPool).AddGas(math.MaxUint64) res, gas, failed, err := core.ApplyMessage(evm, msg, gp) if err := vmError(); err != nil { - return nil, common.Big0, false, err + return nil, 0, false, err } return res, gas, failed, err } @@ -652,28 +651,29 @@ func (s *PublicBlockChainAPI) Call(ctx context.Context, args CallArgs, blockNr r // EstimateGas returns an estimate of the amount of gas needed to execute the // given transaction against the current pending block. -func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (*hexutil.Big, error) { - // Determine the lowest and highest possible gas limits to binary search in between +func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (hexutil.Uint64, error) { + // Binary search the gas requirement, as it may be higher than the amount used var ( lo uint64 = params.TxGas - 1 hi uint64 cap uint64 ) - if (*big.Int)(&args.Gas).Uint64() >= params.TxGas { - hi = (*big.Int)(&args.Gas).Uint64() + if uint64(args.Gas) >= params.TxGas { + hi = uint64(args.Gas) } else { // Retrieve the current pending block to act as the gas ceiling block, err := s.b.BlockByNumber(ctx, rpc.PendingBlockNumber) if err != nil { - return nil, err + return 0, err } - hi = block.GasLimit().Uint64() + hi = block.GasLimit() } cap = hi // Create a helper to check if a gas allowance results in an executable transaction executable := func(gas uint64) bool { - (*big.Int)(&args.Gas).SetUint64(gas) + args.Gas = hexutil.Uint64(gas) + _, _, failed, err := s.doCall(ctx, args, rpc.PendingBlockNumber, vm.Config{}) if err != nil || failed { return false @@ -692,17 +692,17 @@ func (s *PublicBlockChainAPI) EstimateGas(ctx context.Context, args CallArgs) (* // Reject the transaction as invalid if it still fails at the highest allowance if hi == cap { if !executable(hi) { - return nil, fmt.Errorf("gas required exceeds allowance or always failing transaction") + return 0, fmt.Errorf("gas required exceeds allowance or always failing transaction") } } - return (*hexutil.Big)(new(big.Int).SetUint64(hi)), nil + return hexutil.Uint64(hi), nil } // ExecutionResult groups all structured logs emitted by the EVM // while replaying a transaction in debug mode as well as transaction // execution status, the amount of gas used and the return value type ExecutionResult struct { - Gas *big.Int `json:"gas"` + Gas uint64 `json:"gas"` Failed bool `json:"failed"` ReturnValue string `json:"returnValue"` StructLogs []StructLogRes `json:"structLogs"` @@ -778,8 +778,8 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx "totalDifficulty": (*hexutil.Big)(s.b.GetTd(b.Hash())), "extraData": hexutil.Bytes(head.Extra), "size": hexutil.Uint64(uint64(b.Size().Int64())), - "gasLimit": (*hexutil.Big)(head.GasLimit), - "gasUsed": (*hexutil.Big)(head.GasUsed), + "gasLimit": hexutil.Uint64(head.GasLimit), + "gasUsed": hexutil.Uint64(head.GasUsed), "timestamp": (*hexutil.Big)(head.Time), "transactionsRoot": head.TxHash, "receiptsRoot": head.ReceiptHash, @@ -822,7 +822,7 @@ type RPCTransaction struct { BlockHash common.Hash `json:"blockHash"` BlockNumber *hexutil.Big `json:"blockNumber"` From common.Address `json:"from"` - Gas *hexutil.Big `json:"gas"` + Gas hexutil.Uint64 `json:"gas"` GasPrice *hexutil.Big `json:"gasPrice"` Hash common.Hash `json:"hash"` Input hexutil.Bytes `json:"input"` @@ -847,7 +847,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber result := &RPCTransaction{ From: from, - Gas: (*hexutil.Big)(tx.Gas()), + Gas: hexutil.Uint64(tx.Gas()), GasPrice: (*hexutil.Big)(tx.GasPrice()), Hash: tx.Hash(), Input: hexutil.Bytes(tx.Data()), @@ -1024,8 +1024,8 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[ "transactionIndex": hexutil.Uint64(index), "from": from, "to": tx.To(), - "gasUsed": (*hexutil.Big)(receipt.GasUsed), - "cumulativeGasUsed": (*hexutil.Big)(receipt.CumulativeGasUsed), + "gasUsed": hexutil.Uint64(receipt.GasUsed), + "cumulativeGasUsed": hexutil.Uint64(receipt.CumulativeGasUsed), "contractAddress": nil, "logs": receipt.Logs, "logsBloom": receipt.Bloom, @@ -1068,7 +1068,7 @@ func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transacti type SendTxArgs struct { From common.Address `json:"from"` To *common.Address `json:"to"` - Gas *hexutil.Big `json:"gas"` + Gas *hexutil.Uint64 `json:"gas"` GasPrice *hexutil.Big `json:"gasPrice"` Value *hexutil.Big `json:"value"` Nonce *hexutil.Uint64 `json:"nonce"` @@ -1081,7 +1081,8 @@ type SendTxArgs struct { // setDefaults is a helper function that fills in default values for unspecified tx fields. func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error { if args.Gas == nil { - args.Gas = (*hexutil.Big)(big.NewInt(defaultGas)) + args.Gas = new(hexutil.Uint64) + *(*uint64)(args.Gas) = 90000 } if args.GasPrice == nil { price, err := b.SuggestPrice(ctx) @@ -1114,9 +1115,9 @@ func (args *SendTxArgs) toTransaction() *types.Transaction { input = *args.Input } if args.To == nil { - return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), input) + return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input) } - return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), input) + return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input) } // submitTransaction is a helper function that submits tx to txPool and logs a message. @@ -1264,7 +1265,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err // Resend accepts an existing transaction and a new gas price and limit. It will remove // the given transaction from the pool and reinsert it with the new gas price and limit. -func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxArgs, gasPrice, gasLimit *hexutil.Big) (common.Hash, error) { +func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, sendArgs SendTxArgs, gasPrice *hexutil.Big, gasLimit *hexutil.Uint64) (common.Hash, error) { if sendArgs.Nonce == nil { return common.Hash{}, fmt.Errorf("missing transaction nonce in transaction spec") } diff --git a/internal/ethapi/backend.go b/internal/ethapi/backend.go index 368fa48726..af95d7906f 100644 --- a/internal/ethapi/backend.go +++ b/internal/ethapi/backend.go @@ -37,13 +37,14 @@ import ( // Backend interface provides the common API services (that are provided by // both full and light clients) with access to necessary functions. type Backend interface { - // general Ethereum API + // General Ethereum API Downloader() *downloader.Downloader ProtocolVersion() int SuggestPrice(ctx context.Context) (*big.Int, error) ChainDb() ethdb.Database EventMux() *event.TypeMux AccountManager() *accounts.Manager + // BlockChain API SetHead(number uint64) HeaderByNumber(ctx context.Context, blockNr rpc.BlockNumber) (*types.Header, error) diff --git a/les/handler_test.go b/les/handler_test.go index 6207061cc7..7d67af26a1 100644 --- a/les/handler_test.go +++ b/les/handler_test.go @@ -443,16 +443,16 @@ func TestTransactionStatusLes2(t *testing.T) { signer := types.HomesteadSigner{} // test error status by sending an underpriced transaction - tx0, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) + tx0, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) test(tx0, true, txStatus{Status: core.TxStatusUnknown, Error: core.ErrUnderpriced}) - tx1, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), bigTxGas, big.NewInt(100000000000), nil), signer, testBankKey) + tx1, _ := types.SignTx(types.NewTransaction(0, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey) test(tx1, false, txStatus{Status: core.TxStatusUnknown}) // query before sending, should be unknown test(tx1, true, txStatus{Status: core.TxStatusPending}) // send valid processable tx, should return pending test(tx1, true, txStatus{Status: core.TxStatusPending}) // adding it again should not return an error - tx2, _ := types.SignTx(types.NewTransaction(1, acc1Addr, big.NewInt(10000), bigTxGas, big.NewInt(100000000000), nil), signer, testBankKey) - tx3, _ := types.SignTx(types.NewTransaction(2, acc1Addr, big.NewInt(10000), bigTxGas, big.NewInt(100000000000), nil), signer, testBankKey) + tx2, _ := types.SignTx(types.NewTransaction(1, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey) + tx3, _ := types.SignTx(types.NewTransaction(2, acc1Addr, big.NewInt(10000), params.TxGas, big.NewInt(100000000000), nil), signer, testBankKey) // send transactions in the wrong order, tx3 should be queued test(tx3, true, txStatus{Status: core.TxStatusQueued}) test(tx2, true, txStatus{Status: core.TxStatusPending}) diff --git a/les/helper_test.go b/les/helper_test.go index 92a98e27ed..b881b41ce8 100644 --- a/les/helper_test.go +++ b/les/helper_test.go @@ -56,8 +56,6 @@ var ( testContractDeployed = uint64(2) testBufLimit = uint64(100) - - bigTxGas = new(big.Int).SetUint64(params.TxGas) ) /* @@ -81,17 +79,17 @@ func testChainGen(i int, block *core.BlockGen) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. // acc1Addr creates a test contract. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) nonce := block.TxNonce(acc1Addr) - tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) + tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) nonce++ - tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode), signer, acc1Key) + tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 200000, big.NewInt(0), testContractCode), signer, acc1Key) testContractAddr = crypto.CreateAddress(acc1Addr, nonce) block.AddTx(tx1) block.AddTx(tx2) @@ -101,7 +99,7 @@ func testChainGen(i int, block *core.BlockGen) { block.SetCoinbase(acc2Addr) block.SetExtra([]byte("yeehaw")) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, data), signer, testBankKey) block.AddTx(tx) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). @@ -112,7 +110,7 @@ func testChainGen(i int, block *core.BlockGen) { b3.Extra = []byte("foo") block.AddUncle(b3) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, data), signer, testBankKey) block.AddTx(tx) } } diff --git a/les/odr_test.go b/les/odr_test.go index 865f5d83e5..cf609be882 100644 --- a/les/odr_test.go +++ b/les/odr_test.go @@ -129,13 +129,13 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai from := statedb.GetOrNewStateObject(testBankAddress) from.SetBalance(math.MaxBig256) - msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data, false)} + msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)} context := core.NewEVMContext(msg, header, bc, nil) vmenv := vm.NewEVM(context, statedb, config, vm.Config{}) //vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{}) - gp := new(core.GasPool).AddGas(math.MaxBig256) + gp := new(core.GasPool).AddGas(math.MaxUint64) ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) res = append(res, ret...) } @@ -143,10 +143,10 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *params.Chai header := lc.GetHeaderByHash(bhash) state := light.NewState(ctx, header, lc.Odr()) state.SetBalance(testBankAddress, math.MaxBig256) - msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data, false)} + msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 100000, new(big.Int), data, false)} context := core.NewEVMContext(msg, header, lc, nil) vmenv := vm.NewEVM(context, state, config, vm.Config{}) - gp := new(core.GasPool).AddGas(math.MaxBig256) + gp := new(core.GasPool).AddGas(math.MaxUint64) ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) if state.Error() == nil { res = append(res, ret...) diff --git a/light/lightchain.go b/light/lightchain.go index c5c2dcf465..03c7c1f0d0 100644 --- a/light/lightchain.go +++ b/light/lightchain.go @@ -169,7 +169,7 @@ func (bc *LightChain) SetHead(head uint64) { } // GasLimit returns the gas limit of the current HEAD block. -func (self *LightChain) GasLimit() *big.Int { +func (self *LightChain) GasLimit() uint64 { self.mu.RLock() defer self.mu.RUnlock() diff --git a/light/odr_test.go b/light/odr_test.go index c0eb409f99..e3d07518a8 100644 --- a/light/odr_test.go +++ b/light/odr_test.go @@ -50,8 +50,6 @@ var ( testContractCode = common.Hex2Bytes("606060405260cc8060106000396000f360606040526000357c01000000000000000000000000000000000000000000000000000000009004806360cd2685146041578063c16431b914606b57603f565b005b6055600480803590602001909190505060a9565b6040518082815260200191505060405180910390f35b60886004808035906020019091908035906020019091905050608a565b005b80600060005083606481101560025790900160005b50819055505b5050565b6000600060005082606481101560025790900160005b5054905060c7565b91905056") testContractAddr common.Address - - bigTxGas = new(big.Int).SetUint64(params.TxGas) ) type testOdr struct { @@ -178,10 +176,10 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain // Perform read-only call. st.SetBalance(testBankAddress, math.MaxBig256) - msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data, false)} + msg := callmsg{types.NewMessage(testBankAddress, &testContractAddr, 0, new(big.Int), 1000000, new(big.Int), data, false)} context := core.NewEVMContext(msg, header, chain, nil) vmenv := vm.NewEVM(context, st, config, vm.Config{}) - gp := new(core.GasPool).AddGas(math.MaxBig256) + gp := new(core.GasPool).AddGas(math.MaxUint64) ret, _, _, _ := core.ApplyMessage(vmenv, msg, gp) res = append(res, ret...) if st.Error() != nil { @@ -196,17 +194,17 @@ func testChainGen(i int, block *core.BlockGen) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), signer, testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. // acc1Addr creates a test contract. - tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, testBankKey) + tx1, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, testBankKey) nonce := block.TxNonce(acc1Addr) - tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), bigTxGas, nil, nil), signer, acc1Key) + tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil), signer, acc1Key) nonce++ - tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode), signer, acc1Key) + tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), testContractCode), signer, acc1Key) testContractAddr = crypto.CreateAddress(acc1Addr, nonce) block.AddTx(tx1) block.AddTx(tx2) @@ -216,7 +214,7 @@ func testChainGen(i int, block *core.BlockGen) { block.SetCoinbase(acc2Addr) block.SetExtra([]byte("yeehaw")) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001") - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, data), signer, testBankKey) block.AddTx(tx) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). @@ -227,7 +225,7 @@ func testChainGen(i int, block *core.BlockGen) { b3.Extra = []byte("foo") block.AddUncle(b3) data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002") - tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data), signer, testBankKey) + tx, _ := types.SignTx(types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), 100000, nil, data), signer, testBankKey) block.AddTx(tx) } } diff --git a/light/txpool.go b/light/txpool.go index bd215b9928..ca41490bdc 100644 --- a/light/txpool.go +++ b/light/txpool.go @@ -358,7 +358,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error // Check the transaction doesn't exceed the current // block limit gas. header := pool.chain.GetHeaderByHash(pool.head) - if header.GasLimit.Cmp(tx.Gas()) < 0 { + if header.GasLimit < tx.Gas() { return core.ErrGasLimit } @@ -376,10 +376,13 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error } // Should supply enough intrinsic gas - if tx.Gas().Cmp(core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)) < 0 { + gas, err := core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead) + if err != nil { + return err + } + if tx.Gas() < gas { return core.ErrIntrinsicGas } - return currentState.Error() } diff --git a/light/txpool_test.go b/light/txpool_test.go index 2ef9e0cf56..b343f79b05 100644 --- a/light/txpool_test.go +++ b/light/txpool_test.go @@ -77,7 +77,7 @@ func txPoolTestChainGen(i int, block *core.BlockGen) { func TestTxPool(t *testing.T) { for i := range testTx { - testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), bigTxGas, nil, nil), types.HomesteadSigner{}, testBankKey) + testTx[i], _ = types.SignTx(types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil), types.HomesteadSigner{}, testBankKey) } var ( diff --git a/miner/worker.go b/miner/worker.go index c1f848e327..638f759bf5 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -413,7 +413,6 @@ func (self *worker) commitNewWork() { ParentHash: parent.Hash(), Number: num.Add(num, common.Big1), GasLimit: core.CalcGasLimit(parent), - GasUsed: new(big.Int), Extra: self.extra, Time: big.NewInt(tstamp), } @@ -588,7 +587,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, coinbase common.Address, gp *core.GasPool) (error, []*types.Log) { snap := env.state.Snapshot() - receipt, _, err := core.ApplyTransaction(env.config, bc, &coinbase, gp, env.state, env.header, tx, env.header.GasUsed, vm.Config{}) + receipt, _, err := core.ApplyTransaction(env.config, bc, &coinbase, gp, env.state, env.header, tx, &env.header.GasUsed, vm.Config{}) if err != nil { env.state.RevertToSnapshot(snap) return err, nil diff --git a/mobile/bind.go b/mobile/bind.go index 7b79bedafd..1e861d0bcb 100644 --- a/mobile/bind.go +++ b/mobile/bind.go @@ -77,7 +77,7 @@ func (opts *TransactOpts) GetFrom() *Address { return &Address{opts.opts.From func (opts *TransactOpts) GetNonce() int64 { return opts.opts.Nonce.Int64() } func (opts *TransactOpts) GetValue() *BigInt { return &BigInt{opts.opts.Value} } func (opts *TransactOpts) GetGasPrice() *BigInt { return &BigInt{opts.opts.GasPrice} } -func (opts *TransactOpts) GetGasLimit() int64 { return opts.opts.GasLimit.Int64() } +func (opts *TransactOpts) GetGasLimit() int64 { return int64(opts.opts.GasLimit) } // GetSigner cannot be reliably implemented without identity preservation (https://github.com/golang/go/issues/16876) // func (opts *TransactOpts) GetSigner() Signer { return &signer{opts.opts.Signer} } @@ -99,7 +99,7 @@ func (opts *TransactOpts) SetSigner(s Signer) { } func (opts *TransactOpts) SetValue(value *BigInt) { opts.opts.Value = value.bigint } func (opts *TransactOpts) SetGasPrice(price *BigInt) { opts.opts.GasPrice = price.bigint } -func (opts *TransactOpts) SetGasLimit(limit int64) { opts.opts.GasLimit = big.NewInt(limit) } +func (opts *TransactOpts) SetGasLimit(limit int64) { opts.opts.GasLimit = uint64(limit) } func (opts *TransactOpts) SetContext(context *Context) { opts.opts.Context = context.context } // BoundContract is the base wrapper object that reflects a contract on the diff --git a/mobile/ethclient.go b/mobile/ethclient.go index 758863b6d9..66399c6b56 100644 --- a/mobile/ethclient.go +++ b/mobile/ethclient.go @@ -298,9 +298,9 @@ func (ec *EthereumClient) SuggestGasPrice(ctx *Context) (price *BigInt, _ error) // the current pending state of the backend blockchain. There is no guarantee that this is // the true gas limit requirement as other transactions may be added or removed by miners, // but it should provide a basis for setting a reasonable default. -func (ec *EthereumClient) EstimateGas(ctx *Context, msg *CallMsg) (gas *BigInt, _ error) { +func (ec *EthereumClient) EstimateGas(ctx *Context, msg *CallMsg) (gas int64, _ error) { rawGas, err := ec.client.EstimateGas(ctx.context, msg.msg) - return &BigInt{rawGas}, err + return int64(rawGas), err } // SendTransaction injects a signed transaction into the pending pool for execution. diff --git a/mobile/ethereum.go b/mobile/ethereum.go index c9bb3013c2..0eb1d90552 100644 --- a/mobile/ethereum.go +++ b/mobile/ethereum.go @@ -20,7 +20,6 @@ package geth import ( "errors" - "math/big" ethereum "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/common" @@ -49,7 +48,7 @@ func NewCallMsg() *CallMsg { } func (msg *CallMsg) GetFrom() *Address { return &Address{msg.msg.From} } -func (msg *CallMsg) GetGas() int64 { return msg.msg.Gas.Int64() } +func (msg *CallMsg) GetGas() int64 { return int64(msg.msg.Gas) } func (msg *CallMsg) GetGasPrice() *BigInt { return &BigInt{msg.msg.GasPrice} } func (msg *CallMsg) GetValue() *BigInt { return &BigInt{msg.msg.Value} } func (msg *CallMsg) GetData() []byte { return msg.msg.Data } @@ -61,7 +60,7 @@ func (msg *CallMsg) GetTo() *Address { } func (msg *CallMsg) SetFrom(address *Address) { msg.msg.From = address.address } -func (msg *CallMsg) SetGas(gas int64) { msg.msg.Gas = big.NewInt(gas) } +func (msg *CallMsg) SetGas(gas int64) { msg.msg.Gas = uint64(gas) } func (msg *CallMsg) SetGasPrice(price *BigInt) { msg.msg.GasPrice = price.bigint } func (msg *CallMsg) SetValue(value *BigInt) { msg.msg.Value = value.bigint } func (msg *CallMsg) SetData(data []byte) { msg.msg.Data = common.CopyBytes(data) } diff --git a/mobile/types.go b/mobile/types.go index b7f8a3bc15..4790afceff 100644 --- a/mobile/types.go +++ b/mobile/types.go @@ -112,8 +112,8 @@ func (h *Header) GetReceiptHash() *Hash { return &Hash{h.header.ReceiptHash} } func (h *Header) GetBloom() *Bloom { return &Bloom{h.header.Bloom} } func (h *Header) GetDifficulty() *BigInt { return &BigInt{h.header.Difficulty} } func (h *Header) GetNumber() int64 { return h.header.Number.Int64() } -func (h *Header) GetGasLimit() int64 { return h.header.GasLimit.Int64() } -func (h *Header) GetGasUsed() int64 { return h.header.GasUsed.Int64() } +func (h *Header) GetGasLimit() int64 { return int64(h.header.GasLimit) } +func (h *Header) GetGasUsed() int64 { return int64(h.header.GasUsed) } func (h *Header) GetTime() int64 { return h.header.Time.Int64() } func (h *Header) GetExtra() []byte { return h.header.Extra } func (h *Header) GetMixDigest() *Hash { return &Hash{h.header.MixDigest} } @@ -189,8 +189,8 @@ func (b *Block) GetReceiptHash() *Hash { return &Hash{b.block.ReceiptHash()} } func (b *Block) GetBloom() *Bloom { return &Bloom{b.block.Bloom()} } func (b *Block) GetDifficulty() *BigInt { return &BigInt{b.block.Difficulty()} } func (b *Block) GetNumber() int64 { return b.block.Number().Int64() } -func (b *Block) GetGasLimit() int64 { return b.block.GasLimit().Int64() } -func (b *Block) GetGasUsed() int64 { return b.block.GasUsed().Int64() } +func (b *Block) GetGasLimit() int64 { return int64(b.block.GasLimit()) } +func (b *Block) GetGasUsed() int64 { return int64(b.block.GasUsed()) } func (b *Block) GetTime() int64 { return b.block.Time().Int64() } func (b *Block) GetExtra() []byte { return b.block.Extra() } func (b *Block) GetMixDigest() *Hash { return &Hash{b.block.MixDigest()} } @@ -212,8 +212,8 @@ type Transaction struct { } // NewTransaction creates a new transaction with the given properties. -func NewTransaction(nonce int64, to *Address, amount, gasLimit, gasPrice *BigInt, data []byte) *Transaction { - return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, gasLimit.bigint, gasPrice.bigint, common.CopyBytes(data))} +func NewTransaction(nonce int64, to *Address, amount *BigInt, gasLimit int64, gasPrice *BigInt, data []byte) *Transaction { + return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data))} } // NewTransactionFromRLP parses a transaction from an RLP data dump. @@ -256,7 +256,7 @@ func (tx *Transaction) String() string { } func (tx *Transaction) GetData() []byte { return tx.tx.Data() } -func (tx *Transaction) GetGas() int64 { return tx.tx.Gas().Int64() } +func (tx *Transaction) GetGas() int64 { return int64(tx.tx.Gas()) } func (tx *Transaction) GetGasPrice() *BigInt { return &BigInt{tx.tx.GasPrice()} } func (tx *Transaction) GetValue() *BigInt { return &BigInt{tx.tx.Value()} } func (tx *Transaction) GetNonce() int64 { return int64(tx.tx.Nonce()) } @@ -353,10 +353,10 @@ func (r *Receipt) String() string { return r.receipt.String() } -func (r *Receipt) GetPostState() []byte { return r.receipt.PostState } -func (r *Receipt) GetCumulativeGasUsed() *BigInt { return &BigInt{r.receipt.CumulativeGasUsed} } -func (r *Receipt) GetBloom() *Bloom { return &Bloom{r.receipt.Bloom} } -func (r *Receipt) GetLogs() *Logs { return &Logs{r.receipt.Logs} } -func (r *Receipt) GetTxHash() *Hash { return &Hash{r.receipt.TxHash} } -func (r *Receipt) GetContractAddress() *Address { return &Address{r.receipt.ContractAddress} } -func (r *Receipt) GetGasUsed() *BigInt { return &BigInt{r.receipt.GasUsed} } +func (r *Receipt) GetPostState() []byte { return r.receipt.PostState } +func (r *Receipt) GetCumulativeGasUsed() int64 { return int64(r.receipt.CumulativeGasUsed) } +func (r *Receipt) GetBloom() *Bloom { return &Bloom{r.receipt.Bloom} } +func (r *Receipt) GetLogs() *Logs { return &Logs{r.receipt.Logs} } +func (r *Receipt) GetTxHash() *Hash { return &Hash{r.receipt.TxHash} } +func (r *Receipt) GetContractAddress() *Address { return &Address{r.receipt.ContractAddress} } +func (r *Receipt) GetGasUsed() int64 { return int64(r.receipt.GasUsed) } diff --git a/params/protocol_params.go b/params/protocol_params.go index c56faf56f8..5a0b14d61a 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -18,7 +18,15 @@ package params import "math/big" +var ( + TargetGasLimit uint64 = GenesisGasLimit // The artificial target +) + const ( + GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations. + MinGasLimit uint64 = 5000 // Minimum the gas limit may ever be. + GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block. + MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis. ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction. SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added. @@ -72,12 +80,8 @@ const ( ) var ( - GasLimitBoundDivisor = big.NewInt(1024) // The bound divisor of the gas limit, used in update calculations. - MinGasLimit = big.NewInt(5000) // Minimum the gas limit may ever be. - GenesisGasLimit = big.NewInt(4712388) // Gas limit of the Genesis block. - TargetGasLimit = new(big.Int).Set(GenesisGasLimit) // The artificial target - DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations. - GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block. - MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be. - DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not. + DifficultyBoundDivisor = big.NewInt(2048) // The bound divisor of the difficulty, used in the update calculations. + GenesisDifficulty = big.NewInt(131072) // Difficulty of the Genesis block. + MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be. + DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not. ) diff --git a/tests/block_test_util.go b/tests/block_test_util.go index a789e6d887..e2d1a0b43b 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -77,8 +77,8 @@ type btHeader struct { UncleHash common.Hash ExtraData []byte Difficulty *big.Int - GasLimit *big.Int - GasUsed *big.Int + GasLimit uint64 + GasUsed uint64 Timestamp *big.Int } @@ -86,8 +86,8 @@ type btHeaderMarshaling struct { ExtraData hexutil.Bytes Number *math.HexOrDecimal256 Difficulty *math.HexOrDecimal256 - GasLimit *math.HexOrDecimal256 - GasUsed *math.HexOrDecimal256 + GasLimit *math.HexOrDecimal64 + GasUsed *math.HexOrDecimal64 Timestamp *math.HexOrDecimal256 } @@ -141,8 +141,8 @@ func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { Timestamp: t.json.Genesis.Timestamp.Uint64(), ParentHash: t.json.Genesis.ParentHash, ExtraData: t.json.Genesis.ExtraData, - GasLimit: t.json.Genesis.GasLimit.Uint64(), - GasUsed: t.json.Genesis.GasUsed.Uint64(), + GasLimit: t.json.Genesis.GasLimit, + GasUsed: t.json.Genesis.GasUsed, Difficulty: t.json.Genesis.Difficulty, Mixhash: t.json.Genesis.MixHash, Coinbase: t.json.Genesis.Coinbase, @@ -234,11 +234,11 @@ func validateHeader(h *btHeader, h2 *types.Header) error { if h.Difficulty.Cmp(h2.Difficulty) != 0 { return fmt.Errorf("Difficulty: want: %v have: %v", h.Difficulty, h2.Difficulty) } - if h.GasLimit.Cmp(h2.GasLimit) != 0 { - return fmt.Errorf("GasLimit: want: %v have: %v", h.GasLimit, h2.GasLimit) + if h.GasLimit != h2.GasLimit { + return fmt.Errorf("GasLimit: want: %d have: %d", h.GasLimit, h2.GasLimit) } - if h.GasUsed.Cmp(h2.GasUsed) != 0 { - return fmt.Errorf("GasUsed: want: %v have: %v", h.GasUsed, h2.GasUsed) + if h.GasUsed != h2.GasUsed { + return fmt.Errorf("GasUsed: want: %d have: %d", h.GasUsed, h2.GasUsed) } if h.Timestamp.Cmp(h2.Time) != 0 { return fmt.Errorf("Timestamp: want: %v have: %v", h.Timestamp, h2.Time) diff --git a/tests/gen_btheader.go b/tests/gen_btheader.go index 5d65e0dbce..1be659ecb5 100644 --- a/tests/gen_btheader.go +++ b/tests/gen_btheader.go @@ -29,8 +29,8 @@ func (b btHeader) MarshalJSON() ([]byte, error) { UncleHash common.Hash ExtraData hexutil.Bytes Difficulty *math.HexOrDecimal256 - GasLimit *math.HexOrDecimal256 - GasUsed *math.HexOrDecimal256 + GasLimit math.HexOrDecimal64 + GasUsed math.HexOrDecimal64 Timestamp *math.HexOrDecimal256 } var enc btHeader @@ -47,8 +47,8 @@ func (b btHeader) MarshalJSON() ([]byte, error) { enc.UncleHash = b.UncleHash enc.ExtraData = b.ExtraData enc.Difficulty = (*math.HexOrDecimal256)(b.Difficulty) - enc.GasLimit = (*math.HexOrDecimal256)(b.GasLimit) - enc.GasUsed = (*math.HexOrDecimal256)(b.GasUsed) + enc.GasLimit = (math.HexOrDecimal64)(b.GasLimit) + enc.GasUsed = (math.HexOrDecimal64)(b.GasUsed) enc.Timestamp = (*math.HexOrDecimal256)(b.Timestamp) return json.Marshal(&enc) } @@ -68,8 +68,8 @@ func (b *btHeader) UnmarshalJSON(input []byte) error { UncleHash *common.Hash ExtraData hexutil.Bytes Difficulty *math.HexOrDecimal256 - GasLimit *math.HexOrDecimal256 - GasUsed *math.HexOrDecimal256 + GasLimit *math.HexOrDecimal64 + GasUsed *math.HexOrDecimal64 Timestamp *math.HexOrDecimal256 } var dec btHeader @@ -116,10 +116,10 @@ func (b *btHeader) UnmarshalJSON(input []byte) error { b.Difficulty = (*big.Int)(dec.Difficulty) } if dec.GasLimit != nil { - b.GasLimit = (*big.Int)(dec.GasLimit) + b.GasLimit = uint64(*dec.GasLimit) } if dec.GasUsed != nil { - b.GasUsed = (*big.Int)(dec.GasUsed) + b.GasUsed = uint64(*dec.GasUsed) } if dec.Timestamp != nil { b.Timestamp = (*big.Int)(dec.Timestamp) diff --git a/tests/gen_stenv.go b/tests/gen_stenv.go index c780524bc3..1d4baf2fd7 100644 --- a/tests/gen_stenv.go +++ b/tests/gen_stenv.go @@ -17,14 +17,14 @@ func (s stEnv) MarshalJSON() ([]byte, error) { type stEnv struct { Coinbase common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"` Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"` - GasLimit *math.HexOrDecimal256 `json:"currentGasLimit" gencodec:"required"` + GasLimit math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"` Number math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"` Timestamp math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"` } var enc stEnv enc.Coinbase = common.UnprefixedAddress(s.Coinbase) enc.Difficulty = (*math.HexOrDecimal256)(s.Difficulty) - enc.GasLimit = (*math.HexOrDecimal256)(s.GasLimit) + enc.GasLimit = math.HexOrDecimal64(s.GasLimit) enc.Number = math.HexOrDecimal64(s.Number) enc.Timestamp = math.HexOrDecimal64(s.Timestamp) return json.Marshal(&enc) @@ -34,7 +34,7 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { type stEnv struct { Coinbase *common.UnprefixedAddress `json:"currentCoinbase" gencodec:"required"` Difficulty *math.HexOrDecimal256 `json:"currentDifficulty" gencodec:"required"` - GasLimit *math.HexOrDecimal256 `json:"currentGasLimit" gencodec:"required"` + GasLimit *math.HexOrDecimal64 `json:"currentGasLimit" gencodec:"required"` Number *math.HexOrDecimal64 `json:"currentNumber" gencodec:"required"` Timestamp *math.HexOrDecimal64 `json:"currentTimestamp" gencodec:"required"` } @@ -53,7 +53,7 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { if dec.GasLimit == nil { return errors.New("missing required field 'currentGasLimit' for stEnv") } - s.GasLimit = (*big.Int)(dec.GasLimit) + s.GasLimit = uint64(*dec.GasLimit) if dec.Number == nil { return errors.New("missing required field 'currentNumber' for stEnv") } diff --git a/tests/gen_tttransaction.go b/tests/gen_tttransaction.go index b6759be912..840bdfdd81 100644 --- a/tests/gen_tttransaction.go +++ b/tests/gen_tttransaction.go @@ -17,7 +17,7 @@ var _ = (*ttTransactionMarshaling)(nil) func (t ttTransaction) MarshalJSON() ([]byte, error) { type ttTransaction struct { Data hexutil.Bytes `gencodec:"required"` - GasLimit *math.HexOrDecimal256 `gencodec:"required"` + GasLimit math.HexOrDecimal64 `gencodec:"required"` GasPrice *math.HexOrDecimal256 `gencodec:"required"` Nonce math.HexOrDecimal64 `gencodec:"required"` Value *math.HexOrDecimal256 `gencodec:"required"` @@ -28,7 +28,7 @@ func (t ttTransaction) MarshalJSON() ([]byte, error) { } var enc ttTransaction enc.Data = t.Data - enc.GasLimit = (*math.HexOrDecimal256)(t.GasLimit) + enc.GasLimit = (math.HexOrDecimal64)(t.GasLimit) enc.GasPrice = (*math.HexOrDecimal256)(t.GasPrice) enc.Nonce = math.HexOrDecimal64(t.Nonce) enc.Value = (*math.HexOrDecimal256)(t.Value) @@ -42,7 +42,7 @@ func (t ttTransaction) MarshalJSON() ([]byte, error) { func (t *ttTransaction) UnmarshalJSON(input []byte) error { type ttTransaction struct { Data hexutil.Bytes `gencodec:"required"` - GasLimit *math.HexOrDecimal256 `gencodec:"required"` + GasLimit *math.HexOrDecimal64 `gencodec:"required"` GasPrice *math.HexOrDecimal256 `gencodec:"required"` Nonce *math.HexOrDecimal64 `gencodec:"required"` Value *math.HexOrDecimal256 `gencodec:"required"` @@ -62,7 +62,7 @@ func (t *ttTransaction) UnmarshalJSON(input []byte) error { if dec.GasLimit == nil { return errors.New("missing required field 'gasLimit' for ttTransaction") } - t.GasLimit = (*big.Int)(dec.GasLimit) + t.GasLimit = uint64(*dec.GasLimit) if dec.GasPrice == nil { return errors.New("missing required field 'gasPrice' for ttTransaction") } diff --git a/tests/state_test_util.go b/tests/state_test_util.go index 1f4fb2bd5e..78c05b0245 100644 --- a/tests/state_test_util.go +++ b/tests/state_test_util.go @@ -76,7 +76,7 @@ type stPostState struct { type stEnv struct { Coinbase common.Address `json:"currentCoinbase" gencodec:"required"` Difficulty *big.Int `json:"currentDifficulty" gencodec:"required"` - GasLimit *big.Int `json:"currentGasLimit" gencodec:"required"` + GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` Number uint64 `json:"currentNumber" gencodec:"required"` Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` } @@ -84,7 +84,7 @@ type stEnv struct { type stEnvMarshaling struct { Coinbase common.UnprefixedAddress Difficulty *math.HexOrDecimal256 - GasLimit *math.HexOrDecimal256 + GasLimit math.HexOrDecimal64 Number math.HexOrDecimal64 Timestamp math.HexOrDecimal64 } @@ -180,7 +180,7 @@ func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis { Config: config, Coinbase: t.json.Env.Coinbase, Difficulty: t.json.Env.Difficulty, - GasLimit: t.json.Env.GasLimit.Uint64(), + GasLimit: t.json.Env.GasLimit, Number: t.json.Env.Number, Timestamp: t.json.Env.Timestamp, Alloc: t.json.Pre, @@ -233,7 +233,7 @@ func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) { return nil, fmt.Errorf("invalid tx data %q", dataHex) } - msg := types.NewMessage(from, to, tx.Nonce, value, new(big.Int).SetUint64(gasLimit), tx.GasPrice, data, true) + msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, true) return msg, nil } diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index 472b3d6f24..2028d2a278 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -46,7 +46,7 @@ type ttJSON struct { type ttTransaction struct { Data []byte `gencodec:"required"` - GasLimit *big.Int `gencodec:"required"` + GasLimit uint64 `gencodec:"required"` GasPrice *big.Int `gencodec:"required"` Nonce uint64 `gencodec:"required"` Value *big.Int `gencodec:"required"` @@ -58,7 +58,7 @@ type ttTransaction struct { type ttTransactionMarshaling struct { Data hexutil.Bytes - GasLimit *math.HexOrDecimal256 + GasLimit math.HexOrDecimal64 GasPrice *math.HexOrDecimal256 Nonce math.HexOrDecimal64 Value *math.HexOrDecimal256 @@ -100,8 +100,8 @@ func (tt *ttTransaction) verify(signer types.Signer, tx *types.Transaction) erro if !bytes.Equal(tx.Data(), tt.Data) { return fmt.Errorf("Tx input data mismatch: got %x want %x", tx.Data(), tt.Data) } - if tx.Gas().Cmp(tt.GasLimit) != 0 { - return fmt.Errorf("GasLimit mismatch: got %v, want %v", tx.Gas(), tt.GasLimit) + if tx.Gas() != tt.GasLimit { + return fmt.Errorf("GasLimit mismatch: got %d, want %d", tx.Gas(), tt.GasLimit) } if tx.GasPrice().Cmp(tt.GasPrice) != 0 { return fmt.Errorf("GasPrice mismatch: got %v, want %v", tx.GasPrice(), tt.GasPrice) From b47285f1cf0cb475f29322ceb9fac4d7e1cfb11f Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Wed, 3 Jan 2018 15:50:33 +0100 Subject: [PATCH 22/25] vendor: update github.com/rjeczalik/notify (#15801) --- vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go | 7 +++++-- vendor/vendor.json | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go b/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go index fb70de6af0..2248a1b129 100644 --- a/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go +++ b/vendor/github.com/rjeczalik/notify/watcher_fsevents_cgo.go @@ -26,9 +26,9 @@ import "C" import ( "errors" "os" + "runtime" "sync" "sync/atomic" - "time" "unsafe" ) @@ -63,6 +63,10 @@ var ( func init() { wg.Add(1) go func() { + // There is exactly one run loop per thread. Lock this goroutine to its + // thread to ensure that it's not rescheduled on a different thread while + // setting up the run loop. + runtime.LockOSThread() runloop = C.CFRunLoopGetCurrent() C.CFRunLoopAddSource(runloop, source, C.kCFRunLoopDefaultMode) C.CFRunLoopRun() @@ -73,7 +77,6 @@ func init() { //export gosource func gosource(unsafe.Pointer) { - time.Sleep(time.Second) wg.Done() } diff --git a/vendor/vendor.json b/vendor/vendor.json index 17844bd8dd..979e8b34b6 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -286,10 +286,10 @@ "revisionTime": "2016-11-28T21:05:44Z" }, { - "checksumSHA1": "tnQdt7bxmueZFl0EPrW9YrWiqGg=", + "checksumSHA1": "1ESHllhZOIBg7MnlGHUdhz047bI=", "path": "github.com/rjeczalik/notify", - "revision": "e1801ee34d54c4bf45126ef51fe9750b4e42bee8", - "revisionTime": "2017-12-10T15:45:11Z" + "revision": "27b537f07230b3f917421af6dcf044038dbe57e2", + "revisionTime": "2018-01-03T13:19:05Z" }, { "checksumSHA1": "5uqO4ITTDMklKi3uNaE/D9LQ5nM=", From 7a59a9380e9f12729bb094de4151c3d135bdadf9 Mon Sep 17 00:00:00 2001 From: Evangelos Pappas Date: Wed, 3 Jan 2018 16:18:53 +0000 Subject: [PATCH 23/25] cmd/utils: handle git commit a bit safer for user specified strings (#15790) * cmd/utils/flags.go: Applying a String len guard for the gitCommit param of the NewApp() * cmd/utils: remove redundant clause in if condition --- cmd/utils/flags.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 734cf6f369..edf3dc2c21 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -96,7 +96,7 @@ func NewApp(gitCommit, usage string) *cli.App { //app.Authors = nil app.Email = "" app.Version = params.Version - if gitCommit != "" { + if len(gitCommit) >= 8 { app.Version += "-" + gitCommit[:8] } app.Usage = usage From ae71da1b03c6eee82b714ef81b4fc59bcc130bb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Thu, 4 Jan 2018 13:58:11 +0200 Subject: [PATCH 24/25] eth: fix tracer panic when running without configs + reexec (#15799) --- eth/api_tracer.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/eth/api_tracer.go b/eth/api_tracer.go index 0d0e2a73c3..d49f077aed 100644 --- a/eth/api_tracer.go +++ b/eth/api_tracer.go @@ -204,7 +204,7 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl if err != nil { // If the starting state is missing, allow some number of blocks to be reexecuted reexec := defaultTraceReexec - if config.Reexec != nil { + if config != nil && config.Reexec != nil { reexec = *config.Reexec } // Find the most recent block that has the state available @@ -465,7 +465,7 @@ func (api *PrivateDebugAPI) traceBlock(ctx context.Context, block *types.Block, return nil, fmt.Errorf("parent %x not found", block.ParentHash()) } reexec := defaultTraceReexec - if config.Reexec != nil { + if config != nil && config.Reexec != nil { reexec = *config.Reexec } statedb, err := api.computeStateDB(parent, reexec) @@ -619,7 +619,7 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, hash common.Ha return nil, fmt.Errorf("transaction %x not found", hash) } reexec := defaultTraceReexec - if config.Reexec != nil { + if config != nil && config.Reexec != nil { reexec = *config.Reexec } msg, vmctx, statedb, err := api.computeTxEnv(blockHash, int(index), reexec) From 1c2378b926b4ae96ae42a4e802058a2fcd42c87b Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Thu, 4 Jan 2018 13:18:30 +0100 Subject: [PATCH 25/25] tests: update to upstream commit 2bb0c3da3b (#15806) Also raise traceLimit once again and print the VM error and output on failure. --- core/vm/logger.go | 20 ++++++++++++-------- tests/state_test.go | 13 +++++-------- tests/testdata | 2 +- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/core/vm/logger.go b/core/vm/logger.go index 1a6e43ee30..1191814330 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -100,6 +100,8 @@ type StructLogger struct { logs []StructLog changedValues map[common.Address]Storage + output []byte + err error } // NewStructLogger returns a new logger @@ -172,17 +174,19 @@ func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost ui } func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) error { - fmt.Printf("0x%x", output) - if err != nil { - fmt.Printf(" error: %v\n", err) - } + l.output = output + l.err = err return nil } -// StructLogs returns a list of captured log entries -func (l *StructLogger) StructLogs() []StructLog { - return l.logs -} +// StructLogs returns the captured log entries. +func (l *StructLogger) StructLogs() []StructLog { return l.logs } + +// Error returns the VM error captured by the trace. +func (l *StructLogger) Error() error { return l.err } + +// Output returns the VM return value captured by the trace. +func (l *StructLogger) Output() []byte { return l.output } // WriteTrace writes a formatted trace to the given writer func WriteTrace(writer io.Writer, logs []StructLog) { diff --git a/tests/state_test.go b/tests/state_test.go index 5a67b290db..100c776c1a 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -39,16 +39,12 @@ func TestState(t *testing.T) { st.fails(`^stRevertTest/RevertPrefoundEmptyOOG\.json/EIP158`, "bug in test") st.fails(`^stRevertTest/RevertPrecompiledTouch\.json/Byzantium`, "bug in test") st.fails(`^stRevertTest/RevertPrefoundEmptyOOG\.json/Byzantium`, "bug in test") - st.fails(`^stRandom/randomStatetest645\.json/EIP150/.*`, "known bug #15119") - st.fails(`^stRandom/randomStatetest645\.json/Frontier/.*`, "known bug #15119") - st.fails(`^stRandom/randomStatetest645\.json/Homestead/.*`, "known bug #15119") - st.fails(`^stRandom/randomStatetest644\.json/EIP150/.*`, "known bug #15119") - st.fails(`^stRandom/randomStatetest644\.json/Frontier/.*`, "known bug #15119") - st.fails(`^stRandom/randomStatetest644\.json/Homestead/.*`, "known bug #15119") + st.fails(`^stRandom2/randomStatetest64[45]\.json/(EIP150|Frontier|Homestead)/.*`, "known bug #15119") st.fails(`^stCreateTest/TransactionCollisionToEmpty\.json/EIP158/2`, "known bug ") st.fails(`^stCreateTest/TransactionCollisionToEmpty\.json/EIP158/3`, "known bug ") st.fails(`^stCreateTest/TransactionCollisionToEmpty\.json/Byzantium/2`, "known bug ") st.fails(`^stCreateTest/TransactionCollisionToEmpty\.json/Byzantium/3`, "known bug ") + st.walk(t, stateTestDir, func(t *testing.T, name string, test *StateTest) { for _, subtest := range test.Subtests() { subtest := subtest @@ -68,8 +64,7 @@ func TestState(t *testing.T) { } // Transactions with gasLimit above this value will not get a VM trace on failure. -//const traceErrorLimit = 400000 -const traceErrorLimit = 0 +const traceErrorLimit = 400000 func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) { err := test(vm.Config{}) @@ -93,4 +88,6 @@ func withTrace(t *testing.T, gasLimit uint64, test func(vm.Config) error) { } else { t.Log("EVM operation log:\n" + buf.String()) } + t.Logf("EVM output: 0x%x", tracer.Output()) + t.Logf("EVM error: %v", tracer.Error()) } diff --git a/tests/testdata b/tests/testdata index 37f555fbc0..2bb0c3da3b 160000 --- a/tests/testdata +++ b/tests/testdata @@ -1 +1 @@ -Subproject commit 37f555fbc091fbf761aa6f02227132fb31f0681c +Subproject commit 2bb0c3da3bbb15c528bcef2a7e5ac4bd73f81f87