mirror of https://github.com/hyperledger/besu
Add Quorum Permissioning gate to Account and Node permissioning (#1545)
* Create Quorum QIP-714 gate Signed-off-by: Lucas Saldanha <lucascrsaldanha@gmail.com>pull/1560/head
parent
9062140452
commit
6e0a8748c9
@ -0,0 +1,44 @@ |
|||||||
|
/* |
||||||
|
* Copyright ConsenSys AG. |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.ethereum.permissioning; |
||||||
|
|
||||||
|
public class QuorumPermissioningConfiguration { |
||||||
|
|
||||||
|
public static final long QIP714_DEFAULT_BLOCK = 0; |
||||||
|
|
||||||
|
private final long qip714Block; |
||||||
|
private final boolean enabled; |
||||||
|
|
||||||
|
public QuorumPermissioningConfiguration(final long qip714Block, final boolean enabled) { |
||||||
|
this.qip714Block = qip714Block; |
||||||
|
this.enabled = enabled; |
||||||
|
} |
||||||
|
|
||||||
|
public static QuorumPermissioningConfiguration enabled(final long qip714Block) { |
||||||
|
return new QuorumPermissioningConfiguration(qip714Block, true); |
||||||
|
} |
||||||
|
|
||||||
|
public static QuorumPermissioningConfiguration disabled() { |
||||||
|
return new QuorumPermissioningConfiguration(QIP714_DEFAULT_BLOCK, false); |
||||||
|
} |
||||||
|
|
||||||
|
public long getQip714Block() { |
||||||
|
return qip714Block; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isEnabled() { |
||||||
|
return enabled; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
/* |
||||||
|
* Copyright ConsenSys AG. |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
package org.hyperledger.besu.ethereum.permissioning; |
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; |
||||||
|
import org.hyperledger.besu.ethereum.chain.Blockchain; |
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicLong; |
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting; |
||||||
|
|
||||||
|
public class QuorumQip714Gate { |
||||||
|
|
||||||
|
private static QuorumQip714Gate SINGLE_INSTANCE = null; |
||||||
|
|
||||||
|
private final long qip714Block; |
||||||
|
private final AtomicLong latestBlock = new AtomicLong(0L); |
||||||
|
|
||||||
|
@VisibleForTesting |
||||||
|
QuorumQip714Gate(final long qip714Block, final Blockchain blockchain) { |
||||||
|
this.qip714Block = qip714Block; |
||||||
|
|
||||||
|
blockchain.observeBlockAdded(this::checkChainHeight); |
||||||
|
} |
||||||
|
|
||||||
|
// this is only called during start-up, synchronized access won't hurt performance
|
||||||
|
public static synchronized QuorumQip714Gate getInstance( |
||||||
|
final long qip714Block, final Blockchain blockchain) { |
||||||
|
if (SINGLE_INSTANCE == null) { |
||||||
|
SINGLE_INSTANCE = new QuorumQip714Gate(qip714Block, blockchain); |
||||||
|
} else { |
||||||
|
if (SINGLE_INSTANCE.qip714Block != qip714Block) { |
||||||
|
throw new IllegalStateException( |
||||||
|
"Tried to create Quorum QIP-714 gate with different block config from already instantiated gate block config"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return SINGLE_INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean shouldCheckPermissions() { |
||||||
|
if (qip714Block == 0) { |
||||||
|
return true; |
||||||
|
} else { |
||||||
|
return latestBlock.get() >= qip714Block; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@VisibleForTesting |
||||||
|
void checkChainHeight(final BlockAddedEvent event) { |
||||||
|
if (event.isNewCanonicalHead()) { |
||||||
|
latestBlock.set(event.getBlock().getHeader().getNumber()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@VisibleForTesting |
||||||
|
long getLatestBlock() { |
||||||
|
return latestBlock.get(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,109 @@ |
|||||||
|
package org.hyperledger.besu.ethereum.permissioning; |
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat; |
||||||
|
import static org.assertj.core.api.Assertions.assertThatThrownBy; |
||||||
|
import static org.mockito.ArgumentMatchers.any; |
||||||
|
import static org.mockito.Mockito.mock; |
||||||
|
import static org.mockito.Mockito.verify; |
||||||
|
|
||||||
|
import org.hyperledger.besu.ethereum.chain.BlockAddedEvent; |
||||||
|
import org.hyperledger.besu.ethereum.chain.Blockchain; |
||||||
|
import org.hyperledger.besu.ethereum.core.Block; |
||||||
|
import org.hyperledger.besu.ethereum.core.BlockDataGenerator; |
||||||
|
import org.hyperledger.besu.ethereum.core.BlockDataGenerator.BlockOptions; |
||||||
|
|
||||||
|
import java.util.Collections; |
||||||
|
|
||||||
|
import org.junit.Before; |
||||||
|
import org.junit.Test; |
||||||
|
|
||||||
|
/* |
||||||
|
* Copyright ConsenSys AG. |
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||||
|
*/ |
||||||
|
public class QuorumQip714GateTest { |
||||||
|
|
||||||
|
private Blockchain blockchain; |
||||||
|
private QuorumQip714Gate gate; |
||||||
|
|
||||||
|
@Before |
||||||
|
public void before() { |
||||||
|
blockchain = mock(Blockchain.class); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void gateShouldSubscribeAsBlockAddedObserver() { |
||||||
|
gate = new QuorumQip714Gate(100, blockchain); |
||||||
|
|
||||||
|
verify(blockchain).observeBlockAdded(any()); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void whenTargetBlockIsZeroCheckPermissionsReturnTrue() { |
||||||
|
gate = new QuorumQip714Gate(0, blockchain); |
||||||
|
|
||||||
|
assertThat(gate.shouldCheckPermissions()).isTrue(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void whenBelowTargetBlockCheckPermissionsReturnFalse() { |
||||||
|
gate = new QuorumQip714Gate(99, blockchain); |
||||||
|
|
||||||
|
updateChainHead(55); |
||||||
|
|
||||||
|
assertThat(gate.shouldCheckPermissions()).isFalse(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void whenAboveTargetBlockCheckPermissionsReturnTrue() { |
||||||
|
gate = new QuorumQip714Gate(99, blockchain); |
||||||
|
|
||||||
|
updateChainHead(100); |
||||||
|
|
||||||
|
assertThat(gate.shouldCheckPermissions()).isTrue(); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void latestBlockCheckShouldKeepUpToChainHeight() { |
||||||
|
gate = new QuorumQip714Gate(0, blockchain); |
||||||
|
assertThat(gate.getLatestBlock()).isEqualTo(0); |
||||||
|
|
||||||
|
updateChainHead(1); |
||||||
|
assertThat(gate.getLatestBlock()).isEqualTo(1); |
||||||
|
|
||||||
|
updateChainHead(3); |
||||||
|
assertThat(gate.getLatestBlock()).isEqualTo(3); |
||||||
|
|
||||||
|
updateChainHead(2); |
||||||
|
assertThat(gate.getLatestBlock()).isEqualTo(2); |
||||||
|
} |
||||||
|
|
||||||
|
@Test |
||||||
|
public void getInstanceForbidInstancesWithDifferentQip714BlockNumber() { |
||||||
|
// creating singleton with qip714block = 1
|
||||||
|
QuorumQip714Gate.getInstance(1L, blockchain); |
||||||
|
|
||||||
|
// creating new instance with qip714block != 1 should fail
|
||||||
|
assertThatThrownBy(() -> QuorumQip714Gate.getInstance(2L, blockchain)) |
||||||
|
.isInstanceOf(IllegalStateException.class) |
||||||
|
.hasMessage( |
||||||
|
"Tried to create Quorum QIP-714 gate with different block config from already instantiated gate block config"); |
||||||
|
} |
||||||
|
|
||||||
|
private void updateChainHead(final int height) { |
||||||
|
final Block block = new BlockDataGenerator().block(new BlockOptions().setBlockNumber(height)); |
||||||
|
gate.checkChainHeight( |
||||||
|
BlockAddedEvent.createForHeadAdvancement( |
||||||
|
block, Collections.emptyList(), Collections.emptyList())); |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue