diff --git a/txpool/fetch.go b/txpool/fetch.go index 0bae0e981..5d30e6448 100644 --- a/txpool/fetch.go +++ b/txpool/fetch.go @@ -190,7 +190,6 @@ func (f *Fetch) handleInboundMessage(req *sentry.InboundMessage, sentryClient se } var hashbuf [32]byte var unknownHashes Hashes - var unknownCount int for i := 0; i < hashCount; i++ { _, pos, err = ParseHash(req.Data, pos, hashbuf[:0]) if err != nil { @@ -204,12 +203,12 @@ func (f *Fetch) handleInboundMessage(req *sentry.InboundMessage, sentryClient se var encodedRequest []byte var messageId sentry.MessageId if req.Id == sentry.MessageId_NEW_POOLED_TRANSACTION_HASHES_66 { - if encodedRequest, err = EncodeGetPooledTransactions66(unknownHashes, unknownCount, uint64(1), nil); err != nil { + if encodedRequest, err = EncodeGetPooledTransactions66(unknownHashes, uint64(1), nil); err != nil { return err } messageId = sentry.MessageId_GET_POOLED_TRANSACTIONS_66 } else { - if encodedRequest, err = EncodeHashes(unknownHashes, unknownCount, nil); err != nil { + if encodedRequest, err = EncodeHashes(unknownHashes, nil); err != nil { return err } messageId = sentry.MessageId_GET_POOLED_TRANSACTIONS_65 diff --git a/txpool/packets.go b/txpool/packets.go index 0c7c99136..e29d6e5bc 100644 --- a/txpool/packets.go +++ b/txpool/packets.go @@ -81,42 +81,120 @@ func ParseHashesCount(payload []byte, pos int) (int, int, error) { // It appends encoding to the given given slice (encodeBuf), reusing the space // there is there is enough capacity. // The first returned value is the slice where encodinfg -func EncodeHashes(hashes Hashes, count int, encodeBuf []byte) ([]byte, error) { - dataLen := count * 33 - var beLen int - if dataLen >= 56 { - beLen = (bits.Len64(uint64(dataLen)) + 7) / 8 - } - prefixLen := 1 + beLen +func EncodeHashes(hashes Hashes, encodeBuf []byte) ([]byte, error) { + dataLen := len(hashes) / 32 * 33 + prefixLen := rlpListPrefixLen(dataLen) var encoding []byte - if total := len(encodeBuf) + dataLen + prefixLen; cap(encodeBuf) >= total { - encoding = encodeBuf[:dataLen+prefixLen] // Reuse the space in pkbuf, is it has enough capacity + if total := dataLen + prefixLen; cap(encodeBuf) >= total { + encoding = encodeBuf[:total] // Reuse the space in pkbuf, is it has enough capacity } else { encoding = make([]byte, total) copy(encoding, encodeBuf) } - if dataLen < 56 { - encoding[0] = 192 + byte(dataLen) - } else { - encoding[0] = 247 + byte(beLen) - binary.BigEndian.PutUint64(encoding[1:], uint64(beLen)) - copy(encoding[1:], encoding[9-beLen:9]) - } - hashP := 0 + rlpListPrefix(dataLen, encoding) encP := prefixLen - for i := 0; i < count; i++ { - encoding[encP] = 128 + 32 - copy(encoding[encP+1:encP+33], hashes[hashP:hashP+32]) + for i := 0; i < len(hashes); i += 32 { + rlpEncodeString(hashes[i:i+32], encoding[encP:]) encP += 33 - hashP += 32 } return encoding, nil } +func rlpListPrefixLen(dataLen int) int { + if dataLen >= 56 { + return 1 + (bits.Len64(uint64(dataLen))+7)/8 + } + return 1 +} +func rlpListPrefix(dataLen int, to []byte) { + if dataLen >= 56 { + _ = to[9] + beLen := (bits.Len64(uint64(dataLen)) + 7) / 8 + binary.BigEndian.PutUint64(to[1:], uint64(dataLen)) + to[8-beLen] = 247 + byte(beLen) + copy(to, to[8-beLen:9]) + return + } + to[0] = 192 + byte(dataLen) +} +func rlpU64Len(i uint64) int { + if i > 128 { + return 1 + (bits.Len64(i)+7)/8 + } + return 1 +} + +func rlpU64(i uint64, to []byte) { + /* + if requestId == 0 || requestId > 128 { + encoding[pos] = 128 + byte(requestIdLen) + } else { + encoding[pos] = byte(requestId) + } + */ + + if i > 128 { + l := (bits.Len64(i) + 7) / 8 + to[0] = 128 + byte(l) + binary.BigEndian.PutUint64(to[1:], i) + copy(to[1:], to[1+8-l:1+8]) + return + } + if i == 0 { + to[0] = 128 + return + } + to[0] = byte(i) + return + + //if i == 0 { + // w.str = append(w.str, 0x80) + //} else if i < 128 { + //w.str = append(w.str, byte(i)) + //} else { + // s := putint(w.sizebuf[1:], i) + // w.sizebuf[0] = 0x80 + byte(s) + // w.str = append(w.str, w.sizebuf[:s+1]...) + //} + +} + +func rlpEncodeString(s []byte, to []byte) { + switch { + case len(s) > 56: + beLen := (bits.Len(uint(len(s))) + 7) / 8 + binary.BigEndian.PutUint64(to[1:], uint64(len(s))) + _ = to[beLen+len(s)] + + to[8-beLen] = byte(beLen) + 183 + copy(to, to[8-beLen:9]) + copy(to[1+beLen:], s) + case len(s) == 0: + to[0] = 128 + case len(s) == 1: + _ = to[1] + if s[0] >= 128 { + to[0] = 129 + } + copy(to[1:], s) + default: // 1= 56 { hashesBeLen = (bits.Len64(uint64(hashesLen)) + 7) / 8 @@ -125,58 +203,39 @@ func EncodeGetPooledTransactions66(hashes []byte, count int, requestId uint64, e if requestId == 0 || requestId >= 128 { dataLen++ } - var dataBeLen int - if dataLen >= 56 { - dataBeLen = (bits.Len64(uint64(dataLen)) + 7) / 8 - } - prefixLen := 1 + dataBeLen + prefixLen := rlpListPrefixLen(dataLen) var encoding []byte - if total := len(encodeBuf) + dataLen + prefixLen; cap(encodeBuf) >= total { + if total := dataLen + prefixLen; cap(encodeBuf) >= total { encoding = encodeBuf[:dataLen+prefixLen] // Reuse the space in pkbuf, is it has enough capacity } else { encoding = make([]byte, total) copy(encoding, encodeBuf) } - pos := 0 // Length prefix for the entire structure - if dataLen < 56 { - encoding[pos] = 192 + byte(dataLen) - } else { - encoding[pos] = 247 + byte(dataBeLen) - binary.BigEndian.PutUint64(encoding[pos+1:], uint64(dataBeLen)) - copy(encoding[pos+1:], encoding[pos+9-dataBeLen:pos+9]) - } - pos += prefixLen + rlpListPrefix(dataLen, encoding) + pos := prefixLen // encode requestId - if requestId == 0 || requestId > 128 { - encoding[pos] = 128 + byte(requestIdLen) - } else { - encoding[pos] = byte(requestId) - } - pos++ + rlpU64(requestId, encoding[pos:]) + //if requestId == 0 || requestId > 128 { + // encoding[pos] = 128 + byte(requestIdLen) + //} else { + // encoding[pos] = byte(requestId) + //} + //pos++ if requestId > 128 { - binary.BigEndian.PutUint64(encoding[pos:], requestId) - copy(encoding[pos:], encoding[pos+8-requestIdLen:pos+8]) - pos += requestIdLen + //binary.BigEndian.PutUint64(encoding[pos:], requestId) + //copy(encoding[pos:], encoding[pos+8-requestIdLen:pos+8]) + //pos += requestIdLen } + fmt.Printf("aa: %d,%d,%d\n", requestId, rlpU64Len(requestId), requestIdLen) + pos += rlpU64Len(requestId) // Encode length prefix for hashes - if hashesLen < 56 { - encoding[pos] = 192 + byte(hashesLen) - pos++ - } else { - encoding[pos] = 247 + byte(hashesBeLen) - pos++ - binary.BigEndian.PutUint64(encoding[pos:], uint64(hashesBeLen)) - copy(encoding[pos:], encoding[pos+8-hashesBeLen:pos+8]) - pos += hashesBeLen - } - hashP := 0 - for i := 0; i < count; i++ { - encoding[pos] = 128 + 32 - pos++ - copy(encoding[pos:pos+32], hashes[hashP:hashP+32]) - pos += 32 - hashP += 32 + rlpListPrefix(hashesLen, encoding[pos:]) + pos += rlpListPrefixLen(hashesLen) + + for i := 0; i < len(hashes); i += 32 { + rlpEncodeHash(hashes[i:i+32], encoding[pos:pos+33]) + pos += 33 } return encoding, nil } diff --git a/txpool/packets_test.go b/txpool/packets_test.go index 83d4aa7fa..a42b5087f 100644 --- a/txpool/packets_test.go +++ b/txpool/packets_test.go @@ -72,6 +72,8 @@ var hashEncodeTests = []struct { }{ {payloadStr: "e1a0595e27a835cd79729ff1eeacec3120eeb6ed1464a04ec727aaca734ead961328", hashesStr: "595e27a835cd79729ff1eeacec3120eeb6ed1464a04ec727aaca734ead961328", hashCount: 1, expectedErr: false}, + {hashesStr: fmt.Sprintf("%x", toHashes([32]byte{1}, [32]byte{2}, [32]byte{3})), + payloadStr: "f863a00100000000000000000000000000000000000000000000000000000000000000a00200000000000000000000000000000000000000000000000000000000000000a00300000000000000000000000000000000000000000000000000000000000000", hashCount: 3, expectedErr: false}, } func TestEncodeHash(t *testing.T) { @@ -87,7 +89,7 @@ func TestEncodeHash(t *testing.T) { if hashes, err = hex.DecodeString(tt.hashesStr); err != nil { t.Fatal(err) } - if encodeBuf, err = EncodeHashes(hashes, tt.hashCount, encodeBuf); err != nil { + if encodeBuf, err = EncodeHashes(hashes, encodeBuf); err != nil { if !tt.expectedErr { t.Fatal(err) } @@ -126,7 +128,7 @@ func TestEncodeGPT66(t *testing.T) { if hashes, err = hex.DecodeString(tt.hashesStr); err != nil { t.Fatal(err) } - if encodeBuf, err = EncodeGetPooledTransactions66(hashes, tt.hashCount, tt.requestId, encodeBuf); err != nil { + if encodeBuf, err = EncodeGetPooledTransactions66(hashes, tt.requestId, encodeBuf); err != nil { if !tt.expectedErr { t.Fatal(err) } @@ -139,3 +141,21 @@ func TestEncodeGPT66(t *testing.T) { }) } } + +func BenchmarkEncHashes(b *testing.B) { + h := make(Hashes, 32*40) + buf := make([]byte, 39*40) + for i := 0; i < b.N; i++ { + buf = buf[:0] + EncodeHashes(h, buf) + } +} + +func BenchmarkEncHashes2(b *testing.B) { + h := make(Hashes, 32*40) + buf := make([]byte, 39*40) + for i := 0; i < b.N; i++ { + buf = buf[:0] + EncodeHashes(h, buf) + } +} diff --git a/txpool/send.go b/txpool/send.go index 644dd01a4..d233ae21f 100644 --- a/txpool/send.go +++ b/txpool/send.go @@ -85,7 +85,7 @@ func (f *Send) BroadcastLocalPooledTxs(txs Hashes) (sentToPeers int) { txs = txs[:0] } - data, err := EncodeHashes(pending, len(pending)/32, nil) + data, err := EncodeHashes(pending, nil) if err != nil { f.logger.Warnf("encode hashes: %s", err) return @@ -145,7 +145,7 @@ func (f *Send) BroadcastRemotePooledTxs(txs Hashes) { txs = txs[:0] } - data, err := EncodeHashes(pending, len(pending)/32, nil) + data, err := EncodeHashes(pending, nil) if err != nil { f.logger.Warnf("encode hashes: %s", err) return @@ -207,7 +207,7 @@ func (f *Send) PropagatePooledTxsToPeersList(peers []PeerID, txs []byte) { txs = txs[:0] } - data, err := EncodeHashes(pending, len(pending)/32, nil) + data, err := EncodeHashes(pending, nil) if err != nil { f.logger.Warnf("encode hashes: %s", err) return