Skip to content

tm2/pkg/crypto: Address.Compare needlessly allocates #4129

Open
@odeke-em

Description

@odeke-em

Description

crypto.Address is very paramount to Gno and basically all of cryptocurrencies as addresses are foundational!

While working on PR #4128 to fix #4122, I noticed that we have this code for crypto.Address.Compare

func (addr Address) Compare(other Address) int {
bz1 := make([]byte, len(addr))
bz2 := make([]byte, len(other))
copy(bz1, addr[:])
copy(bz2, other[:])
return bytes.Compare(bz1, bz2)
}

but the definition of Address is an array of a fixed size derived from a []byte slice.

See how involved that code is, creating new slices and copying both byteslices then invoking bytes.Compare: this is unnecessary and we are very lucky that the Go compiler is very smart with escape analysis along with single static assignment to detect that unnecessary copying but really that code can be simplified to this

func (addr *Address) Compare2(other Address) int {
    return bytes.Compare(addr[:], other[:])
}

and it'll be even much more efficient per

package crypto

import (
	"crypto/rand"
	"testing"
)

var sink any = nil

func BenchmarkAddressCompare(b *testing.B) {
	var addr1, addr2 Address
	rand.Read(addr1[:])
	rand.Read(addr2[:])
	b.ResetTimer()
	b.ReportAllocs()

	for i := 0; i < b.N; i++ {
		sink = addr1.Compare(addr1)
		sink = addr1.Compare(addr2)
		sink = addr2.Compare(addr2)
		sink = addr2.Compare(addr1)
	}

	if sink == nil {
		b.Fatal("Benchmark did not run!")
	}

	sink = nil
}

which gives us this result

name              old time/op    new time/op    delta
AddressCompare-8    79.5ns ± 1%    52.4ns ± 1%  -34.13%  (p=0.000 n=10+9)

name              old alloc/op   new alloc/op   delta
AddressCompare-8     8.00B ± 0%     8.00B ± 0%     ~     (all equal)

name              old allocs/op  new allocs/op  delta
AddressCompare-8      1.00 ± 0%      1.00 ± 0%     ~     (all equal)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    Triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions