From 3ca700d16994335f69339f855e92457b339fa1da Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Tue, 29 Oct 2024 08:36:31 -0700 Subject: [PATCH 1/2] types: remove string prefixes --- types/types.go | 100 ++++++++++++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/types/types.go b/types/types.go index bdee4ed5..a459ad64 100644 --- a/types/types.go +++ b/types/types.go @@ -817,39 +817,28 @@ func (b *Block) ID() BlockID { return BlockID(HashBytes(buf)) } -// Implementations of fmt.Stringer, encoding.Text(Un)marshaler, and json.(Un)marshaler - -func stringerHex(prefix string, data []byte) string { - return prefix + ":" + hex.EncodeToString(data) -} - -func marshalHex(prefix string, data []byte) ([]byte, error) { - return []byte(stringerHex(prefix, data)), nil -} - -func unmarshalHex(dst []byte, prefix string, data []byte) error { - data = bytes.TrimPrefix(data, []byte(prefix+":")) +func unmarshalHex(dst []byte, data []byte) error { if len(data) > len(dst)*2 { - return fmt.Errorf("decoding %v: failed: input too long", prefix) + return errors.New("input too long") } n, err := hex.Decode(dst, data) if err == nil && n < len(dst) { err = io.ErrUnexpectedEOF } if err != nil { - return fmt.Errorf("decoding %v: failed: %w", prefix, err) + return fmt.Errorf("decoding %q failed: %w", data, err) } return nil } // String implements fmt.Stringer. -func (h Hash256) String() string { return stringerHex("h", h[:]) } +func (h Hash256) String() string { return hex.EncodeToString(h[:]) } // MarshalText implements encoding.TextMarshaler. -func (h Hash256) MarshalText() ([]byte, error) { return marshalHex("h", h[:]) } +func (h Hash256) MarshalText() ([]byte, error) { return []byte(hex.EncodeToString(h[:])), nil } // UnmarshalText implements encoding.TextUnmarshaler. -func (h *Hash256) UnmarshalText(b []byte) error { return unmarshalHex(h[:], "h", b) } +func (h *Hash256) UnmarshalText(b []byte) error { return unmarshalHex(h[:], b) } // String implements fmt.Stringer. func (ci ChainIndex) String() string { @@ -928,7 +917,7 @@ func (s *Specifier) UnmarshalText(b []byte) error { // MarshalText implements encoding.TextMarshaler. func (uk UnlockKey) MarshalText() ([]byte, error) { - return marshalHex(uk.Algorithm.String(), uk.Key) + return []byte(uk.Algorithm.String() + ":" + hex.EncodeToString(uk.Key)), nil } // UnmarshalText implements encoding.TextUnmarshaler. @@ -946,25 +935,28 @@ func (uk *UnlockKey) UnmarshalText(b []byte) error { // String implements fmt.Stringer. func (a Address) String() string { checksum := HashBytes(a[:]) - return stringerHex("addr", append(a[:], checksum[:6]...)) + return hex.EncodeToString(append(a[:], checksum[:6]...)) } // MarshalText implements encoding.TextMarshaler. func (a Address) MarshalText() ([]byte, error) { return []byte(a.String()), nil } // UnmarshalText implements encoding.TextUnmarshaler. -func (a *Address) UnmarshalText(b []byte) (err error) { +func (a *Address) UnmarshalText(b []byte) error { withChecksum := make([]byte, 32+6) - n, err := hex.Decode(withChecksum, bytes.TrimPrefix(b, []byte("addr:"))) + if len(b) != len(withChecksum)*2 { + return fmt.Errorf("address must be %d characters", len(withChecksum)*2) + } + n, err := hex.Decode(withChecksum, b) if err != nil { - err = fmt.Errorf("decoding addr: failed: %w", err) + return fmt.Errorf("decoding %q failed: %w", b, err) } else if n != len(withChecksum) { - err = fmt.Errorf("decoding addr: failed: %w", io.ErrUnexpectedEOF) + return fmt.Errorf("decoding %q failed: %w", b, io.ErrUnexpectedEOF) } else if checksum := HashBytes(withChecksum[:32]); !bytes.Equal(checksum[:6], withChecksum[32:]) { - err = errors.New("bad checksum") + return errors.New("bad checksum") } copy(a[:], withChecksum[:32]) - return + return nil } // ParseAddress parses an address from a prefixed hex encoded string. @@ -974,71 +966,87 @@ func ParseAddress(s string) (a Address, err error) { } // String implements fmt.Stringer. -func (bid BlockID) String() string { return stringerHex("bid", bid[:]) } +func (bid BlockID) String() string { return hex.EncodeToString(bid[:]) } // MarshalText implements encoding.TextMarshaler. -func (bid BlockID) MarshalText() ([]byte, error) { return marshalHex("bid", bid[:]) } +func (bid BlockID) MarshalText() ([]byte, error) { return []byte(hex.EncodeToString(bid[:])), nil } // UnmarshalText implements encoding.TextUnmarshaler. -func (bid *BlockID) UnmarshalText(b []byte) error { return unmarshalHex(bid[:], "bid", b) } +func (bid *BlockID) UnmarshalText(b []byte) error { return unmarshalHex(bid[:], b) } // String implements fmt.Stringer. -func (pk PublicKey) String() string { return stringerHex("ed25519", pk[:]) } +func (pk PublicKey) String() string { return "ed25519:" + hex.EncodeToString(pk[:]) } // MarshalText implements encoding.TextMarshaler. -func (pk PublicKey) MarshalText() ([]byte, error) { return marshalHex("ed25519", pk[:]) } +func (pk PublicKey) MarshalText() ([]byte, error) { return []byte(pk.String()), nil } // UnmarshalText implements encoding.TextUnmarshaler. -func (pk *PublicKey) UnmarshalText(b []byte) error { return unmarshalHex(pk[:], "ed25519", b) } +func (pk *PublicKey) UnmarshalText(b []byte) error { + i := bytes.IndexByte(b, ':') + if i < 0 { + return errors.New("missing separator") + } else if string(b[:i]) != "ed25519" { + return fmt.Errorf("unknown algorithm %q", b[:i]) + } + return unmarshalHex(pk[:], b[i+1:]) +} // String implements fmt.Stringer. -func (tid TransactionID) String() string { return stringerHex("txid", tid[:]) } +func (tid TransactionID) String() string { return hex.EncodeToString(tid[:]) } // MarshalText implements encoding.TextMarshaler. -func (tid TransactionID) MarshalText() ([]byte, error) { return marshalHex("txid", tid[:]) } +func (tid TransactionID) MarshalText() ([]byte, error) { + return []byte(hex.EncodeToString(tid[:])), nil +} // UnmarshalText implements encoding.TextUnmarshaler. -func (tid *TransactionID) UnmarshalText(b []byte) error { return unmarshalHex(tid[:], "txid", b) } +func (tid *TransactionID) UnmarshalText(b []byte) error { return unmarshalHex(tid[:], b) } // String implements fmt.Stringer. -func (scoid SiacoinOutputID) String() string { return stringerHex("scoid", scoid[:]) } +func (scoid SiacoinOutputID) String() string { return hex.EncodeToString(scoid[:]) } // MarshalText implements encoding.TextMarshaler. -func (scoid SiacoinOutputID) MarshalText() ([]byte, error) { return marshalHex("scoid", scoid[:]) } +func (scoid SiacoinOutputID) MarshalText() ([]byte, error) { + return []byte(hex.EncodeToString(scoid[:])), nil +} // UnmarshalText implements encoding.TextUnmarshaler. func (scoid *SiacoinOutputID) UnmarshalText(b []byte) error { - return unmarshalHex(scoid[:], "scoid", b) + return unmarshalHex(scoid[:], b) } // String implements fmt.Stringer. -func (sfoid SiafundOutputID) String() string { return stringerHex("sfoid", sfoid[:]) } +func (sfoid SiafundOutputID) String() string { return hex.EncodeToString(sfoid[:]) } // MarshalText implements encoding.TextMarshaler. -func (sfoid SiafundOutputID) MarshalText() ([]byte, error) { return marshalHex("sfoid", sfoid[:]) } +func (sfoid SiafundOutputID) MarshalText() ([]byte, error) { + return []byte(hex.EncodeToString(sfoid[:])), nil +} // UnmarshalText implements encoding.TextUnmarshaler. func (sfoid *SiafundOutputID) UnmarshalText(b []byte) error { - return unmarshalHex(sfoid[:], "sfoid", b) + return unmarshalHex(sfoid[:], b) } // String implements fmt.Stringer. -func (fcid FileContractID) String() string { return stringerHex("fcid", fcid[:]) } +func (fcid FileContractID) String() string { return hex.EncodeToString(fcid[:]) } // MarshalText implements encoding.TextMarshaler. -func (fcid FileContractID) MarshalText() ([]byte, error) { return marshalHex("fcid", fcid[:]) } +func (fcid FileContractID) MarshalText() ([]byte, error) { + return []byte(hex.EncodeToString(fcid[:])), nil +} // UnmarshalText implements encoding.TextUnmarshaler. -func (fcid *FileContractID) UnmarshalText(b []byte) error { return unmarshalHex(fcid[:], "fcid", b) } +func (fcid *FileContractID) UnmarshalText(b []byte) error { return unmarshalHex(fcid[:], b) } // String implements fmt.Stringer. -func (sig Signature) String() string { return stringerHex("sig", sig[:]) } +func (sig Signature) String() string { return hex.EncodeToString(sig[:]) } // MarshalText implements encoding.TextMarshaler. -func (sig Signature) MarshalText() ([]byte, error) { return marshalHex("sig", sig[:]) } +func (sig Signature) MarshalText() ([]byte, error) { return []byte(hex.EncodeToString(sig[:])), nil } // UnmarshalText implements encoding.TextUnmarshaler. -func (sig *Signature) UnmarshalText(b []byte) error { return unmarshalHex(sig[:], "sig", b) } +func (sig *Signature) UnmarshalText(b []byte) error { return unmarshalHex(sig[:], b) } // MarshalJSON implements json.Marshaler. func (fcr FileContractRevision) MarshalJSON() ([]byte, error) { From d15642b38c0c54fef56d5ddcdbf8d4ca20eeb324 Mon Sep 17 00:00:00 2001 From: Nate Maninger Date: Tue, 29 Oct 2024 08:37:01 -0700 Subject: [PATCH 2/2] consensus,rhp,types: fix tests --- consensus/merkle_test.go | 12 ++++++------ rhp/v2/merkle_test.go | 14 +++++++------- rhp/v2/rhp.go | 3 +-- rhp/v4/merkle_test.go | 6 +++--- types/policy_test.go | 12 ++++++------ types/{currency_test.go => types_test.go} | 22 +++++++++++----------- 6 files changed, 34 insertions(+), 35 deletions(-) rename types/{currency_test.go => types_test.go} (94%) diff --git a/consensus/merkle_test.go b/consensus/merkle_test.go index bbb3ffbf..e3d05ad1 100644 --- a/consensus/merkle_test.go +++ b/consensus/merkle_test.go @@ -13,12 +13,12 @@ func TestElementAccumulatorEncoding(t *testing.T) { exp string }{ {0, `{"numLeaves":0,"trees":[]}`}, - {1, `{"numLeaves":1,"trees":["h:0000000000000000000000000000000000000000000000000000000000000000"]}`}, - {2, `{"numLeaves":2,"trees":["h:0100000000000000000000000000000000000000000000000000000000000000"]}`}, - {3, `{"numLeaves":3,"trees":["h:0000000000000000000000000000000000000000000000000000000000000000","h:0100000000000000000000000000000000000000000000000000000000000000"]}`}, - {10, `{"numLeaves":10,"trees":["h:0100000000000000000000000000000000000000000000000000000000000000","h:0300000000000000000000000000000000000000000000000000000000000000"]}`}, - {1 << 16, `{"numLeaves":65536,"trees":["h:1000000000000000000000000000000000000000000000000000000000000000"]}`}, - {1 << 32, `{"numLeaves":4294967296,"trees":["h:2000000000000000000000000000000000000000000000000000000000000000"]}`}, + {1, `{"numLeaves":1,"trees":["0000000000000000000000000000000000000000000000000000000000000000"]}`}, + {2, `{"numLeaves":2,"trees":["0100000000000000000000000000000000000000000000000000000000000000"]}`}, + {3, `{"numLeaves":3,"trees":["0000000000000000000000000000000000000000000000000000000000000000","0100000000000000000000000000000000000000000000000000000000000000"]}`}, + {10, `{"numLeaves":10,"trees":["0100000000000000000000000000000000000000000000000000000000000000","0300000000000000000000000000000000000000000000000000000000000000"]}`}, + {1 << 16, `{"numLeaves":65536,"trees":["1000000000000000000000000000000000000000000000000000000000000000"]}`}, + {1 << 32, `{"numLeaves":4294967296,"trees":["2000000000000000000000000000000000000000000000000000000000000000"]}`}, } { acc := ElementAccumulator{NumLeaves: test.numLeaves} for i := range acc.Trees { diff --git a/rhp/v2/merkle_test.go b/rhp/v2/merkle_test.go index 50d085ef..3b66f216 100644 --- a/rhp/v2/merkle_test.go +++ b/rhp/v2/merkle_test.go @@ -45,16 +45,16 @@ func recNodeRoot(roots []types.Hash256) types.Hash256 { func TestSectorRoot(t *testing.T) { // test some known roots var sector [SectorSize]byte - if SectorRoot(§or).String() != "h:50ed59cecd5ed3ca9e65cec0797202091dbba45272dafa3faa4e27064eedd52c" { + if SectorRoot(§or).String() != "50ed59cecd5ed3ca9e65cec0797202091dbba45272dafa3faa4e27064eedd52c" { t.Error("wrong Merkle root for empty sector") } sector[0] = 1 - if SectorRoot(§or).String() != "h:8c20a2c90a733a5139cc57e45755322e304451c3434b0c0a0aad87f2f89a44ab" { + if SectorRoot(§or).String() != "8c20a2c90a733a5139cc57e45755322e304451c3434b0c0a0aad87f2f89a44ab" { t.Error("wrong Merkle root for sector[0] = 1") } sector[0] = 0 sector[SectorSize-1] = 1 - if SectorRoot(§or).String() != "h:d0ab6691d76750618452e920386e5f6f98fdd1219a70a06f06ef622ac6c6373c" { + if SectorRoot(§or).String() != "d0ab6691d76750618452e920386e5f6f98fdd1219a70a06f06ef622ac6c6373c" { t.Error("wrong Merkle root for sector[SectorSize-1] = 1") } @@ -95,11 +95,11 @@ func TestMetaRoot(t *testing.T) { t.Error("wrong Merkle root for single root") } roots = make([]types.Hash256, 32) - if MetaRoot(roots).String() != "h:1c23727030051d1bba1c887273addac2054afbd6926daddef6740f4f8bf1fb7f" { + if MetaRoot(roots).String() != "1c23727030051d1bba1c887273addac2054afbd6926daddef6740f4f8bf1fb7f" { t.Error("wrong Merkle root for 32 empty roots") } roots[0][0] = 1 - if MetaRoot(roots).String() != "h:c5da05749139505704ea18a5d92d46427f652ac79c5f5712e4aefb68e20dffb8" { + if MetaRoot(roots).String() != "c5da05749139505704ea18a5d92d46427f652ac79c5f5712e4aefb68e20dffb8" { t.Error("wrong Merkle root for roots[0][0] = 1") } @@ -161,7 +161,7 @@ func TestProofAccumulator(t *testing.T) { for _, root := range roots { pa.insertNode(root, 0) } - if pa.root().String() != "h:1c23727030051d1bba1c887273addac2054afbd6926daddef6740f4f8bf1fb7f" { + if pa.root().String() != "1c23727030051d1bba1c887273addac2054afbd6926daddef6740f4f8bf1fb7f" { t.Error("wrong root for 32 empty roots") } @@ -170,7 +170,7 @@ func TestProofAccumulator(t *testing.T) { for _, root := range roots { pa.insertNode(root, 0) } - if pa.root().String() != "h:c5da05749139505704ea18a5d92d46427f652ac79c5f5712e4aefb68e20dffb8" { + if pa.root().String() != "c5da05749139505704ea18a5d92d46427f652ac79c5f5712e4aefb68e20dffb8" { t.Error("wrong root for roots[0][0] = 1") } diff --git a/rhp/v2/rhp.go b/rhp/v2/rhp.go index a366bb31..bcc7a504 100644 --- a/rhp/v2/rhp.go +++ b/rhp/v2/rhp.go @@ -6,7 +6,6 @@ import ( "errors" "fmt" "net" - "strings" "time" "go.sia.tech/core/types" @@ -91,7 +90,7 @@ func (hs HostSettings) MarshalJSON() ([]byte, error) { "remainingstorage": hs.RemainingStorage, "sectorsize": hs.SectorSize, "totalstorage": hs.TotalStorage, - "unlockhash": strings.TrimPrefix(hs.Address.String(), "addr:"), // trim the "addr:" prefix for compatibility with siad + "unlockhash": hs.Address.String(), "windowsize": hs.WindowSize, "collateral": hs.Collateral, "maxcollateral": hs.MaxCollateral, diff --git a/rhp/v4/merkle_test.go b/rhp/v4/merkle_test.go index 83457ebb..d6d602e8 100644 --- a/rhp/v4/merkle_test.go +++ b/rhp/v4/merkle_test.go @@ -44,16 +44,16 @@ func recNodeRoot(roots []types.Hash256) types.Hash256 { func TestSectorRoot(t *testing.T) { // test some known roots var sector [SectorSize]byte - if SectorRoot(§or).String() != "h:50ed59cecd5ed3ca9e65cec0797202091dbba45272dafa3faa4e27064eedd52c" { + if SectorRoot(§or).String() != "50ed59cecd5ed3ca9e65cec0797202091dbba45272dafa3faa4e27064eedd52c" { t.Error("wrong Merkle root for empty sector") } sector[0] = 1 - if SectorRoot(§or).String() != "h:8c20a2c90a733a5139cc57e45755322e304451c3434b0c0a0aad87f2f89a44ab" { + if SectorRoot(§or).String() != "8c20a2c90a733a5139cc57e45755322e304451c3434b0c0a0aad87f2f89a44ab" { t.Error("wrong Merkle root for sector[0] = 1") } sector[0] = 0 sector[SectorSize-1] = 1 - if SectorRoot(§or).String() != "h:d0ab6691d76750618452e920386e5f6f98fdd1219a70a06f06ef622ac6c6373c" { + if SectorRoot(§or).String() != "d0ab6691d76750618452e920386e5f6f98fdd1219a70a06f06ef622ac6c6373c" { t.Error("wrong Merkle root for sector[SectorSize-1] = 1") } diff --git a/types/policy_test.go b/types/policy_test.go index 4a295434..1ec8179a 100644 --- a/types/policy_test.go +++ b/types/policy_test.go @@ -272,7 +272,7 @@ func TestPolicyVerify(t *testing.T) { func TestPolicyGolden(t *testing.T) { pk := PublicKey{1, 2, 3} p := SpendPolicy{PolicyTypeUnlockConditions(StandardUnlockConditions(pk))} - if p.Address().String() != "addr:72b0762b382d4c251af5ae25b6777d908726d75962e5224f98d7f619bb39515dd64b9a56043a" { + if p.Address().String() != "72b0762b382d4c251af5ae25b6777d908726d75962e5224f98d7f619bb39515dd64b9a56043a" { t.Fatal("wrong address:", p, p.Address()) } else if StandardUnlockHash(pk) != p.Address() { t.Fatal("StandardUnlockHash differs from Policy.Address") @@ -289,7 +289,7 @@ func TestPolicyGolden(t *testing.T) { PolicyPublicKey(PublicKey{4, 5, 6}), }), }) - if p.Address().String() != "addr:111d2995afa8bf162180a647b9f1eb6a275fe8818e836b69b351871d5caf9c590ed25aec0616" { + if p.Address().String() != "111d2995afa8bf162180a647b9f1eb6a275fe8818e836b69b351871d5caf9c590ed25aec0616" { t.Fatal("wrong address:", p, p.Address()) } } @@ -395,7 +395,7 @@ func TestSpendPolicyMarshalJSON(t *testing.T) { }, { sp: PolicyHash(hash), - exp: fmt.Sprintf(`{"type":"h","policy":"h:%x"}`, hash[:]), + exp: fmt.Sprintf(`{"type":"h","policy":"%x"}`, hash[:]), }, { sp: PolicyThreshold(2, []SpendPolicy{ @@ -453,13 +453,13 @@ func TestSatisfiedPolicyMarshalJSON(t *testing.T) { sp: PolicyThreshold(1, []SpendPolicy{PolicyPublicKey(publicKey), PolicyHash(hash)}), signatures: []Signature{signature}, preimages: [][32]byte{{1, 2, 3}}, - exp: fmt.Sprintf(`{"policy":{"type":"thresh","policy":{"n":1,"of":[{"type":"pk","policy":"ed25519:%x"},{"type":"h","policy":"h:%x"}]}},"signatures":[%q],"preimages":["0102030000000000000000000000000000000000000000000000000000000000"]}`, publicKey[:], hash[:], signature), + exp: fmt.Sprintf(`{"policy":{"type":"thresh","policy":{"n":1,"of":[{"type":"pk","policy":"ed25519:%x"},{"type":"h","policy":"%x"}]}},"signatures":[%q],"preimages":["0102030000000000000000000000000000000000000000000000000000000000"]}`, publicKey[:], hash[:], signature), }, { name: "PolicyWithPreimagesOnly", sp: PolicyHash(hash), preimages: [][32]byte{{4, 5, 6}}, - exp: fmt.Sprintf(`{"policy":{"type":"h","policy":"h:%x"},"preimages":["0405060000000000000000000000000000000000000000000000000000000000"]}`, hash[:]), + exp: fmt.Sprintf(`{"policy":{"type":"h","policy":"%x"},"preimages":["0405060000000000000000000000000000000000000000000000000000000000"]}`, hash[:]), }, { name: "PolicyWithEmptySignatures", @@ -469,7 +469,7 @@ func TestSatisfiedPolicyMarshalJSON(t *testing.T) { { name: "PolicyWithEmptyPreimages", sp: PolicyHash(hash), - exp: fmt.Sprintf(`{"policy":{"type":"h","policy":"h:%x"}}`, hash[:]), + exp: fmt.Sprintf(`{"policy":{"type":"h","policy":"%x"}}`, hash[:]), }, } diff --git a/types/currency_test.go b/types/types_test.go similarity index 94% rename from types/currency_test.go rename to types/types_test.go index a4cf92d5..d6b2e65d 100644 --- a/types/currency_test.go +++ b/types/types_test.go @@ -761,27 +761,27 @@ func TestParseCurrency(t *testing.T) { func TestUnmarshalHex(t *testing.T) { for _, test := range []struct { - prefix string data string dstLen int err string }{ - {"", strings.Repeat("0", 2), 1, ""}, - {"", strings.Repeat("_", 2), 1, "decoding : failed: encoding/hex: invalid byte: U+005F '_'"}, - {"ed25519", strings.Repeat("0", 62), 32, "decoding ed25519: failed: unexpected EOF"}, - {"ed25519", strings.Repeat("0", 63), 32, "decoding ed25519: failed: encoding/hex: odd length hex string"}, - {"ed25519", strings.Repeat("0", 64), 32, ""}, - {"ed25519", strings.Repeat("0", 65), 32, "decoding ed25519: failed: input too long"}, + {strings.Repeat("_", 2), 1, "encoding/hex: invalid byte: U+005F '_'"}, + {strings.Repeat("0", 62), 32, "unexpected EOF"}, + {strings.Repeat("0", 63), 32, "encoding/hex: odd length hex string"}, + {strings.Repeat("0", 65), 32, "input too long"}, + + {strings.Repeat("0", 2), 1, ""}, + {strings.Repeat("0", 64), 32, ""}, } { dst := make([]byte, test.dstLen) - err := unmarshalHex(dst, test.prefix, []byte(test.data)) + err := unmarshalHex(dst, []byte(test.data)) if err == nil { if test.err != "" { - t.Errorf("unmarshalHex(%s, %s) expected error %q, got nil", test.prefix, test.data, test.err) + t.Errorf("unmarshal %q expected error %q, got nil", test.data, test.err) } } else { - if err.Error() != test.err { - t.Errorf("unmarshalHex(%s, %s) expected error %q, got %q", test.prefix, test.data, test.err, err) + if !strings.Contains(err.Error(), test.err) { + t.Errorf("unmarshal %q expected error %q, got %q", test.data, test.err, err) } } }