• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

unpackdev / solgo / 8465579594

28 Mar 2024 10:03AM UTC coverage: 68.339% (-0.3%) from 68.666%
8465579594

Pull #163

github

0x19
Introducing log, tx decoder including fixes for constructor
Pull Request #163: Bytecode package: Log, Tx decoder incl. fixes for contract

4 of 185 new or added lines in 4 files covered. (2.16%)

2 existing lines in 1 file now uncovered.

26677 of 39036 relevant lines covered (68.34%)

0.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.89
/bytecode/metadata.go
1
package bytecode
2

3
import (
4
        "bytes"
5
        "errors"
6
        "fmt"
7
        "strconv"
8
        "strings"
9

10
        "github.com/fxamacker/cbor/v2"
11
        "github.com/mr-tron/base58"
12
        metadata_pb "github.com/unpackdev/protos/dist/go/metadata"
13
)
14

15
// Metadata represents the metadata contained in Ethereum contract creation bytecode.
16
// The structure and encoding of the metadata is defined by the Solidity compiler.
17
// More information can be found at https://docs.soliditylang.org/en/v0.8.20/metadata.html#encoding-of-the-metadata-hash-in-the-bytecode
18
type Metadata struct {
19
        executionBytecode []byte      // The execution bytecode of the contract
20
        cborLength        int16       // The length of the CBOR metadata
21
        auxbytes          []byte      // The raw CBOR metadata
22
        Ipfs              []byte      `cbor:"ipfs"`         // The IPFS hash of the metadata, if present
23
        Bzzr1             []byte      `cbor:"bzzr1"`        // The Swarm hash of the metadata, if present (version 1)
24
        Bzzr0             []byte      `cbor:"bzzr0"`        // The Swarm hash of the metadata, if present (version 0)
25
        Experimental      interface{} `cbor:"experimental"` // Experimental metadata, if present
26
        Solc              []byte      `cbor:"solc"`         // The version of the Solidity compiler used
27
}
28

29
// ToProto converts the Metadata instance into a protobuf representation, suitable for
30
// serialization and transmission across different systems or networks.
31
func (m *Metadata) ToProto() *metadata_pb.BytecodeMetadata {
1✔
32
        return &metadata_pb.BytecodeMetadata{
1✔
33
                ExecutionBytecode: m.executionBytecode,
1✔
34
                CborLength:        uint32(m.cborLength),
1✔
35
                Raw:               m.auxbytes,
1✔
36
                Ipfs:              m.GetIPFS(),
1✔
37
                Bzzr1:             m.GetBzzr1(),
1✔
38
                Bzzr0:             m.GetBzzr0(),
1✔
39
                Experimental:      m.GetExperimental(),
1✔
40
                Solc:              m.GetCompilerVersion(),
1✔
41
                Solgo:             "", // TODO: Solgo version should be appended...
1✔
42
        }
1✔
43
}
1✔
44

45
// GetCompilerVersion returns the version of the Solidity compiler used to compile the contract.
46
func (m *Metadata) GetCompilerVersion() string {
1✔
47
        s := make([]string, 0, len(m.Solc))
1✔
48
        for _, i := range m.Solc {
2✔
49
                s = append(s, strconv.Itoa(int(i)))
1✔
50
        }
1✔
51
        return strings.Join(s, ".")
1✔
52
}
53

54
// GetExperimental returns whether the contract includes experimental metadata.
55
func (m *Metadata) GetExperimental() bool {
1✔
56
        if experimental, ok := m.Experimental.(string); ok {
1✔
NEW
57
                toReturn, err := strconv.ParseBool(experimental)
×
NEW
58
                if err != nil {
×
NEW
59
                        return false
×
NEW
60
                }
×
NEW
61
                return toReturn
×
62
        }
63

64
        if experimental, ok := m.Experimental.(bool); ok {
1✔
NEW
65
                return experimental
×
UNCOV
66
        }
×
67

68
        return false
1✔
69
}
70

71
// GetIPFS returns the IPFS hash of the contract's metadata, if present.
72
func (m *Metadata) GetIPFS() string {
1✔
73
        return fmt.Sprintf("ipfs://%s", base58.Encode(m.Ipfs))
1✔
74
}
1✔
75

