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