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

unpackdev / solgo / 8763674951

20 Apr 2024 08:08AM UTC coverage: 65.062% (-0.006%) from 65.068%
8763674951

Pull #204

github

0x19
Constructor tests improvements
Pull Request #204: TBD

3 of 17 new or added lines in 3 files covered. (17.65%)

2 existing lines in 1 file now uncovered.

27445 of 42183 relevant lines covered (65.06%)

0.71 hits per line

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

68.27
/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✔
57
                toReturn, err := strconv.ParseBool(experimental)
×
58
                if err != nil {
×
59
                        return false
×
60
                }
×
61
                return toReturn
×
62
        }
63

64
        if experimental, ok := m.Experimental.(bool); ok {
1✔
65
                return experimental
×
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
// IsPartial checks whenever decoded bytecode data is partial (some fields are missing, not known)
NEW
123
func (m *Metadata) IsPartial() bool {
×
NEW
124
        if m.cborLength == 0 {
×
NEW
125
                return true
×
NEW
126
        }
×
127

NEW
128
        if len(m.auxbytes) == 0 {
×
NEW
129
                return true
×
NEW
130
        }
×
131

NEW
132
        if len(m.Solc) == 0 {
×
NEW
133
                return true
×
NEW
134
        }
×
135

NEW
136
        if len(m.Ipfs) == 0 && len(m.Bzzr0) == 0 && len(m.Bzzr1) == 0 {
×
NEW
137
                return true
×
NEW
138
        }
×
139

NEW
140
        return false
×
141
}
142

143
// DecodeContractMetadata decodes the metadata from Ethereum contract creation bytecode.
144
// It returns a Metadata object and an error, if any occurred during decoding.
145
func DecodeContractMetadata(bytecode []byte) (*Metadata, error) {
1✔
146
        if len(bytecode) == 0 {
2✔
147
                return nil, errors.New("provided bytecode slice is empty")
1✔
148
        }
1✔
149

150
        toReturn := Metadata{}
1✔
151

1✔
152
        // Per solidity docs, last two bytes of the bytecode are the length of the cbor object
1✔
153
        bytesLength := 2
1✔
154

1✔
155
        // Take latest 2 bytes of the bytecode (length of the cbor object)
1✔
156
        cborLength := int(bytecode[len(bytecode)-2])<<8 | int(bytecode[len(bytecode)-1])
1✔
157
        toReturn.cborLength = int16(cborLength)
1✔
158

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

164
        // Split the bytecode into execution bytecode and auxdata
165
        if len(bytecode) >= bytesLength+cborLength {
2✔
166
                toReturn.executionBytecode = bytecode[:len(bytecode)-bytesLength-cborLength]
1✔
167
                toReturn.auxbytes = bytecode[len(bytecode)-bytesLength-cborLength : len(bytecode)-bytesLength]
1✔
168
                if err := cbor.Unmarshal(toReturn.auxbytes, &toReturn); err != nil {
1✔
169
                        return nil, err
×
170
                }
×
171
        } else {
×
172
                return nil, errors.New("provided bytecode slice is smaller than the length of the cbor object")
×
173
        }
×
174

175
        return &toReturn, nil
1✔
176
}
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

© 2025 Coveralls, Inc