76
// GetBzzr0 returns the Swarm (version 0) hash of the contract's metadata, if present.
77
func (m *Metadata) GetBzzr0() string {
1✔
78
        return fmt.Sprintf("bzz://%s", base58.Encode(m.Bzzr0))
1✔
79
}
1✔
80

81
// GetBzzr1 returns the Swarm (version 1) hash of the contract's metadata, if present.
82
func (m *Metadata) GetBzzr1() string {
1✔
83
        return fmt.Sprintf("bzz://%s", base58.Encode(m.Bzzr1))
1✔
84
}
1✔
85

86
// GetExecutionBytecode returns the execution bytecode of the contract.
87
func (m *Metadata) GetExecutionBytecode() []byte {
1✔
88
        return m.executionBytecode
1✔
89
}
1✔
90

91
// GetAuxBytecode returns the raw CBOR metadata of the contract.
92
func (m *Metadata) GetAuxBytecode() []byte {
1✔
93
        return m.auxbytes
1✔
94
}
1✔
95

96
// GetCborLength returns the length of the CBOR metadata.
97
func (m *Metadata) GetCborLength() int16 {
1✔
98
        return m.cborLength
1✔
99
}
1✔
100

101
// AuxFound returns whether the CBOR metadata bytes are contained in the provided byte slice.
102
// This is used to verify if contract extracted cbor metadata can be found in the deployed/execution contract bytecode.
103
func (m *Metadata) AuxFound(b []byte) bool {
×
104
        return bytes.Contains(b, m.auxbytes)
×
105
}
×
106

107
// GetUrls returns the URLs of the contract's metadata.
108
func (m *Metadata) GetUrls() []string {
1✔
109
        urls := make([]string, 0)
1✔
110
        if len(m.GetIPFS()) > 7 {
2✔
111
                urls = append(urls, m.GetIPFS())
1✔
112
        }
1✔
113
        if len(m.GetBzzr0()) > 6 {
1✔
114
                urls = append(urls, m.GetBzzr1())
×
115
        }
×
116
        if len(m.GetBzzr1()) > 6 {
1✔
117
                urls = append(urls, m.GetBzzr0())
×
118
        }
×
119
        return urls
1✔
120
}
121

122
// DecodeContractMetadata decodes the metadata from Ethereum contract creation bytecode.
123
// It returns a Metadata object and an error, if any occurred during decoding.
124
func DecodeContractMetadata(bytecode []byte) (*Metadata, error) {
1✔
125
        if len(bytecode) == 0 {
2✔
126
                return nil, errors.New("provided bytecode slice is empty")
1✔
127
        }
1✔
128

129
        toReturn := Metadata{}
1✔
130

1✔
131
        // Per solidity docs, last two bytes of the bytecode are the length of the cbor object
1✔
132
        bytesLength := 2
1✔
133

1✔
134
        // Take latest 2 bytes of the bytecode (length of the cbor object)
1✔
135
        cborLength := int(bytecode[len(bytecode)-2])<<8 | int(bytecode[len(bytecode)-1])
1✔
136
        toReturn.cborLength = int16(cborLength)
1✔
137

1✔
138
        // If the length of the cbor is more or equal to the length of the execution bytecode, it means there is no cbor
1✔
139
        if len(bytecode)-bytesLength <= 0 {
2✔
140
                return nil, errors.New("provided bytecode slice does not contain cbor metadata")
1✔
141
        }
1✔
142

143
        // Split the bytecode into execution bytecode and auxdata
144
        if len(bytecode) >= bytesLength+cborLength {
2✔
145
                toReturn.executionBytecode = bytecode[:len(bytecode)-bytesLength-cborLength]
1✔
146
                toReturn.auxbytes = bytecode[len(bytecode)-bytesLength-cborLength : len(bytecode)-bytesLength]
1✔
147
                if err := cbor.Unmarshal(toReturn.auxbytes, &toReturn); err != nil {
1✔
UNCOV
148
                        return nil, err
×
149
                }
×
150
        } else {
×
151
                return nil, errors.New("provided bytecode slice is smaller than the length of the cbor object")
×
152
        }
×
153

154
        return &toReturn, nil
1✔
155
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc