From 2d0552b90343fb89cfc8131a99ab9c49a8ed2fb9 Mon Sep 17 00:00:00 2001 From: Andreas Schildbach Date: Sat, 6 Mar 2021 14:51:30 +0100 Subject: [PATCH] AlertMessage: Remove alert messages. The alert message facility has been removed from the Bitcoin protocol due to its centralized nature. --- .../java/org/bitcoinj/core/AlertMessage.java | 254 ------------------ .../org/bitcoinj/core/BitcoinSerializer.java | 11 - .../org/bitcoinj/core/DummySerializer.java | 5 - .../org/bitcoinj/core/MessageSerializer.java | 7 - .../org/bitcoinj/core/NetworkParameters.java | 15 -- .../src/main/java/org/bitcoinj/core/Peer.java | 18 -- .../org/bitcoinj/params/TestNet3Params.java | 1 - .../org/bitcoinj/core/AlertMessageTest.java | 59 ---- 8 files changed, 370 deletions(-) delete mode 100644 core/src/main/java/org/bitcoinj/core/AlertMessage.java delete mode 100644 core/src/test/java/org/bitcoinj/core/AlertMessageTest.java diff --git a/core/src/main/java/org/bitcoinj/core/AlertMessage.java b/core/src/main/java/org/bitcoinj/core/AlertMessage.java deleted file mode 100644 index b4e1131265f..00000000000 --- a/core/src/main/java/org/bitcoinj/core/AlertMessage.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * Copyright 2015 Andreas Schildbach - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.bitcoinj.core; - -import java.util.Date; -import java.util.HashSet; -import java.util.Set; - -/** - * Alerts are signed messages that are broadcast on the peer-to-peer network if they match a hard-coded signing key. - * The private keys are held by a small group of core Bitcoin developers, and alerts may be broadcast in the event of - * an available upgrade or a serious network problem. Alerts have an expiration time, data that specifies what - * set of software versions it matches and the ability to cancel them by broadcasting another type of alert.

- * - * The right course of action on receiving an alert is usually to either ensure a human will see it (display on screen, - * log, email), or if you decide to use alerts for notifications that are specific to your app in some way, to parse it. - * For example, you could treat it as an upgrade notification specific to your app. Satoshi designed alerts to ensure - * that software upgrades could be distributed independently of a hard-coded website, in order to allow everything to - * be purely peer-to-peer. You don't have to use this of course, and indeed it often makes more sense not to.

- * - *

Before doing anything with an alert, you should check {@link AlertMessage#isSignatureValid()}.

- * - *

Instances of this class are not safe for use by multiple threads.

- */ -public class AlertMessage extends Message { - private byte[] content; - private byte[] signature; - - // See the getters for documentation of what each field means. - private long version = 1; - private Date relayUntil; - private Date expiration; - private long id; - private long cancel; - private long minVer, maxVer; - private long priority; - private String comment, statusBar, reserved; - - // Chosen arbitrarily to avoid memory blowups. - private static final long MAX_SET_SIZE = 100; - - public AlertMessage(NetworkParameters params, byte[] payloadBytes) throws ProtocolException { - super(params, payloadBytes, 0); - } - - @Override - public String toString() { - return "ALERT: " + getStatusBar(); - } - - @Override - protected void parse() throws ProtocolException { - // Alerts are formatted in two levels. The top level contains two byte arrays: a signature, and a serialized - // data structure containing the actual alert data. - int startPos = cursor; - content = readByteArray(); - signature = readByteArray(); - // Now we need to parse out the contents of the embedded structure. Rewind back to the start of the message. - cursor = startPos; - readVarInt(); // Skip the length field on the content array. - // We're inside the embedded structure. - version = readUint32(); - // Read the timestamps. Bitcoin uses seconds since the epoch. - relayUntil = new Date(readUint64().longValue() * 1000); - expiration = new Date(readUint64().longValue() * 1000); - id = readUint32(); - cancel = readUint32(); - // Sets are serialized as .... - long cancelSetSize = readVarInt(); - if (cancelSetSize < 0 || cancelSetSize > MAX_SET_SIZE) { - throw new ProtocolException("Bad cancel set size: " + cancelSetSize); - } - // Using a hashset here is very inefficient given that this will normally be only one item. But Java doesn't - // make it easy to do better. What we really want is just an array-backed set. - Set cancelSet = new HashSet<>((int) cancelSetSize); - for (long i = 0; i < cancelSetSize; i++) { - cancelSet.add(readUint32()); - } - minVer = readUint32(); - maxVer = readUint32(); - // Read the subver matching set. - long subverSetSize = readVarInt(); - if (subverSetSize < 0 || subverSetSize > MAX_SET_SIZE) { - throw new ProtocolException("Bad subver set size: " + subverSetSize); - } - Set matchingSubVers = new HashSet<>((int) subverSetSize); - for (long i = 0; i < subverSetSize; i++) { - matchingSubVers.add(readStr()); - } - priority = readUint32(); - comment = readStr(); - statusBar = readStr(); - reserved = readStr(); - - length = cursor - offset; - } - - /** - * Returns true if the digital signature attached to the message verifies. Don't do anything with the alert if it - * doesn't verify, because that would allow arbitrary attackers to spam your users. - */ - public boolean isSignatureValid() { - try { - return ECKey.verify(Sha256Hash.hashTwice(content), signature, params.getAlertSigningKey()); - } catch (SignatureDecodeException e) { - return false; - } - } - - ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Field accessors. - - /** - * The time at which the alert should stop being broadcast across the network. Note that you can still receive - * the alert after this time from other nodes if the alert still applies to them or to you. - */ - public Date getRelayUntil() { - return relayUntil; - } - - public void setRelayUntil(Date relayUntil) { - this.relayUntil = relayUntil; - } - - /** - * The time at which the alert ceases to be relevant. It should not be presented to the user or app administrator - * after this time. - */ - public Date getExpiration() { - return expiration; - } - - public void setExpiration(Date expiration) { - this.expiration = expiration; - } - - /** - * The numeric identifier of this alert. Each alert should have a unique ID, but the signer can choose any number. - * If an alert is broadcast with a cancel field higher than this ID, this alert is considered cancelled. - * @return uint32 - */ - public long getId() { - return id; - } - - public void setId(long id) { - this.id = id; - } - - /** - * A marker that results in any alerts with an ID lower than this value to be considered cancelled. - * @return uint32 - */ - public long getCancel() { - return cancel; - } - - public void setCancel(long cancel) { - this.cancel = cancel; - } - - /** - * The inclusive lower bound on software versions that are considered for the purposes of this alert. Bitcoin Core - * compares this against a protocol version field, but as long as the subVer field is used to restrict it your - * alerts could use any version numbers. - * @return uint32 - */ - public long getMinVer() { - return minVer; - } - - public void setMinVer(long minVer) { - this.minVer = minVer; - } - - /** - * The inclusive upper bound on software versions considered for the purposes of this alert. Bitcoin Core - * compares this against a protocol version field, but as long as the subVer field is used to restrict it your - * alerts could use any version numbers. - */ - public long getMaxVer() { - return maxVer; - } - - public void setMaxVer(long maxVer) { - this.maxVer = maxVer; - } - - /** - * Provides an integer ordering amongst simultaneously active alerts. - * @return uint32 - */ - public long getPriority() { - return priority; - } - - public void setPriority(long priority) { - this.priority = priority; - } - - /** - * This field is unused. It is presumably intended for the author of the alert to provide a justification for it - * visible to protocol developers but not users. - */ - public String getComment() { - return comment; - } - - public void setComment(String comment) { - this.comment = comment; - } - - /** - * A string that is intended to display in the status bar of Bitcoin Core's GUI client. It contains the user-visible - * message. English only. - */ - public String getStatusBar() { - return statusBar; - } - - public void setStatusBar(String statusBar) { - this.statusBar = statusBar; - } - - /** - * This field is never used. - */ - public String getReserved() { - return reserved; - } - - public void setReserved(String reserved) { - this.reserved = reserved; - } - - public long getVersion() { - return version; - } -} diff --git a/core/src/main/java/org/bitcoinj/core/BitcoinSerializer.java b/core/src/main/java/org/bitcoinj/core/BitcoinSerializer.java index 1b438e40522..5d5bc6f1401 100644 --- a/core/src/main/java/org/bitcoinj/core/BitcoinSerializer.java +++ b/core/src/main/java/org/bitcoinj/core/BitcoinSerializer.java @@ -216,8 +216,6 @@ private Message makeMessage(String command, int length, byte[] payloadBytes, byt return new VersionAck(params, payloadBytes); } else if (command.equals("headers")) { return new HeadersMessage(params, payloadBytes); - } else if (command.equals("alert")) { - return makeAlertMessage(payloadBytes); } else if (command.equals("filterload")) { return makeBloomFilter(payloadBytes); } else if (command.equals("notfound")) { @@ -254,15 +252,6 @@ public AddressMessage makeAddressMessage(byte[] payloadBytes, int length) throws return new AddressMessage(params, payloadBytes, this, length); } - /** - * Make an alert message from the payload. Extension point for alternative - * serialization format support. - */ - @Override - public Message makeAlertMessage(byte[] payloadBytes) throws ProtocolException { - return new AlertMessage(params, payloadBytes); - } - /** * Make a block from the payload. Extension point for alternative * serialization format support. diff --git a/core/src/main/java/org/bitcoinj/core/DummySerializer.java b/core/src/main/java/org/bitcoinj/core/DummySerializer.java index 68121e7056c..3ec34566096 100644 --- a/core/src/main/java/org/bitcoinj/core/DummySerializer.java +++ b/core/src/main/java/org/bitcoinj/core/DummySerializer.java @@ -58,11 +58,6 @@ public AddressMessage makeAddressMessage(byte[] payloadBytes, int length) throws throw new UnsupportedOperationException(DEFAULT_EXCEPTION_MESSAGE); } - @Override - public Message makeAlertMessage(byte[] payloadBytes) throws UnsupportedOperationException { - throw new UnsupportedOperationException(DEFAULT_EXCEPTION_MESSAGE); - } - @Override public Block makeBlock(byte[] payloadBytes, int offset, int length) throws UnsupportedOperationException { throw new UnsupportedOperationException(DEFAULT_EXCEPTION_MESSAGE); diff --git a/core/src/main/java/org/bitcoinj/core/MessageSerializer.java b/core/src/main/java/org/bitcoinj/core/MessageSerializer.java index 2e962eef2f4..ce591339b7b 100644 --- a/core/src/main/java/org/bitcoinj/core/MessageSerializer.java +++ b/core/src/main/java/org/bitcoinj/core/MessageSerializer.java @@ -57,13 +57,6 @@ public abstract class MessageSerializer { */ public abstract AddressMessage makeAddressMessage(byte[] payloadBytes, int length) throws ProtocolException, UnsupportedOperationException; - /** - * Make an alert message from the payload. Extension point for alternative - * serialization format support. - */ - public abstract Message makeAlertMessage(byte[] payloadBytes) throws ProtocolException, UnsupportedOperationException; - - /** * Make a block from the payload, using an offset of zero and the payload * length as block length. diff --git a/core/src/main/java/org/bitcoinj/core/NetworkParameters.java b/core/src/main/java/org/bitcoinj/core/NetworkParameters.java index 2dc8d8bf2b1..0950925813b 100644 --- a/core/src/main/java/org/bitcoinj/core/NetworkParameters.java +++ b/core/src/main/java/org/bitcoinj/core/NetworkParameters.java @@ -46,11 +46,6 @@ * them, you are encouraged to call the static get() methods on each specific params class directly.

*/ public abstract class NetworkParameters { - /** - * The alert signing key originally owned by Satoshi, and now passed on to Gavin along with a few others. - */ - public static final byte[] SATOSHI_KEY = Utils.HEX.decode("04fc9702847840aaf195de8442ebecedf5b095cdbb9bc716bda9110971b28a49e0ead8564ff0db22209e0374782c093bb899692d524e9d6a6956e7c5ecbcd68284"); - /** The string returned by getId() for the main, production network where people trade things. */ public static final String ID_MAINNET = "org.bitcoin.production"; /** The string returned by getId() for the testnet. */ @@ -80,7 +75,6 @@ public abstract class NetworkParameters { protected String segwitAddressHrp; protected int interval; protected int targetTimespan; - protected byte[] alertSigningKey; protected int bip32HeaderP2PKHpub; protected int bip32HeaderP2PKHpriv; protected int bip32HeaderP2WPKHpub; @@ -110,7 +104,6 @@ public abstract class NetworkParameters { protected volatile transient MessageSerializer defaultSerializer = null; protected NetworkParameters() { - alertSigningKey = SATOSHI_KEY; genesisBlock = createGenesis(this); } @@ -334,14 +327,6 @@ public BigInteger getMaxTarget() { return maxTarget; } - /** - * The key used to sign {@link AlertMessage}s. You can use {@link ECKey#verify(byte[], byte[], byte[])} to verify - * signatures using it. - */ - public byte[] getAlertSigningKey() { - return alertSigningKey; - } - /** Returns the 4 byte header for BIP32 wallet P2PKH - public key part. */ public int getBip32HeaderP2PKHpub() { return bip32HeaderP2PKHpub; diff --git a/core/src/main/java/org/bitcoinj/core/Peer.java b/core/src/main/java/org/bitcoinj/core/Peer.java index 1d13988ea35..2cccf1fdbd6 100644 --- a/core/src/main/java/org/bitcoinj/core/Peer.java +++ b/core/src/main/java/org/bitcoinj/core/Peer.java @@ -485,8 +485,6 @@ protected void processMessage(Message m) throws Exception { processAddressMessage((AddressMessage) m); } else if (m instanceof HeadersMessage) { processHeaders((HeadersMessage) m); - } else if (m instanceof AlertMessage) { - processAlert((AlertMessage) m); } else if (m instanceof VersionMessage) { processVersionMessage((VersionMessage) m); } else if (m instanceof VersionAck) { @@ -627,22 +625,6 @@ protected void processNotFoundMessage(NotFoundMessage m) { } } - protected void processAlert(AlertMessage m) { - try { - if (log.isDebugEnabled()) { - if (m.isSignatureValid()) - log.debug("Received alert from peer {}: {}", this, m.getStatusBar()); - else - log.debug("Received alert with invalid signature from peer {}: {}", this, m.getStatusBar()); - } - } catch (Throwable t) { - // Signature checking can FAIL on Android platforms before Gingerbread apparently due to bugs in their - // BigInteger implementations! See https://github.com/bitcoinj/bitcoinj/issues/526 for discussion. As - // alerts are just optional and not that useful, we just swallow the error here. - log.error("Failed to check signature: bug in platform libraries?", t); - } - } - protected void processHeaders(HeadersMessage m) throws ProtocolException { // Runs in network loop thread for this peer. // diff --git a/core/src/main/java/org/bitcoinj/params/TestNet3Params.java b/core/src/main/java/org/bitcoinj/params/TestNet3Params.java index 3bf4f96520a..b250865866e 100644 --- a/core/src/main/java/org/bitcoinj/params/TestNet3Params.java +++ b/core/src/main/java/org/bitcoinj/params/TestNet3Params.java @@ -61,7 +61,6 @@ public TestNet3Params() { subsidyDecreaseBlockCount = 210000; String genesisHash = genesisBlock.getHashAsString(); checkState(genesisHash.equals("000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943")); - alertSigningKey = Utils.HEX.decode("04302390343f91cc401d56d68b123028bf52e5fca1939df127f63c6467cdf9c8e2c14b61104cf817d0b780da337893ecc4aaff1309e536162dabbdb45200ca2b0a"); dnsSeeds = new String[] { "testnet-seed.bitcoin.jonasschnelli.ch", // Jonas Schnelli diff --git a/core/src/test/java/org/bitcoinj/core/AlertMessageTest.java b/core/src/test/java/org/bitcoinj/core/AlertMessageTest.java deleted file mode 100644 index e38a84e9a4a..00000000000 --- a/core/src/test/java/org/bitcoinj/core/AlertMessageTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2011 Google Inc. - * Copyright 2014 Andreas Schildbach - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.bitcoinj.core; - -import org.bitcoinj.params.UnitTestParams; -import org.junit.Before; -import org.junit.Test; - -import static org.bitcoinj.core.Utils.HEX; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -public class AlertMessageTest { - private static final byte[] TEST_KEY_PRIV = HEX.decode("6421e091445ade4b24658e96aa60959ce800d8ea9e7bd8613335aa65ba8d840b"); - private NetworkParameters params; - - @Before - public void setUp() throws Exception { - final ECKey key = ECKey.fromPrivate(TEST_KEY_PRIV); - params = new UnitTestParams() { - @Override - public byte[] getAlertSigningKey() { - return key.getPubKey(); - } - }; - } - - @Test - public void deserialize() throws Exception { - // A CAlert taken from Bitcoin Core. - // TODO: This does not check the subVer or set fields. Support proper version matching. - final byte[] payload = HEX.decode("5c010000004544eb4e000000004192ec4e00000000eb030000e9030000000000000048ee00000088130000002f43416c6572742073797374656d20746573743a2020202020202020207665722e302e352e3120617661696c61626c6500473045022100ec799908c008b272d5e5cd5a824abaaac53d210cc1fa517d8e22a701ecdb9e7002206fa1e7e7c251d5ba0d7c1fe428fc1870662f2927531d1cad8d4581b45bc4f8a7"); - AlertMessage alert = new AlertMessage(params, payload); - assertEquals(1324041285, alert.getRelayUntil().getTime() / 1000); - assertEquals(1324126785, alert.getExpiration().getTime() / 1000); - assertEquals(1003, alert.getId()); - assertEquals(1001, alert.getCancel()); - assertEquals(0, alert.getMinVer()); - assertEquals(61000, alert.getMaxVer()); - assertEquals(5000, alert.getPriority()); - assertEquals("CAlert system test: ver.0.5.1 available", alert.getStatusBar()); - assertTrue(alert.isSignatureValid()); - } -}