Skip to content

Commit 8c2439a

Browse files
authored
[Witness] Minor optimization to witnessing request (#927)
I noticed a deep lint warning about the string appending, and then decided to modernize it and benchmark it. While I was there, I did it properly to pre-allocate a byte array for the b64 encoding. It's 5x faster and and uses a lot fewer memory allocations now. ``` // New BenchmarkBuildRequestBody-24 533068 2524 ns/op 2082 B/op 7 allocs/op // Old BenchmarkBuildRequestBody-24 95288 12502 ns/op 14301 B/op 65 allocs/op ```
1 parent 41ff86c commit 8c2439a

2 files changed

Lines changed: 43 additions & 13 deletions

File tree

internal/witness/witness.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -291,23 +291,11 @@ func (w *witness) update(ctx context.Context, cp []byte, size uint64, fetchProof
291291
}
292292
}
293293

294-
// The request body MUST be a sequence of
295-
// - a previous size line,
296-
// - zero or more consistency proof lines,
297-
// - and an empty line,
298-
// - followed by a [checkpoint][].
299-
body := fmt.Sprintf("old %d\n", w.size)
300-
for _, p := range proof {
301-
body += base64.StdEncoding.EncodeToString(p) + "\n"
302-
}
303-
body += "\n"
304-
body += string(cp)
305-
306294
start := time.Now()
307295
nameAttr := witnessNameKey.String(w.verifier.Name())
308296
witnessReqsTotal.Add(ctx, 1, metric.WithAttributes(nameAttr))
309297

310-
req, err := http.NewRequestWithContext(ctx, http.MethodPost, w.url, strings.NewReader(body))
298+
req, err := http.NewRequestWithContext(ctx, http.MethodPost, w.url, w.buildRequestBody(proof, cp))
311299
if err != nil {
312300
return nil, fmt.Errorf("failed to construct request to %q: %v", w.url, err)
313301
}
@@ -390,3 +378,26 @@ func (w *witness) update(ctx context.Context, cp []byte, size uint64, fetchProof
390378
}
391379
})
392380
}
381+
382+
// buildRequestBody formats the request body for the witness.
383+
// The request body MUST be a sequence of
384+
// - a previous size line,
385+
// - zero or more consistency proof lines,
386+
// - and an empty line,
387+
// - followed by a [checkpoint][].
388+
func (w *witness) buildRequestBody(proof [][]byte, cp []byte) io.Reader {
389+
var b bytes.Buffer
390+
fmt.Fprintf(&b, "old %d\n", w.size)
391+
392+
// Preallocate for 32 byte SHA256 nodes
393+
dst := make([]byte, base64.StdEncoding.EncodedLen(32))
394+
395+
for _, p := range proof {
396+
base64.StdEncoding.Encode(dst, p)
397+
b.Write(dst)
398+
b.WriteByte('\n')
399+
}
400+
b.WriteByte('\n')
401+
b.Write(cp)
402+
return &b
403+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package witness
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func BenchmarkBuildRequestBody(b *testing.B) {
8+
w := &witness{size: 0}
9+
proof := make([][]byte, 20)
10+
for i := range proof {
11+
proof[i] = []byte("representative-proof-data-block")
12+
}
13+
cp := []byte("checkpoint-data-is-usually-longer-and-has-multiple-lines\n")
14+
15+
b.ResetTimer()
16+
for b.Loop() {
17+
_ = w.buildRequestBody(proof, cp)
18+
}
19+
}

0 commit comments

Comments
 (0)