def test_NetAddressDecodeErrors(): """ Peform negative tests against wire encode and decode NetAddress to confirm error paths work correctly. """ # baseNetAddr is used in the various tests as a baseline NetAddress. baseNetAddr = netaddress.NetAddress( ip="127.0.0.1", port=8333, services=wire.SFNodeNetwork, stamp=0x495FAB29, # 2009-01-03 12:15:05 -0600 CST ) bufWithTime = netaddress.writeNetAddress(baseNetAddr, True) bufWithoutTime = netaddress.writeNetAddress(baseNetAddr, False) tests = [ (bufWithTime[:-1], True), (bufWithTime + [0], True), (bufWithoutTime[:-1], False), (bufWithoutTime + [0], False), (ByteArray(), True), ] for buf, hasStamp in tests: with pytest.raises(DecredError): netaddress.readNetAddress(buf, hasStamp)
def test_NetAddress(): ip = "127.0.0.1" port = 8333 # Test NewNetAddress. na = netaddress.NetAddress(ip, port, 0) # Ensure we get the same ip, port, and services back out. assert byteIP4 == na.ip assert port == na.port assert na.services == 0 assert not na.hasService(wire.SFNodeNetwork) # Ensure adding the full service node flag works. na.addService(wire.SFNodeNetwork) assert na.services == wire.SFNodeNetwork assert na.hasService(wire.SFNodeNetwork) # Ensure max payload is expected value for latest protocol version. wantPayload = 30 maxPayload = netaddress.MaxNetAddressPayload assert maxPayload == wantPayload # Ensure max payload length is not more than MaxMessagePayload. assert maxPayload <= wire.MaxMessagePayload
def test_VersionOptionalFields(): """ Perform tests to ensure that an encoded version messages that omit optional fields are handled correctly. """ # onlyRequiredVersion is a version message that only contains the # required versions and all other values set to their default values. onlyRequiredVersion = minimumMsgVersion() onlyRequiredVersionEncoded = baseVersionEncoded()[:-55] # addrMeVersion is a version message that contains all fields through # the AddrMe field. addrMe = netaddress.NetAddress( ip="127.0.0.1", port=8333, services=wire.SFNodeNetwork, stamp=0, ) addrMeVersion = minimumMsgVersion() addrMeVersion.addrMe = addrMe addrMeVersionEncoded = baseVersionEncoded()[:-29] # nonceVersion is a version message that contains all fields through # the Nonce field. nonceVersion = minimumMsgVersion() nonceVersion.addrMe = addrMe nonceVersion.nonce = 123123 # 0x1e0f3 nonceVersionEncoded = baseVersionEncoded()[:-21] # uaVersion is a version message that contains all fields through # the UserAgent field. uaVersion = minimumMsgVersion() uaVersion.addrMe = addrMe uaVersion.nonce = 123123 uaVersion.userAgent = "/dcrdtest:0.0.1/" uaVersionEncoded = baseVersionEncoded()[:-4] # lastBlockVersion is a version message that contains all fields # through the LastBlock field. lastBlockVersion = minimumMsgVersion() lastBlockVersion.addrMe = addrMe lastBlockVersion.nonce = 123123 lastBlockVersion.userAgent = "/dcrdtest:0.0.1/" lastBlockVersion.lastBlock = 234234 # 0x392fa lastBlockVersionEncoded = baseVersionEncoded() tests = [ (onlyRequiredVersion, onlyRequiredVersionEncoded), (addrMeVersion, addrMeVersionEncoded), (nonceVersion, nonceVersionEncoded), (uaVersion, uaVersionEncoded), (lastBlockVersion, lastBlockVersionEncoded), ] for expMsg, buf in tests: # Decode the message from wire format. msg = msgversion.MsgVersion.btcDecode(buf, wire.ProtocolVersion) assert sameMsgVersion(msg, expMsg)
def minimumMsgVersion(): return msgversion.MsgVersion( protocolVersion=60002, services=wire.SFNodeNetwork, timestamp=0x495FAB29, addrYou=netaddress.NetAddress( ip="192.168.0.1", port=8333, services=wire.SFNodeNetwork, stamp=0, ), addrMe=netaddress.NetAddress( ip=ByteArray(length=16), port=0, services=0, stamp=0, ), nonce=0, userAgent="", lastBlock=0, disableRelayTx=False, )
def baseVersion(): return msgversion.MsgVersion( addrMe=netaddress.NetAddress( ip="127.0.0.1", port=8333, services=wire.SFNodeNetwork, stamp=0, ), addrYou=netaddress.NetAddress( ip="192.168.0.1", port=8333, services=wire.SFNodeNetwork, stamp=0, ), nonce=123123, lastBlock=234234, services=wire.SFNodeNetwork, disableRelayTx=False, protocolVersion=60002, timestamp=0x495FAB29, userAgent="/dcrdtest:0.0.1/", )
def btcDecode(b, pver): """ btcDecode decodes b using the Decred protocol encoding into the receiver. The version message is special in that the protocol version hasn't been negotiated yet. As a result, the pver field is ignored and any fields which are added in new versions are optional. This is part of the Message API. Args: b (ByteArray): The encoded MsgVersion. pver (int): The protocol version. Unused. Returns: MsgVersion: The decoded MsgVersion. """ uint64 = 8 int32 = 4 pver = b.pop(int32).unLittle().int() services = b.pop(uint64).unLittle().int() stamp = b.pop(uint64).unLittle().int() addrYou = netaddress.readNetAddress(b.pop(26), False) # Protocol versions >= 106 added a from address, nonce, and user agent # field and they are only considered present if there are bytes # remaining in the message. if len(b) > 0: addrMe = netaddress.readNetAddress(b.pop(26), False) else: addrMe = netaddress.NetAddress( ByteArray(length=16), port=0, services=0, stamp=0 ) nonce = 0 if len(b) > 0: nonce = b.pop(uint64).unLittle().int() userAgent = "" if len(b) > 0: userAgent = wire.readVarString(b, pver) if not validateUserAgent(userAgent): raise DecredError(f"bad user agent: {userAgent}") # Protocol versions >= 209 added a last known block field. It is only # considered present if there are bytes remaining in the message. lastBlock = 0 if len(b) > 0: lastBlock = b.pop(int32).unLittle().int() # There was no relay transactions field before BIP0037Version, but # the default behavior prior to the addition of the field was to always # relay transactions. disableRelayTx = False if len(b) > 0: # The wire encoding for the field is true when transactions should # be relayed, so reverse it for the DisableRelayTx field. disableRelayTx = b.pop(1) == [0] return MsgVersion( protocolVersion=pver, services=services, timestamp=stamp, addrYou=addrYou, addrMe=addrMe, nonce=nonce, userAgent=userAgent, lastBlock=lastBlock, disableRelayTx=disableRelayTx, )
def test_NetAddressWire(): """ test the NetAddress wire encode and decode for various protocol versions and timestamp flag combinations. """ # baseNetAddr is used in the various tests as a baseline NetAddress. baseNetAddr = netaddress.NetAddress( ip="127.0.0.1", port=8333, services=wire.SFNodeNetwork, stamp=0x495FAB29, # 2009-01-03 12:15:05 -0600 CST ) # baseNetAddrNoTS is baseNetAddr with a zero value for the timestamp. baseNetAddrNoTS = netaddress.NetAddress( ip=baseNetAddr.ip, port=baseNetAddr.port, services=baseNetAddr.services, stamp=0, ) # fmt: off # baseNetAddrEncoded is the wire encoded bytes of baseNetAddr. baseNetAddrEncoded = ByteArray([ 0x29, 0xab, 0x5f, 0x49, # Timestamp 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # SFNodeNetwork 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, # IP 127.0.0.1 0x20, 0x8d, # Port 8333 in big-endian ]) # baseNetAddrNoTSEncoded is the wire encoded bytes of baseNetAddrNoTS. baseNetAddrNoTSEncoded = ByteArray([ # No timestamp 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, # SFNodeNetwork 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x01, # IP 127.0.0.1 0x20, 0x8d, # Port 8333 in big-endian ]) # fmt: on """ addrIn NetAddress to encode out Expected decoded NetAddress ts Include timestamp? buf Wire encoding pver Protoc """ tests = [ # Latest protocol version without ts flag. dict( addrIn=baseNetAddr, out=baseNetAddrNoTS, ts=False, buf=baseNetAddrNoTSEncoded, pver=wire.ProtocolVersion, ), # Latest protocol version with ts flag. dict( addrIn=baseNetAddr, out=baseNetAddr, ts=True, buf=baseNetAddrEncoded, pver=wire.ProtocolVersion, ), ] for test in tests: # Encode to wire format. b = netaddress.writeNetAddress(test["addrIn"], test["ts"]) assert b == test["buf"] # Decode the message from wire format. na = netaddress.readNetAddress(test["buf"], test["ts"]) assert byteIP4 == test["out"].ip assert na.port == test["out"].port assert na.services == test["out"].services assert na.timestamp == test["out"].timestamp baseNetAddr.ip = None b = netaddress.writeNetAddress(baseNetAddr, True) reNA = netaddress.readNetAddress(b, True) assert reNA.ip == ByteArray(length=16) # make sure a ipv6 address parses without an exception. netaddress.NetAddress( ip="2001:0db8:85a3:0000:0000:8a2e:0370:7334", port=8333, services=wire.SFNodeNetwork, stamp=0x495FAB29, # 2009-01-03 12:15:05 -0600 CST )
def test_MsgVersion(): pver = wire.ProtocolVersion # Create version message data. lastBlock = 234234 me = netaddress.NetAddress(ip="127.0.0.1", port=8333, services=wire.SFNodeNetwork) you = netaddress.NetAddress(ip="192.168.0.1", port=8333, services=wire.SFNodeNetwork) nonce = random.randint(0, 0xFFFFFFFF) # Ensure we get the correct data back out. msg = msgversion.MsgVersion( addrMe=me, addrYou=you, nonce=nonce, lastBlock=lastBlock, services=0, ) assert msg.protocolVersion == pver assert sameNetAddress(msg.addrMe, me) assert sameNetAddress(msg.addrYou, you) assert msg.nonce == nonce assert msg.userAgent == msgversion.DefaultUserAgent assert msg.lastBlock == lastBlock assert not msg.disableRelayTx msg.addUserAgent("myclient", "1.2.3", "optional", "comments") customUserAgent = (msgversion.DefaultUserAgent + "myclient:1.2.3(optional; comments)/") assert msg.userAgent == customUserAgent msg.addUserAgent("mygui", "3.4.5") customUserAgent += "mygui:3.4.5/" assert msg.userAgent == customUserAgent # accounting for ":", "/" with pytest.raises(DecredError): msg.addUserAgent( "t" * (msgversion.MaxUserAgentLen - len(customUserAgent) - 2 + 1), "") # Version message should not have any services set by default. assert msg.services == 0 assert not msg.hasService(wire.SFNodeNetwork) # Ensure the command is expected value. assert msg.command() == "version" # Ensure max payload is expected value. # Protocol version 4 bytes + services 8 bytes + timestamp 8 bytes + # remote and local net addresses + nonce 8 bytes + length of user agent # (varInt) + max allowed user agent length + last block 4 bytes + # relay transactions flag 1 byte. wantPayload = 358 maxPayload = msg.maxPayloadLength(pver) assert maxPayload == wantPayload # Ensure max payload length is not more than MaxMessagePayload. assert maxPayload <= wire.MaxMessagePayload # Ensure adding the full service node flag works. msg.addService(wire.SFNodeNetwork) assert msg.services == wire.SFNodeNetwork assert msg.hasService(wire.SFNodeNetwork)